Sam OT
Sam OT

Reputation: 430

Matplotlib FuncAnimation Step-by-Step Animation Function

I am trying to use matplotlib's FuncAnimation to make an animated video. Each frame is just a boolean n x n array visualised as white/black squares. I can do this successfully by defining all the arrays in advance and then going through them one by one. This uses code similar to matplotlib's example.

My items are rather large and I want to run the simulation for a long time. I thus don't want to create the entire list of arrays then go through them one by one. Instead, I want to define the animate function to do each step. Let me explain with a minimal non-working example. My actual example includes far larger arrays!

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

def create_video(n):
    global X
    X = np.random.binomial(1, 0.3, size = (n,n))
    
    fig = plt.figure()
    im = plt.imshow(X, cmap = plt.cm.gray)
    
    def animate(t):
        global X
        X = np.roll(X, +1, axis = 0)
        im.set_array(X)
    
    anim = FuncAnimation(
        fig,
        animate,
        frames = 100,
        interval = 1000 / 30,
        blit = True
    )
    
    return anim

anim = create_video(10)

This initialises some random 10 x 10 set of 0/1s then just 'rolls' it at each step. I get an error.

RuntimeError: The animation function must return a sequence of Artist objects.

If I remove the return anim, replacing it with pass, and replacing anim = create_video(10) with create_video(10), then I get a warning.

UserWarning: Animation was deleted without rendering anything. This is most likely unintended. To prevent deletion, assign the Animation to a variable that exists for as long as you need the Animation.

Clearly, I don't understand well enough FuncAnimation. What I want to happen is for the function animate to update the array X, by 'rolling' it one step, as well as doing im.set_array(X).

Upvotes: 2

Views: 18549

Answers (1)

Zephyr
Zephyr

Reputation: 12496

As explained in this answer:

As the error suggests, and as can be seen e.g. in the simple_animation example, but also from the FuncAnimation documentation, the init_func as well as the updating func are supposed to return an iterable of artists to animate.

The documentation does not say that this is actually only needed when using blit=True, but since you are using blitting here, it is definitely needed.

So you have two ways:

  • add

    return im,
    

    to animate function

  • set blit = False in FuncAnimation

Complete Code

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation


def create_video(n):
    global X
    X = np.random.binomial(1, 0.3, size = (n, n))

    fig = plt.figure()
    im = plt.imshow(X, cmap = plt.cm.gray)

    def animate(t):
        global X
        X = np.roll(X, +1, axis = 0)
        im.set_array(X)
        return im, 

    anim = FuncAnimation(
        fig,
        animate,
        frames = 100,
        interval = 1000/30,
        blit = True
    )

    plt.show()

    return anim

anim = create_video(10)

enter image description here

Upvotes: 2

Related Questions