The documentation for matplotlib.animation.FuncAnimation
says:
init_func : […] This function will be called once before the first frame.
But whenever I use FuncAnimation
, the init_func
is called multiple times.
You can see this by adding a print statement to the basic example from Matplotlib’s website:
""" 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) 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(): # ---> Adding a print statement here <--- print('Initializing') 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()
Apart from producing a lovely plot, it immediately gives the standard output:
Initializing Initializing
If I keep the animation running, the init_func
is in fact called over and over again!
Is this a bug or a feature? What can I do about it?
A little background: I use the init_func
to initialize multiple plots as described here, only within a class:
class MyAnimation: def __init__(self, n): self.fig, self.ax = plt.subplots() self.n = n self.lines = [] def run_animation(self): def init(): for i in range(self.n): line = ax.plot([], [])[0] self.lines.append(line) return self.lines def animate(i): ... # Update lines return self.lines animation = FuncAnimation(self.fig, animate, init_func=init, blit=True) plt.show()
Of course, this makes no sense if init()
is called more than once, because additional lines will be appended to self.lines
.
Is my approach not good practice?
Should I set self.lines = []
inside the init()
function?
Advertisement
Answer
First of all it should be mentionned that “This function will be called once before the first frame.” means that it is called once before the first frame per animation. So because the FuncAnimation
‘s repeat
argument is True
by default, each time the animation is repeated, init_func
will be called again.
Next you are right that this function is actually called twice. The first call is to set the animation up. This step is apparently needed internally. One therefore should take this into account and make sure the init function does not produce anything irreversible in the plot.
Also note that if you did not provide any init_func, the first frame would be used for the internal setup procedure.
Therefore I think you are completely right to reset the lines
attribute in the init_func
. Possibly you might even want to clear the axes (self.ax.clear()
) to get rid of previously drawn elements.