Turn any static matplotlib script into an animated GIF by sweeping a variable
Project description
mpl-animator
Turn any static matplotlib script into an animated GIF by sweeping a variable - no rewriting required.
Features
- Zero boilerplate - point it at an existing script, it figures out the rest
- AST-based dependency tracking - automatically identifies which variables and calculations need to update each frame
- Parallel rendering - renders frames across all CPU cores via
multiprocessing, falls back to sequential automatically - Math expressions in ranges -
--range "0,2*pi"just works - 2D, 3D, and polar plots - handles
plot_surface,scatter3D, subplots, polar axes, and more - Single-file, standalone -
mpl_animator.pycan be dropped into any project with no install required; only depends onmatplotlib,numpy, andPillow(no exotic dependencies) - Library API - importable as a Python module for use in notebooks or pipelines
Install
pip install mpl-animator
Or just copy the file - no install needed:
# copy mpl_animator.py into your project, then use it directly
python mpl_animator.py my_plot.py --var t --range "0,1"
Usage
If installed via pip, use the mpl-animator command. If using the file directly, replace mpl-animator with python mpl_animator.py - everything else is identical.
# Basic: animate variable `f` from 3 to 60
mpl-animator wave_static.py --var f --range "3,60"
# Math expressions in range, custom frame count and FPS
mpl-animator plot.py --var t --range "0,2*pi" --frames 60 --fps 30
# Control output quality and parallelism
mpl-animator plot.py --var alpha --range "0,1" --dpi 150 --workers 8
# Custom output filename
mpl-animator plot.py --var t --range "0,1" --out my_animation.gif
This generates a <script>_animated.py file. Run it to produce the GIF:
python wave_static_animated.py # parallel (default)
python wave_static_animated.py --sequential # single-threaded fallback
Examples
Example 1 - Wave & spectrum (2D)
wave_static.py plots a signal and its frequency spectrum for a fixed frequency f:
# wave_static.py (key lines)
f = 10.0 # <- variable to animate
t = np.linspace(0, 1, 1000)
y = np.sin(2*np.pi*f*t) + 0.4*np.sin(2*np.pi*2*f*t)
freqs = np.fft.rfftfreq(len(t), d=t[1]-t[0])
spectrum = np.abs(np.fft.rfft(y))
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(9, 6))
ax1.plot(t, y, 'royalblue', lw=1.5)
ax2.plot(freqs, spectrum, 'tomato', lw=1.5)
plt.show()
Animate f from 3 Hz to 60 Hz:
python mpl_animator.py examples/wave_static.py --var f --range "3,60" --frames 60 --fps 20
python wave_static_animated.py
The animator detects that y, spectrum depend on f, moves them into the per-frame update(), and keeps the figure/axes creation static - so only the data redraws each frame.
Example 2 - 3D Lissajous curve
lissajous_3d_static.py draws a 3D Lissajous figure for fixed frequency ratio a:
# lissajous_3d_static.py (key lines)
a = 3.0 # <- variable to animate
b = 2.0
c = 1.0
t = np.linspace(0, 2 * np.pi, 1000)
x = np.sin(a * t + delta)
y = np.sin(b * t)
z = np.sin(c * t)
fig = plt.figure(figsize=(8, 6))
ax = fig.add_subplot(111, projection='3d')
ax.scatter(x, y, z, c=colors, s=2, alpha=0.8)
ax.set_title(f"3D Lissajous a={a:.1f}, b={b:.1f}, c={c:.1f}")
plt.show()
Animate a from 1 to 6, sweeping through different curve topologies:
python mpl_animator.py examples/lissajous_3d_static.py --var a --range "1,6" --frames 80 --fps 20
python lissajous_3d_static_animated.py
For 3D plots the animator calls fig.clear() and recreates the axes each frame (required to preserve the projection='3d' state), then re-runs all drawing commands with the new value of a.
How it works
- Parses your script's AST to find which variables depend on the animated one
- Splits code into static (run once) and dynamic (recalculated per frame)
- Generates a new script with
FuncAnimation(sequential) andmultiprocessing(parallel) renderers
Library usage
from mpl_animator import animate
src = open("my_plot.py").read()
animated_code = animate(src, var="t", range_str="0,6.28", frames=60, fps=25)
open("my_plot_animated.py", "w").write(animated_code)
Supported plot types
2D (plot, scatter, bar, hist, contour, imshow, ...), 3D (plot_surface, scatter3D, ...), polar, and anything else matplotlib draws.
Tests
pytest tests/ -v # fast tests (111)
pytest tests/ -v -m slow # slow tests that generate actual GIFs
Author: Basem Rajjoub
Built with the assistance of Claude Code
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mpl_animator-0.1.1.tar.gz.
File metadata
- Download URL: mpl_animator-0.1.1.tar.gz
- Upload date:
- Size: 15.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bd96ce131689e74ef03b08861c76f47b270966461fc26f065ea928af87827967
|
|
| MD5 |
54192c5d0080c051f7f1ede35ea4a696
|
|
| BLAKE2b-256 |
92a8b108be7a33bda969380370480cb7940927cce2c85b5963971adfbbc1e56e
|
File details
Details for the file mpl_animator-0.1.1-py3-none-any.whl.
File metadata
- Download URL: mpl_animator-0.1.1-py3-none-any.whl
- Upload date:
- Size: 12.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c6f4459e3ef678169c5e0bf887db24850da3d72a215eb4f298c3e34876cd9c13
|
|
| MD5 |
94e017c2f1d49ca6e2fe93c187fbd360
|
|
| BLAKE2b-256 |
d800506c5439d3efd9e517678929202e3c3a229841e99541b8f9dbcadafd5384
|