Matplotlib останавливает анимацию после первого кадра
Я пытаюсь оживить две подзаголовки, каждая из которых имеет несколько строк. Я использую Matplotlib, и я использую FuncAnimation
, который используется многими из примеры анимации.
Использование анимации:
Если я попытаюсь оживить его, я получаю только результат первого кадра:
![with animation]()
Без использования анимации:
Если я вручную вызываю функцию update_lines
, она работает нормально.
![without animation]()
Код:
Ниже приведен полный код (раскомментирование трех указанных строк в main()
работает, но я хотел бы, чтобы он обновлялся в режиме реального времени, поэтому пытался использовать анимацию).
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
def make_subplots():
def setup_axes(axes):
for ax in axes:
ax.set_xbound(0, 100) # bound will change as needed.
ax.set_ylim(0, 1) # limit won't change automatically.
def make_lines(axes):
labels = ('a', 'b', 'c')
lines = []
for ax in axes:
ax_lines = []
for label in labels:
x, y = [0], [0]
line, = ax.plot(x, y, label=label) # comma for unpacking.
ax_lines.append((line, x, y))
lines.append(ax_lines)
return lines
fig, axes = plt.subplots(2, 1, sharex=True, sharey=True)
lines = make_lines(axes)
setup_axes(axes)
return fig, axes, lines
def make_data():
for i in xrange(100):
print 'make_data():', i
data = dict()
for label in ('a', 'b', 'c'):
from random import random
data[label] = random()
yield (i + 1, data)
def update_lines(data, lines):
print 'update_lines():', data, lines
updated_lines = []
for ax_lines in lines:
for line, x, y in ax_lines:
label = line.get_label()
x.append(data[0])
y.append(data[1][label])
line.set_data(x, y)
updated_lines.append(line)
def main():
fig, axes, lines = make_subplots()
# Uncomment these 3 lines, and it works!
# new_data = make_data()
# for data in new_data:
# update_lines(data, lines)
FuncAnimation(fig=fig,
func=update_lines,
frames=make_data,
fargs=(lines,),
interval=10,
blit=False)
plt.show()
if __name__ == '__main__':
main()
Ответы
Ответ 1
(Недокументированные?) Крючки
Итак, я копал исходный код matplotlib.animation.Animation
, и я заметил эти строки в функции __init__()
:
# Clear the initial frame
self._init_draw()
# Instead of starting the event source now, we connect to the figure's
# draw_event, so that we only start once the figure has been drawn.
self._first_draw_id = fig.canvas.mpl_connect('draw_event', self._start)
Звучит знакомо...
Пока это выглядит правильно. Вызов self._init_draw()
вызывает мой первый кадр немедленно. Затем анимационный объект перехватывает фигуру-объект и ждет, пока фигура будет показана, прежде чем пытаться нарисовать еще несколько кадров для анимации.
Эврика!
Ключевое слово: animation- object. Поскольку я не планировал использовать экземпляр анимации позже (например, для рисования фильма), я не назначал его переменной. Фактически, я был кричал на pyflakes, потому что Local variable '...' is assigned to but never used
.
Но поскольку вся функциональность зависит от крючка, когда, наконец, отображается холст, я предполагаю, что сбор мусора Python удалил экземпляр Animation --- поскольку он никогда не был привязан к переменной --- и, следовательно, анимация никогда не будет начать.
Исправление
Просто назначьте экземпляр экземпляра FuncAnimation
переменной, и все будет работать так, как ожидалось!
anim = FuncAnimation(fig=fig,
func=update_lines,
frames=make_data,
fargs=(lines,),
interval=10,
blit=False)