Animation Module — Save / Embed Helpers for Any FuncAnimation#
The cleopatra.glyphs.base.animation module exposes cleopatra's animation save / inline-embed
machinery as glyph-independent helpers. They operate on any
matplotlib.animation.FuncAnimation — a sine wave, stock prices, or a map — not only on a
Glyph's internal self.anim:
save_animation(anim, path, fps=2, ...)writes an animation to a file, choosing the writer from the extension:gifandwebpvia Pillow,mov/avi/mp4via FFmpeg. The extension is matched case-insensitively. Quality controls are keyword-only:crf/bitrate(mutually exclusive),codec,preset,pix_fmt, anddpifor the FFmpeg formats;optimizeandloopfor the Pillow (GIF/WebP) formats; plusextra_argspassed straight through to the writer.to_bytes(anim, fmt="gif", fps=2, ...)renders to in-memory bytes in any supported format (temp file cleaned up afterwards);to_gif(...)andto_mp4(...)are thin wrappers for the two common formats.embed_gif(anim, fps=2)returns anIPython.display.Imagefor inline notebook display. IPython is imported lazily (and is bundled with Jupyter, so any notebook already has it); if it is absent,embed_gifraises a clearModuleNotFoundErrorwith apip install ipythonhint — or useto_giffor raw bytes with no IPython dependency.
SUPPORTED_VIDEO_FORMAT is ["gif", "mov", "avi", "mp4", "webp"]. Glyph.save_animation
delegates to save_animation, so the writer/format logic has a single source of truth.
Downstream packages that build their own FuncAnimation can reuse these helpers instead of
re-rolling temp-file + writer + IPython.display glue.
Usage#
import matplotlib
matplotlib.use("Agg") # any backend; Agg shown for headless rendering
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from cleopatra.glyphs.base.animation import embed_gif, save_animation, to_gif
# Build any FuncAnimation — no Glyph required.
fig, ax = plt.subplots()
(line,) = ax.plot([0, 1], [0, 0])
def update(i):
line.set_ydata([0, i])
return (line,)
anim = FuncAnimation(fig, update, frames=3, blit=True)
save_animation(anim, "wave.gif", fps=3) # write to a file (gif/webp/mov/avi/mp4)
save_animation(anim, "wave.mp4", fps=3, crf=18) # quality-controlled MP4
gif_bytes = to_gif(anim, fps=3) # in-memory GIF bytes
embed_gif(anim, fps=3) # inline in a notebook cell
Note
The output format is taken from the file extension and is matched case-insensitively
(out.GIF works). gif / webp are written with Pillow (no FFmpeg needed). Video
formats (mov/avi/mp4) use FFmpeg: cleopatra depends on imageio-ffmpeg, which
bundles a static FFmpeg binary, so video export works out of the box — a system
FFmpeg on the PATH is used in preference when present. A FileNotFoundError (pointing
at https://ffmpeg.org/) is raised only if no FFmpeg — bundled or system — is available;
an unsupported extension raises a ValueError. embed_gif imports IPython only when
called; if IPython is absent it raises a ModuleNotFoundError with a pip install
ipython hint (use to_gif to avoid IPython).
Module Documentation#
cleopatra.glyphs.base.animation
#
Save/embed helpers for matplotlib animations (glyph-independent).
These helpers operate on any matplotlib.animation.FuncAnimation, not
only on a Glyph's internal self.anim. Saving or embedding an animation
is generic matplotlib machinery — it works on a sine wave, stock prices, or
a map — so it lives here alongside the glyph classes that produce
animations. Downstream packages that build their own FuncAnimation can
reuse cleopatra's writer/format handling instead of re-rolling temp-file +
writer + IPython.display glue.
Glyph.save_animation delegates to save_animation below, so the
writer/format logic has a single source of truth.
embed_gif(anim, fps=2)
#
Return an IPython.display.Image of the animation for inline display.
IPython is imported lazily, so importing cleopatra never requires it.
IPython ships with Jupyter, so any notebook already has it; outside a
notebook the returned Image is not renderable anyway — use to_gif
for raw bytes with no IPython dependency.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
anim
|
FuncAnimation
|
The animation to embed. |
required |
fps
|
int
|
Frames per second. Default is 2. |
2
|
Returns:
| Type | Description |
|---|---|
Image
|
An |
Image
|
returned as the last expression of a notebook cell. |
Raises:
| Type | Description |
|---|---|
ModuleNotFoundError
|
If IPython is not installed, with a hint to
|
Examples:
- Wrap an animation as an inline image and read back its payload:
>>> import matplotlib >>> matplotlib.use("Agg") >>> import matplotlib.pyplot as plt >>> from matplotlib.animation import FuncAnimation >>> from cleopatra.glyphs.base.animation import embed_gif >>> fig, ax = plt.subplots() >>> (line,) = ax.plot([0, 1], [0, 0]) >>> anim = FuncAnimation(fig, lambda i: (line,), frames=2) >>> img = embed_gif(anim) >>> img.format 'gif' >>> img.data[:6] in (b"GIF87a", b"GIF89a") True >>> plt.close(fig) - Returning the image as a cell's last expression renders it inline;
a custom
fpscontrols playback speed:>>> import matplotlib >>> matplotlib.use("Agg") >>> import matplotlib.pyplot as plt >>> from matplotlib.animation import FuncAnimation >>> from cleopatra.glyphs.base.animation import embed_gif >>> fig, ax = plt.subplots() >>> (line,) = ax.plot([0, 1], [0, 0]) >>> anim = FuncAnimation(fig, lambda i: (line,), frames=2) >>> img = embed_gif(anim, fps=3) >>> len(img.data) > 0 True >>> plt.close(fig)
See Also
to_gif: Produce the underlying GIF bytes without IPython. save_animation: Write the animation to a file path instead.
Source code in src/cleopatra/glyphs/base/animation.py
save_animation(anim, path, fps=2, *, crf=None, bitrate=None, codec=None, preset=None, pix_fmt='yuv420p', dpi=None, optimize=True, loop=0, extra_args=None)
#
Save any FuncAnimation to a file.
The output format is determined by the file extension. GIF and animated
WebP use an optimising Pillow writer; mov/avi/mp4 use FFmpeg. FFmpeg is
located on PATH when present and otherwise falls back to the binary
bundled with imageio-ffmpeg, so video export works with no separate
install. WebP is typically 3-5x smaller than GIF for photographic frames.
Note: when no system FFmpeg is found, the first video export sets
matplotlib's global rcParams["animation.ffmpeg_path"] to the bundled
binary — a process-wide side effect that then applies to any later
matplotlib animation in the same process.
For the FFmpeg formats the frame is automatically padded up to an even
width/height (libx264 rejects odd dimensions) and encoded with
pix_fmt=yuv420p for universal playback. By default no fixed bitrate is
requested (unlike older versions, which forced 1800 kbit/s), so libx264
uses its constant-quality default of roughly CRF 23 — pass crf or
bitrate to trade size against quality. GIF output is written with
Pillow's optimize pass enabled; both GIF and WebP loop forever by
default.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
anim
|
FuncAnimation
|
The animation to save. |
required |
path
|
str | PathLike
|
Output file path, as a |
required |
fps
|
int
|
Frames per second. Default is 2. |
2
|
crf
|
int | None
|
Constant Rate Factor for the ffmpeg formats (lower is higher
quality/larger; ~18-28 is typical). Assumes an x264/x265-family
|
None
|
bitrate
|
int | None
|
Target bitrate in kbit/s for the ffmpeg formats. Mutually
exclusive with |
None
|
codec
|
str | None
|
ffmpeg codec (e.g. |
None
|
preset
|
str | None
|
libx264/libx265 speed/size preset (e.g. |
None
|
pix_fmt
|
str
|
Pixel format for the ffmpeg formats. Defaults to
|
'yuv420p'
|
dpi
|
int | None
|
Resolution in dots per inch. |
None
|
optimize
|
bool
|
GIF only — run Pillow's palette optimisation pass (a no-op
for WebP, whose encoder ignores it). Default |
True
|
loop
|
int
|
GIF/WebP only — number of times to loop; |
0
|
extra_args
|
list[str] | None
|
Extra ffmpeg flags. A |
None
|
Returns:
| Type | Description |
|---|---|
str
|
The output path as a |
str
|
convenient for chaining. Note a |
str
|
back as its string form, not the original object. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the file format is not supported, or if both |
FileNotFoundError
|
If a video format is requested but neither a system FFmpeg nor imageio-ffmpeg's bundled binary can be found. |
Examples:
- Save a tiny animation to a GIF; the call returns the path it wrote:
>>> import os, shutil, tempfile, matplotlib >>> matplotlib.use("Agg") >>> import matplotlib.pyplot as plt >>> from pathlib import Path >>> from matplotlib.animation import FuncAnimation >>> from cleopatra.glyphs.base.animation import save_animation >>> tmp = tempfile.mkdtemp() >>> fig, ax = plt.subplots() >>> (line,) = ax.plot([0, 1], [0, 0]) >>> anim = FuncAnimation(fig, lambda i: (line,), frames=2) >>> path = os.path.join(tmp, "wave.gif") >>> save_animation(anim, path) == path True >>> Path(path).read_bytes()[:6] in (b"GIF87a", b"GIF89a") True >>> plt.close(fig) >>> shutil.rmtree(tmp) - The extension is matched case-insensitively, so
.GIFalso works:>>> import os, shutil, tempfile, matplotlib >>> matplotlib.use("Agg") >>> import matplotlib.pyplot as plt >>> from matplotlib.animation import FuncAnimation >>> from cleopatra.glyphs.base.animation import save_animation >>> tmp = tempfile.mkdtemp() >>> fig, ax = plt.subplots() >>> (line,) = ax.plot([0, 1], [0, 0]) >>> anim = FuncAnimation(fig, lambda i: (line,), frames=2) >>> save_animation(anim, os.path.join(tmp, "WAVE.GIF")).endswith("WAVE.GIF") True >>> plt.close(fig) >>> shutil.rmtree(tmp) - An unsupported extension raises
ValueErrorbefore writing (here the animation is rendered once first, so nothing is left dangling):>>> import os, shutil, tempfile, matplotlib >>> matplotlib.use("Agg") >>> import matplotlib.pyplot as plt >>> from matplotlib.animation import FuncAnimation >>> from cleopatra.glyphs.base.animation import save_animation >>> tmp = tempfile.mkdtemp() >>> fig, ax = plt.subplots() >>> (line,) = ax.plot([0, 1], [0, 0]) >>> anim = FuncAnimation(fig, lambda i: (line,), frames=2) >>> _ = save_animation(anim, os.path.join(tmp, "ok.gif")) >>> save_animation(anim, "movie.webm") # doctest: +ELLIPSIS Traceback (most recent call last): ... ValueError: ...not supported... >>> plt.close(fig) >>> shutil.rmtree(tmp)
See Also
to_gif: Render an animation to in-memory GIF bytes instead of a file.
embed_gif: Wrap an animation as an IPython.display.Image.
Source code in src/cleopatra/glyphs/base/animation.py
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 | |
to_bytes(anim, fmt='gif', fps=2, **kwargs)
#
Render a FuncAnimation to in-memory bytes in any supported format.
Renders to a temporary file (the writers need a real path) and reads it back, leaving nothing on disk. Handy for embedding in a notebook or serving over HTTP.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
anim
|
FuncAnimation
|
The animation to render. |
required |
fmt
|
str
|
Output format — any member of |
'gif'
|
fps
|
int
|
Frames per second. Default is 2. |
2
|
**kwargs
|
Extra keyword arguments forwarded to |
{}
|
Returns:
| Type | Description |
|---|---|
bytes
|
The encoded bytes of the animation in the requested format. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Examples:
- Render to GIF bytes and inspect the payload:
>>> import matplotlib >>> matplotlib.use("Agg") >>> import matplotlib.pyplot as plt >>> from matplotlib.animation import FuncAnimation >>> from cleopatra.glyphs.base.animation import to_bytes >>> fig, ax = plt.subplots() >>> (line,) = ax.plot([0, 1], [0, 0]) >>> anim = FuncAnimation(fig, lambda i: (line,), frames=2) >>> data = to_bytes(anim, fmt="gif") >>> data[:6] in (b"GIF87a", b"GIF89a") True >>> plt.close(fig) - Render to animated WebP and confirm the container magic bytes:
>>> import matplotlib >>> matplotlib.use("Agg") >>> import matplotlib.pyplot as plt >>> from matplotlib.animation import FuncAnimation >>> from cleopatra.glyphs.base.animation import to_bytes >>> fig, ax = plt.subplots() >>> (line,) = ax.plot([0, 1], [0, 0]) >>> anim = FuncAnimation(fig, lambda i: (line,), frames=2) >>> data = to_bytes(anim, fmt="webp") >>> data[:4] == b"RIFF" and data[8:12] == b"WEBP" True >>> plt.close(fig) - An unsupported format raises
ValueError:
See Also
to_gif: Convenience wrapper for GIF bytes. to_mp4: Convenience wrapper for MP4 bytes. save_animation: Write an animation directly to a file path.
Source code in src/cleopatra/glyphs/base/animation.py
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 | |
to_gif(anim, fps=2, **kwargs)
#
Render a FuncAnimation to in-memory GIF bytes.
Handy for embedding in a notebook or serving over HTTP without leaving
a file on disk. Thin wrapper around to_bytes with fmt="gif".
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
anim
|
FuncAnimation
|
The animation to render. |
required |
fps
|
int
|
Frames per second. Default is 2. |
2
|
**kwargs
|
Extra keyword arguments forwarded to |
{}
|
Returns:
| Type | Description |
|---|---|
bytes
|
The GIF-encoded bytes of the animation. |
Examples:
- Render an animation to GIF bytes and inspect the payload:
>>> import matplotlib >>> matplotlib.use("Agg") >>> import matplotlib.pyplot as plt >>> from matplotlib.animation import FuncAnimation >>> from cleopatra.glyphs.base.animation import to_gif >>> fig, ax = plt.subplots() >>> (line,) = ax.plot([0, 1], [0, 0]) >>> anim = FuncAnimation(fig, lambda i: (line,), frames=2) >>> data = to_gif(anim) >>> data[:6] in (b"GIF87a", b"GIF89a") True >>> len(data) > 0 True >>> plt.close(fig) - A higher
fpsstill yields self-contained bytes you can serve over HTTP or write yourself, without leaving a temp file behind:>>> import matplotlib >>> matplotlib.use("Agg") >>> import matplotlib.pyplot as plt >>> from matplotlib.animation import FuncAnimation >>> from cleopatra.glyphs.base.animation import to_gif >>> fig, ax = plt.subplots() >>> (line,) = ax.plot([0, 1], [0, 0]) >>> anim = FuncAnimation(fig, lambda i: (line,), frames=3) >>> payload = to_gif(anim, fps=5) >>> payload.startswith((b"GIF87a", b"GIF89a")) True >>> plt.close(fig)
See Also
to_bytes: Render to bytes in any supported format.
save_animation: Write an animation directly to a file path.
embed_gif: Wrap these bytes as an IPython.display.Image.
Source code in src/cleopatra/glyphs/base/animation.py
to_mp4(anim, fps=2, **kwargs)
#
Render a FuncAnimation to in-memory MP4 (H.264) bytes.
Handy for embedding a compact, universally-playable clip or serving it
over HTTP without leaving a file on disk. Thin wrapper around to_bytes
with fmt="mp4"; the frame is auto-padded to even dimensions and
encoded yuv420p like every other MP4 export.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
anim
|
FuncAnimation
|
The animation to render. |
required |
fps
|
int
|
Frames per second. Default is 2. |
2
|
**kwargs
|
Extra keyword arguments forwarded to |
{}
|
Returns:
| Type | Description |
|---|---|
bytes
|
The MP4-encoded bytes of the animation. |
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If neither a system FFmpeg nor imageio-ffmpeg's bundled binary can be found. |
Examples:
- Render to MP4 bytes and confirm the ISO base-media
ftypbox:>>> import matplotlib >>> matplotlib.use("Agg") >>> import matplotlib.pyplot as plt >>> from matplotlib.animation import FuncAnimation >>> from cleopatra.glyphs.base.animation import to_mp4 >>> fig, ax = plt.subplots() >>> (line,) = ax.plot([0, 1], [0, 0]) >>> anim = FuncAnimation(fig, lambda i: (line,), frames=2) >>> data = to_mp4(anim) >>> data[4:8] == b"ftyp" True >>> plt.close(fig) - Trade size for quality with a CRF and confirm non-empty output:
>>> import matplotlib >>> matplotlib.use("Agg") >>> import matplotlib.pyplot as plt >>> from matplotlib.animation import FuncAnimation >>> from cleopatra.glyphs.base.animation import to_mp4 >>> fig, ax = plt.subplots() >>> (line,) = ax.plot([0, 1], [0, 0]) >>> anim = FuncAnimation(fig, lambda i: (line,), frames=2) >>> data = to_mp4(anim, crf=30, preset="veryfast") >>> len(data) > 0 True >>> plt.close(fig)
See Also
to_bytes: Render to bytes in any supported format. to_gif: Render an animation to in-memory GIF bytes. save_animation: Write an animation directly to a file path.