Skip to content
Advertisement

Matplotlib’s FuncAnimation calls init_func more than once

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.

Advertisement