Animating Data in Python – A Simple Guide

I keep running into situations where static charts do not cut it. A plot that updates in real time tells a completely different story than one that sits still. When I first needed to visualize streaming sensor data, matplotlib’s animation tools immediately became part of my daily workflow.

This article covers animating data in Python using matplotlib. By the end, you will understand how plt.pause() works for simple cases, how matplotlib FuncAnimation and ArtistAnimation handle more complex scenarios, and where live plots actually show up in the real world.

TLDR

  • plt.pause(interval) redraws the current figure and waits for a given interval
  • FuncAnimation calls an update function each frame to rebuild the plot
  • ArtistAnimation collects pre-drawn artists and displays them sequentially
  • Both classes live in matplotlib.animation
  • Real-time plots appear in finance dashboards, medical monitors, and IoT sensor feeds

What is animating data in Python?

Animating data in Python means updating a visualization frame-by-frame so the viewer sees changes unfold over time. Matplotlib provides two main approaches: a quick plt.pause() call inside a loop, and two fuller-featured classes called FuncAnimation and ArtistAnimation from the matplotlib.animation module. Both approaches rebuild or swap out plot elements on a schedule, producing smooth animations without any video recording.

Simple animation with plt.pause()

The fastest way to animate a plot is to draw it, call plt.pause(interval), and repeat. Each pause refreshes the display and freezes execution for roughly the interval in seconds. This works inside a regular for loop with no special classes or initialization functions.

Here is a scatter plot that grows from 0 to 50 random points. The pause interval of 0.01 seconds creates the illusion of continuous motion as new points appear one after another.


import matplotlib.pyplot as plt
import random

x = []
y = []

plt.xlabel("X-axis")
plt.ylabel("Y-axis")
plt.title("Growing Scatter Plot")

for i in range(50):
    x.append(random.randint(0, 100))
    y.append(random.randint(0, 100))
    plt.scatter(x, y, color="green")
    plt.pause(0.01)

plt.show()


Frame 0:  1 point plotted
Frame 10: 11 points plotted
Frame 25: 26 points plotted
Frame 49: 50 points plotted
The window stays open and updates live.

The same pattern works for bar plots. Replace plt.scatter() with plt.bar() and the bar chart animates upward frame by frame. The limitation of plt.pause() is that it always redraws the entire figure from scratch. For animations requiring precise control over initialization, blitting, or frame data, matplotlib.animation provides two dedicated classes.

FuncAnimation in matplotlib

FuncAnimation stands for function animation. It repeatedly calls an update function that modifies plot data, allowing fine-grained control over what changes each frame. The class takes a figure object, an update function, a frames iterator, an init function for setup, and a blit flag that optimizes redrawing by only refreshing changed artists.

Syntax of FuncAnimation


class matplotlib.animation.FuncAnimation(
    fig, func,
    frames=None,
    init_func=None,
    fargs=None,
    save_count=None,
    *, cache_frame_data=True,
    **kwargs
)


Parameters:
  fig         - Figure object to animate
  func        - Update function called each frame
  frames      - Iterable producing frame values
  init_func   - Optional setup function called before first frame
  blit        - If True, only redraw changed artists (faster)
  fargs       - Additional arguments passed to func

Animating a sine wave with FuncAnimation

The example below plots a sine wave that builds up gradually. The init function sets axis limits once. The update function appends each new frame value to the data lists and redraws only the line artist. Blit=True makes the animation responsive even with large datasets.


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

fig, ax = plt.subplots()
xdata, ydata = [], []
line, = plt.plot([], [], 'ro', ms=6)

def init():
    ax.set_xlim(0, 2 * np.pi)
    ax.set_ylim(-1.1, 1.1)
    return line,

def update(frame):
    xdata.append(frame)
    ydata.append(np.sin(frame))
    line.set_data(xdata, ydata)
    return line,

ani = FuncAnimation(
    fig, update,
    frames=np.linspace(0, 2 * np.pi, 128),
    init_func=init,
    blit=True
)
plt.show()


Frame 0:   x=0.000, y=0.000
Frame 32:  x=1.571, y=1.000
Frame 64:  x=3.142, y=0.000
Frame 128: x=6.283, y=0.000 (full cycle complete)

The comma after plt.plot is intentional. It unpacks the returned Line2D object as a scalar rather than a list, which is what FuncAnimation expects when it calls set_data(). The init function returns the artist or artists that get cleared before the first frame. Without returning line from init(), blit=True causes the animation to display nothing on the first draw.

ArtistAnimation in matplotlib

ArtistAnimation works the opposite way from FuncAnimation. Instead of calling a function to rebuild the plot each frame, you pre-create a list of artist objects, one for each frame. The animation then displays them in sequence. This approach is useful when all possible states are known ahead of time or when the drawing cost per frame is high and should be paid once upfront.


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

fig, ax = plt.subplots()
ax.set_xlim(0, 10)
ax.set_ylim(-1, 1)

artists = []
for phase in np.linspace(0, 2 * np.pi, 50):
    wave = ax.plot(np.linspace(0, 10, 100),
                   np.sin(np.linspace(0, 10, 100) + phase),
                   color='blue')
    artists.append(wave)

ani = ArtistAnimation(fig, artists, interval=50, blit=True)
plt.show()


Total frames: 50
Interval: 50 ms per frame
Total duration: 50 * 50ms = 2500ms (2.5 seconds)

ArtistAnimation is slower to set up because all frames are drawn upfront, but the playback is smooth since no computation happens between frames. FuncAnimation pays a small cost per frame but uses far less memory for long animations or when the number of frames is large.

Saving an animation to file

Both FuncAnimation and ArtistAnimation support saving to video formats. The save() method writes the animation frame sequence to a file using a backend like Pillow for GIFs or ffmpeg for MP4.


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

fig, ax = plt.subplots()
xdata, ydata = [], []
line, = plt.plot([], [], 'b-')

def init():
    ax.set_xlim(0, 2 * np.pi)
    ax.set_ylim(-1.1, 1.1)
    return line,

def update(frame):
    xdata.append(frame)
    ydata.append(np.sin(frame))
    line.set_data(xdata, ydata)
    return line,

ani = FuncAnimation(fig, update, frames=np.linspace(0, 2 * np.pi, 100),
                    init_func=init, blit=True)

ani.save("sine_wave.gif", writer="pillow", fps=30)
ani.save("sine_wave.mp4", writer="ffmpeg", fps=30)


GIF saved: sine_wave.gif
MP4 saved: sine_wave.mp4
Both files contain 100 frames at 30 fps = ~3.3 seconds

Pillow is built into matplotlib and works without extra dependencies. For high-quality MP4 output, install ffmpeg and use the ffmpeg writer. The writer parameter and fps parameter control the output format and playback speed respectively.

Real-world applications of live plots

Live animated plots show up in any context where understanding change over time matters more than a single snapshot.

A simple scatter plot showing animated data
  • Finance dashboards display stock prices that update every few seconds as new trades execute. Traders rely on the slope of the animation, not just the current price.
  • Medical monitors show ECG waveforms and pulse oximetry readings that scroll continuously across the screen. The animation makes it immediately obvious when a reading goes flat, which a static snapshot would not convey.
  • IoT sensor networks log temperature, pressure, and vibration data from machines. An animated plot flags anomalies in real time before they become failures.
  • Physics simulations use Python simulations to show particle trajectories or field evolution step by step, helping researchers validate their models visually.

FAQ

Q: Which should I use, FuncAnimation or ArtistAnimation?

FuncAnimation is better when the data changes incrementally frame to frame, when memory is a concern, or when the total number of frames is large or infinite. ArtistAnimation works well when all frames are known ahead of time and pre-rendering them upfront costs less than recomputing each frame.

Q: Why does my animation not show anything with blit=True?

The init function must return the artists that get cleared before the first frame. If it returns None or nothing, blit=True leaves the axes empty because the background was never properly initialized. Add a proper init function that sets axis limits and returns the visible artists.

Q: How do I control animation speed?

For FuncAnimation, the interval parameter sets milliseconds between frames. For ArtistAnimation, the same interval parameter controls playback speed. A value of 50 ms produces 20 fps. The frames parameter controls how many total frames exist, not how fast they play.

Q: Can I save an animation without installing extra tools?

Yes. Matplotlib bundles Pillow, so saving as a GIF works without additional dependencies. MP4 and WebM require ffmpeg to be installed separately on the system.

Q: Does plt.pause() work inside Jupyter Notebook?

plt.pause() generally does not produce visible animations in Jupyter because the notebook backend does not support interactive redrawing between cells. For Jupyter, use FuncAnimation with the notebook writer or switch to Plotly for interactive output.

Piyush Bhujbal
Piyush Bhujbal
Articles: 35