Skip to main content

parallel-matplotlib-animation

Create matplotlib animations rendered to video in parallel, with efficient resources reuse.

Installation

pip install parallel-matplotlib-animation

or from a local copy:

git clone https://github.com/sibocw/parallel-matplotlib-animation.git
cd parallel-matplotlib-animation
pip install -e . --config-settings editable_mode=compat

What it does

Renders matplotlib animations by:

  1. Creating a bunch of worker processes, and creating matplotlib resources (plt.Figure, plt.Axes, artists, etc.) once per worker
  2. Distributing frames across workers via a dynamic queue
  3. Rendering the assigned frames from each worker, but updating the data only (without redrawing the whole plot from scratch)
  4. Encoding frames to video with parallel-video-io (FFmpeg under the hood, with automatic GPU/NVENC acceleration when available)

Key design: Figure reuse. In each worker process, setup() runs once to create the figure, then update() modifies it repeatedly. This brings the best of:

  • Serial processing: avoids the overhead of recreating complex layouts for every frame
  • Parallel processing: accomplishes speedup by using multiple CPU cores

Quick example

import numpy as np
import matplotlib.pyplot as plt
from parallel_animate import Animator

# Step 1: Create a child class of parallel_animate.Animator
class WaveAnimation(Animator):

    # Step 2: Define how the plot should be set up
    def setup(self):
        fig, ax = plt.subplots()
        self.x = np.linspace(0, 4 * np.pi, 200)
        (self.line,) = ax.plot(self.x, np.cos(self.x))
        ax.set_xlim(0, 4 * np.pi)
        ax.set_ylim(-1.5, 1.5)
        ax.set_xlabel("x")
        ax.set_ylabel("y")
        ax.set_title("Cosine Wave")
        return fig  # <- return a plt.Figure object

    # Step 3: Define how plot elements should be updated for each frame
    # (given parameters that you define later)
    def update(self, frame_idx, params):
        phase = params["phase"]
        self.line.set_ydata(np.cos(self.x + phase))

# Step 4: Define a list of input parameters, one for each frame
params = [{"phase": 2 * np.pi * i / 60} for i in range(60)]

# Step 5: Make the video in parallel
anim = WaveAnimation()
anim.make_video("wave.mp4", param_by_frame=params, fps=30, num_workers=4)

Usage

This library has a single class: parallel_animate.Animator. To make an animation, you must create your own class inheriting from it and define the following methods:

  • .setup(self): No input argument except self. In this method, you can setup your figure however you like. Just make sure you return the figure you created (i.e. the plt.Figure object). You might want to save the things you created as attributes—axes, return values of plotting calls like plt.plot, etc. This way, you can access and modify them in the update method.
  • .update(self, frame_idx, params): Given the frame index and some input parameters, update the plot elements. params is typically a dictionary of variables, but really it can be any Python object (tuple, a single value, etc.) as long as it's picklable. In this method, you want to call methods like .set_data on the plot elements that you created in setup and saved as attributes.
  • (Optional) __init__(self, ...): You can add any custom logic here. It's handy if you want to create many animation instances using the same custom class, but with different parameters. For example, if you make __init__ accept an input data path, you can do things like anim = RecordingAnimator(dataset_path=...) and animate many datasets in a loop.

Once you have defined your animator class, there is a single method that you need to call that makes the video: .make_video(...). It accepts the following arguments:

  • output_file (Path or str): Output video path
  • param_by_frame (Iterable): Iterable of parameters. Each element is the params argument to be given to the .update call for the corresponding frame. Can be a list, tuple, generator, or any other iterable. Using generators is particularly useful for large data (e.g., bitmaps) to avoid loading everything into memory at once.
  • fps (int): Frame rate of the output video
  • n_frames (int or None): Number of frames to render. If None, use the length of param_by_frame. If param_by_frame does not have __len__ implemented and n_frames is None, the progress bar won't show completion percentage.
  • num_workers (int): Number of worker processes to be spawned. If -1, use all CPU cores. If -2, use all but one CPU cores, etc. If 1, no child process is created and the video is made in the main process itself. Default is -1.
  • video_mode (str): Encoder selection passed to parallel-video-io: "auto" (default) uses the GPU encoder (FFmpeg/NVENC) when a CUDA device is available and falls back to CPU (libx264) otherwise; "gpu" forces NVENC and "cpu" forces libx264. Output is always an H.264 MP4.
  • video_quality (int or None), video_preset (str or None), video_extra_ffmpeg_params (list of str or None): Optional encoding-quality controls forwarded to parallel-video-io. Leave as None to use its sensible defaults.
  • See the docstring for parallel_animate.animator directly for the remaining less commonly used, optional parameters. These control logging, figure reuse, prefetching, etc.

Note: parallel-video-io is currently Linux-only.

Special case: frame params arriving out-of-order in param_by_frame

In some cases, frames in param_by_frame might be out of order. We can handle these scenarios by populating param_by_frame with a special parallel_animate.IndexedFrameParams dataclass, which specifies the frame index that overrides the ordering in param_by_frame. This can be useful when, for example, the animator needs to draw frames that are decoded from a video, and the dataloader for that video might return frames in nondeterministic order because it's parallelized.

See examples/nondeterministic_video_loader.py for details.

Examples

See examples/. Run all of them (except the benchmark) with ./examples/run_all.sh.

simple_wave_animation.py: The example above

multi_panel_animation.py: 5 subplots with different plot types

very_complex_animation.py: 14 subplots with GridSpec layout

nondeterministic_video_loader.py: handling frames that arrive out of order

Performance test

A strong scaling test is implemented in examples/scaling_test.py. Here's the result on my 8-core (16-thread) Intel Core i9-11900K Processor:

See the interactive scaling figure on the documentation site.

The left-most blue dot indicates serial processing with resources reuse. The black line indicates ideal scaling (zero overhead) if all frames are rendered completely independently in parallel (as is the case in all parallel matplotlib animation libraries I found). Blue dots at 1+ workers are what's implemented in this library.

Unit tests

python -m unittest discover -s tests

Metadata

Release files for parallel-matplotlib-animation 0.1.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for parallel-matplotlib-animation 0.1.4
File Size Uploaded Provenance
parallel_matplotlib_animation-0.1.4.tar.gz 173.2 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for parallel-matplotlib-animation 0.1.4
File Interpreter ABI Platform
parallel_matplotlib_animation-0.1.4-py3-none-any.whl Python 3 none any Details

Total release size: 198.9 kB

Release files / parallel_matplotlib_animation-0.1.4.tar.gz

Download URL parallel_matplotlib_animation-0.1.4.tar.gz
Size 173.2 kB
Tags Source
SHA-256 checksum
How to use checksums
0d3a08211f70e6b7bfd0f48b3106ff94e94c38d1d3c1809421b6a77962d575fc
BLAKE2b-256 checksum
How to use checksums
59660ad07caed55742603205027e2c54783540bf03fc68dfcfacb565e78ee8ce
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 29, 2026.

Transparency log

Release files / parallel_matplotlib_animation-0.1.4-py3-none-any.whl

Download URL parallel_matplotlib_animation-0.1.4-py3-none-any.whl
Size 25.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5e1d7fdc94da89b53acbaf78a90156781af7ba3cd45b1b806127adea5dc54a33
BLAKE2b-256 checksum
How to use checksums
dc56d98093f73c96d4578b0015ec1b95e89a672012a1412227bf3a995ae1d61b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 29, 2026.

Transparency log

Security for parallel-matplotlib-animation 0.1.4

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for parallel_matplotlib_animation-0.1.4.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 29, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page