5.4.18 · D1Scientific Computing (Python)

Foundations — Animation — FuncAnimation

3,848 words17 min readBack to topic

This page assumes you know nothing. Before you can read the line line, = ax.plot([], []) you need to know what a Figure, an Axes, an artist, set_data, a generator, a frame, the update function, init_func, the event loop, and even the lonely trailing comma actually are. We build each from a picture, in an order where each one leans on the one before, and at the end we wire them all together into the real FuncAnimation(...) call and start it running.

Recall Required pre-reading vs. self-contained

This deep dive is self-contained: every pitfall and mechanic below is explained here in full. The linked notes (e.g. Artists in Matplotlib, Generators in Python) are optional enrichment, not prerequisites — you can finish this page without opening them.


0. The picture the whole topic lives inside

Figure — Animation — FuncAnimation
  • The stack of cards → the sequence of frames.
  • One card → one frame (one still picture).
  • The speed you flip → the interval (how long each card is shown).
  • The rule "for card n, put the dot here" → your update function.
  • The robot flipping → the event loop / timer.

Keep this figure in mind; every symbol maps onto it.


1. The canvas: fig and ax

Before anything moves, we need a surface to draw on. Matplotlib splits this into two nested things.

Figure — Animation — FuncAnimation

In the picture: the pale outer rectangle is the Figure; the inner boxed region with tick marks is the Axes. The code

fig, ax = plt.subplots()   # plt = matplotlib.pyplot (see imports above)

hands you both at once: fig = the paper, ax = the one drawing box on it.

See Matplotlib Figure and Axes for the full anatomy.


2. The thing that actually gets drawn: an artist

You do not draw pixels by hand. Instead, matplotlib gives you objects that know how to draw themselves. These are called artists.

Figure — Animation — FuncAnimation

When you write

line, = ax.plot([], [])

you are creating one Line2D puppet on the axes. Right now it holds empty data ([] and []), so it draws nothing — but the puppet exists, ready to be told where to be.

More on Line2D, markers, and blitting live in Artists in Matplotlib.


3. Moving the puppet without rebuilding it: set_data

Here is the single most important verb in the whole topic.

  • xs — a sequence of x-coordinates (left-right).
  • ys — a matching sequence of y-coordinates (up-down).
  • They must be the same length: point k is at .

4. Where the per-frame numbers come from: linspace and phase shift

To move a whole wave we need many x-points and a y-value at each.

Here (np.pi) is just the number ; is one full turn of a sine wave. We choose so exactly one hump-and-trough fits on screen.

To make the wave travel, we write np.sin(x - 0.1*frame). Why subtract?

Because one NumPy expression computes all 400 y-values at once, we lean on NumPy linspace and broadcasting.


5. Two words for one still picture: frame and frames

So when you write frames=200, the update function receives frame = 0, then 1, … up to 199. When you write frames=frame_gen, each value the generator yields becomes frame.


6. A machine that hands out one value at a time: the generator

Figure — Animation — FuncAnimation

In the figure, the generator is a vending slot: each "next!" pops out the next value (, then , then …) and then freezes mid-code until the next request.

def frame_gen():
    t = 0.0
    while t < 6.28:
        yield t      # hand out t, then FREEZE here
        t += 0.05    # on next request, resume from here

Deeper mechanics: Generators in Python.


7. The rule for one card: the update function (func)

Now the star of the show. FuncAnimation never draws anything itself — it just calls your function once per frame and lets that function reposition the puppets.


8. The clean first page: init_func

Before the very first real frame, matplotlib wants a known blank starting state — think of the cover of the flip-book, the picture "before frame 0."


9. The speed trick: blitting (blit=True)


10. The lonely comma: line, = ... and return line,

Two commas confuse every beginner. Here they are, defused.


11. The robot's stopwatch: interval, FPS, and the event loop

The frames-per-second (how many cards flip in one second) is:

Who fires the stopwatch? The event loop.

See Event Loops / GUI backends for why blocking loops feel "hung."


12. Wiring it all together: the real FuncAnimation(...) call

Now every part exists. Here is the full signature, then the complete runnable program that uses every piece above.


13. Actually starting it — and keeping it alive

Building anim does not by itself make anything move; it only registers the timer. The event loop must be started.

To save the movie you hand the frames to ffmpeg (mp4) or pillow (gif). See Saving figures and ffmpeg.


14. save_count — capping an endless generator


Prerequisite map

Figure and Axes - the canvas

Artists - Line2D puppet

set_data - move the puppet

linspace - the x points

update func - one frame rule

Generators - yield values

frames - which cards

init_func - clean background

FuncAnimation call

Event loop - the timer

interval and FPS

Blitting - return artists

plt.show starts the loop

anim.save via ffmpeg and save_count

Keep the anim reference


Equipment checklist

Difference between a Figure and an Axes?
Figure = the whole sheet/window; Axes = one plotting rectangle (with ticks and grid) inside it.
What is an artist, and which type is a plotted line?
A self-drawing object matplotlib manages; a plotted line is a Line2D.
What does line.set_data(xs, ys) do?
Mutates the existing line to new x/y points in place — same puppet, new pose.
Why call ax.plot ONCE outside the update function?
To reuse one artist via set_data; calling it per frame piles up new artists and breaks blit.
What does np.linspace(0, 2*np.pi, 400) produce?
400 evenly spaced numbers from 0 to 2π inclusive.
Why does np.sin(x - 0.1*frame) move the wave right?
Bigger shift pushes the peak (input = π/2) to a larger x, so features slide right.
What is a generator and what does yield do?
A function that hands back one value then pauses, resuming on the next request.
What is the update function func and its argument?
A function you write that takes the current frame, repositions the puppets via set_data, and returns the changed artists.
What is init_func for, and what argument does it take?
It draws the clean empty background before frame 0; it takes no frame argument and returns the artists.
What is the second positional argument to FuncAnimation?
func, your update function.
Convert interval=20 ms to FPS.
1000/20 = 50 FPS.
What fires the per-frame timer?
The GUI event loop, which also keeps the window responsive.
How do you actually START the animation on screen?
Call plt.show(), which runs the event loop (and blocks until the window closes).
With blit=True, what must func (and init_func) return?
An iterable of the changed artists, e.g. return line,.
What does the trailing comma in line, = ax.plot(...) do?
Unpacks the single-element list ax.plot returns into line.
Why must you keep anim = FuncAnimation(...)?
Otherwise it's garbage-collected, the timer stops, and the animation freezes/blanks.
What is save_count for?
A cap on how many frames to grab when SAVING a generator-driven animation of unknown length; ignored during live playback.

Connections

  • Animation — FuncAnimation — the parent topic this page prepares you for.
  • Matplotlib Figure and Axes — the fig/ax canvas.
  • Artists in MatplotlibLine2D, set_data, blitting.
  • Generators in Python — the yield machine behind frames.
  • Event Loops / GUI backends — the timer that fires each frame.
  • NumPy linspace and broadcasting — building per-frame arrays.
  • Saving figures and ffmpeg — exporting to mp4/gif.