I'm trying to implement a function which outputs an animated plot.
If I take simple_anim.py (from matplotlib examples) as a base:
"""
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()
Effectively it works.
BUT, if I close this code inside a function (in order to provide changing parameters, and avoid doing an explicit file for each possible parameter value):
"""
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()
and then call the function, the figure plot remains white. In fact, it never arrives to enter into the animate function.
I know that I'm missing some information, and that's why it does not work. Does anybody can give me some hints?
Thank you very much,
Andrés
The reason that this happens is that the timers and call backs which update the window are attributes of the object ani
. If you do not keep a reference to it around, then ani
in garbage collected and your timers/callbacks go away.
The solution is to have your function return ani
and keep a reference to it in your code:
def a(...):
# stuff
ani = animation.FuncAnimation(...)
# more stuff
return ani
outer_ani = a(...)
This issue (see github #1656) has been discussed, but not resolved.
FuncAnimation should not be scraped off as garbage so just assign it to a global variable
global anim
def callfuncanimation():
global anim
anim = FuncAnimation(....)
as anim is a global variable, it persists and will not be scraped
As tcaswell's good answer implies, the behavior of the problem code is undefined because it relies on an object which has been deleted and is available for garbage collection.
In practice, this undefined behavior manifests differently with different GUI backends. For some users (e.g. this "duplicate" question), using the Wx backend in IDLE or in the default Pylab shortcut on Windows, the undefined code seems to work (I say "seems to" because it's really not working, but rather producing the desired results by luck). When running in the Canopy GUI with its default Qt backend, the code does not work. Qt and Wx have very different architectures and garbage collection. (In Canopy, the GUI backend can be changed in the Python tab of the Preferences menu; if it is changed to Wx, then the undefined code also seems to work, but again, that doesn't make it correct.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With