Python matplotlib: невозможно вызвать функцию FuncAnimation изнутри функции
Я пытаюсь реализовать функцию, которая выводит анимированный сюжет.
Если я возьму simple_anim.py(из примеров matplotlib) в качестве базы:
"""
A simple example of an animated plot
"""
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig, ax = plt.subplots()
x = np.arange(0, 2*np.pi, 0.01) # x-array
line, = ax.plot(x, np.sin(x))
def animate(i):
line.set_ydata(np.sin(x+i/10.0)) # update the data
return line,
#Init only required for blitting to give a clean slate.
def init():
line.set_ydata(np.ma.array(x, mask=True))
return line,
ani = animation.FuncAnimation(fig, animate, np.arange(1, 200), init_func=init,
interval=25, blit=True)
plt.show()
Эффективно работает.
НО, если я закрою этот код внутри функции (чтобы обеспечить изменение параметров и избежать выполнения явного файла для каждого возможного значения параметра):
"""
A simple example of an animated plot
"""
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
def a():
fig, ax = plt.subplots()
x = np.arange(0, 2*np.pi, 0.01) # x-array
line, = ax.plot(x, np.sin(x))
def animate(i):
line.set_ydata(np.sin(x+i/10.0)) # update the data
return line,
#Init only required for blitting to give a clean slate.
def init():
line.set_ydata(np.ma.array(x, mask=True))
return line,
ani = animation.FuncAnimation(fig, animate, np.arange(1, 200), init_func=init,
interval=25, blit=True)
plt.show()
а затем вызовите функцию, график рисунка останется белым. Фактически, он никогда не приходит, чтобы войти в одушевленную функцию.
Я знаю, что мне не хватает информации, и почему она не работает.
Кто-нибудь может дать мне несколько советов?
Большое спасибо,
Andrés
Ответы
Ответ 1
Причина, по которой это происходит, заключается в том, что таймеры и обратные вызовы, которые обновляют окно, являются атрибутами объекта ani
. Если вы не держите ссылку на него, то ani
в собранном мусоре и ваши таймеры/обратные вызовы исчезнут.
Решение состоит в том, чтобы вернуть вашу функцию ani
и сохранить ссылку на нее в вашем коде:
def a(...):
# stuff
ani = animation.FuncAnimation(...)
# more stuff
return ani
outer_ani = a(...)
Эта проблема (см. github # 1656) обсуждалась, но не разрешалась.
Ответ 2
Как следует из хорошего ответа, поведение кода проблемы undefined, поскольку оно зависит от объекта, который был удален и доступен для сбора мусора.
На практике это поведение undefined проявляется по-разному с различными бэкэндами GUI. Для некоторых пользователей (например, этот "повторяющийся" вопрос), используя Wx-сервер в IDLE или в ярлыке Pylab по умолчанию в Windows, код undefined, похоже, работает ( Я говорю "кажется", потому что он действительно не работает, а скорее дает желаемые результаты на удачу). При работе в графическом интерфейсе Canopy с его базовым компонентом Qt по умолчанию код не работает. Qt и Wx имеют очень разные архитектуры и сборку мусора. (В Canopy бэкэнд GUI можно изменить на вкладке Python в меню "Настройки", если он изменен на Wx, тогда код undefined также работает, но опять же, это не делает его правильным.)
Ответ 3
As Исправлено 1656: Анимация - это сбор мусора, если явно не хранится # 8214, сборщик мусора Python удалит вашу анимацию, если она явно не сохранена.
Если вы хотите получить его в основной функции, вы можете сделать это так же, как @tacaswell. Однако, это не работает, если вы хотите сгенерировать анимацию в другой функции.
Мы можем определить глобальную переменную для хранения возвращаемого значения FuncAnimation.
global anim
def return_anim():
anim = animation.FuncAnimation(fig, animate, blit=True)
return anim
def use_ani():
global anim
anim = return_anim
use_ani()
Пожалуйста, не забудьте установить blit = True, иначе Python не будет перерисовывать вашу анимацию.