Анимация спектрограммы Matplotlib без вызова pyplot.specgram непосредственно каждый цикл - PullRequest
0 голосов
/ 20 ноября 2018

Я сделал анимированную спектрограмму таким образом:

import matplotlib.pyplot as plt
import matplotlib.animation as animation
import librosa

window = 100000
jump = 1000
interval = 1
filename = 'sound.wav'

sound, rate = librosa.load(filename,sr=None)
fig = plt.figure()

_, _, _, im = plt.specgram(sound[:window], Fs=rate)

def animate(i):
    _, _, _, im = plt.specgram(sound[i*jump:(i*jump)+window], Fs=rate)
    return im,

ani = animation.FuncAnimation(fig, animate, interval=interval, blit=True)

plt.ion()
plt.show()

Это работает, но в примерах использования FuncAnimation Я видел, что люди не вызывают всю функцию построения графиков для каждого кадра анимации, а вместо этого обновляют данные напрямую, и кажется, что есть причины (производительность?) для этого. Примеры дали некоторое представление о том, как сделать это для других изображений (тех, где вы в основном делали свою собственную математику, чтобы заполнить массив, который является изображением), но с чем-то более черным, как pyplot.specgram my hack (возможно) должен был просто вызывать функцию построения графика снова и снова. Мой вопрос заключается в том, можно ли это сделать способом, более похожим на приведенный выше по ссылке на сайте matplotlib, и, если да, то как?

Ответы [ 2 ]

0 голосов
/ 22 ноября 2018

Согласно ответу, который я принял, у меня теперь есть это:

import matplotlib.pyplot as plt
import matplotlib.animation as animation
import librosa

window = 50000
jump = 500
interval = 1
filename = 'sound.wav'

sound, rate = librosa.load(filename,sr=None)
fig = plt.figure(figsize=(10,5))

arr = plt.mlab.specgram(sound[:window], Fs=rate)[0]
im = plt.imshow(arr, animated=True)

def animate(i):
    arr = plt.mlab.specgram(sound[i*jump:(i*jump)+window], Fs=rate)[0]
    im.set_array(arr)
    return im,

ani = animation.FuncAnimation(fig, animate, interval=interval, blit=True)
plt.ion()
plt.show()

plt.mlab.specgram дает немного иную картину, чем plt.specgram (к которой я еще не дошел), но это, кажется, не совсем ключ к сути моего первоначального вопроса, который, я думаю, сейчас решается .

0 голосов
/ 20 ноября 2018

Причина, по которой вы не хотите повторно вызывать функцию plt.specgram внутри анимации, - это производительность.После N циклов у вас есть N изображений на вашей фигуре, что делает рисование все более и более дорогим.

Конечно, возможное решение состоит в том, чтобы удалить предыдущее изображение в каждой итерации, например, с помощью дескриптора (im.remove()) или через список изображений (ax.images[0].remove()).

Тем не менее, вы правы, что более желательным решением является не воссоздание какого-либо изображения вообще, а только изменение данных изображения.

В этом случае вы захотите позвонить matplotlib.mlab.specgram, чтобы получить спектр в виде массива numpy и использовать метод set_array() изображения для обновления изображения в анимации.

Обратите внимание, однако, что для этого может потребоваться обновить ограничения цветатакже изображения, если разные спектры имеют разные минимальные или максимальные амплитуды.


Поскольку изображение, показанное plt.specgram, не является непосредственно спектрограммой, возвращенной mlab.specgram, вам может потребоваться установитьнекоторые параметры вручную.В частности, по умолчанию изображение отображается в масштабе дБ.

Я думаю, что эквивалент

Fs = rate
NFFT = 256
noverlap= 128
spec, freqs, t, im = plt.specgram(sound, Fs=Fs, NFFT=NFFT, noverlap=noverlap)

будет

spec, freqs, t = plt.mlab.specgram(sound, Fs=rate, NFFT=NFFT, noverlap=noverlap)
pad_xextent = (NFFT-noverlap) / Fs / 2
xmin, xmax = np.min(t) - pad_xextent, np.max(t) + pad_xextent
extent = xmin, xmax, freqs[0], freqs[-1]
im = plt.imshow(np.flipud(10. * np.log10(spec)), extent=extent, aspect="auto")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...