Comprehensive Python library for creating static, animated, and interactive visualizations
—
Creating animated plots and interactive visualizations. Matplotlib provides comprehensive animation capabilities through function-based and artist-based approaches, with support for various export formats and interactive backends.
Core animation framework for creating animated visualizations.
import matplotlib.animation as manimation
class Animation:
def __init__(self, fig, event_source=None, blit=False):
"""Base class for all animations."""
def save(self, filename, writer=None, fps=None, dpi=None, codec=None,
bitrate=None, extra_args=None, metadata=None, extra_anim=None,
savefig_kwargs=None, *, progress_callback=None) -> None:
"""Save the animation to a file."""
def to_html5_video(self, embed_limit=None) -> str:
"""Convert animation to HTML5 video."""
def to_jshtml(self, fps=None, embed_frames=True, default_mode=None) -> str:
"""Generate HTML representation with JavaScript controls."""
def pause(self) -> None:
"""Pause the animation."""
def resume(self) -> None:
"""Resume the animation."""
class TimedAnimation(Animation):
def __init__(self, fig, interval=200, repeat_delay=0, repeat=True,
event_source=None, *args, **kwargs):
"""Base class for timed animations."""
def _draw_frame(self, framedata) -> None:
"""Draw a single frame of the animation."""Animation using a function that is called repeatedly to update the plot.
class FuncAnimation(TimedAnimation):
def __init__(self, fig, func, frames=None, init_func=None, fargs=None,
save_count=None, *, cache_frame_data=True, **kwargs):
"""Animation by repeatedly calling a function."""
def new_frame_seq(self):
"""Return a new sequence of frame information."""
def new_saved_frame_seq(self):
"""Return a new sequence of saved frame information."""
# Convenience function
def FuncAnimation(fig, func, frames=None, init_func=None, fargs=None,
interval=200, repeat_delay=0, repeat=True, blit=False,
save_count=None, cache_frame_data=True) -> FuncAnimation:
"""Animate by repeatedly calling function func."""Animation using a list of artists that are shown sequentially.
class ArtistAnimation(TimedAnimation):
def __init__(self, fig, artists, interval=200, repeat_delay=0, repeat=True,
blit=False):
"""Animation using a list of artists."""
def new_frame_seq(self):
"""Return a new sequence of artists."""
def new_saved_frame_seq(self):
"""Return a new sequence of saved artists."""
# Convenience function
def ArtistAnimation(fig, artists, interval=200, repeat_delay=0, repeat=True,
blit=False) -> ArtistAnimation:
"""Animate by sequentially displaying a list of artists."""Classes for saving animations to various file formats.
class Writer:
def __init__(self, fps=5, codec=None, bitrate=None, extra_args=None,
metadata=None):
"""Base class for animation writers."""
def setup(self, fig, outfile, dpi=None) -> None:
"""Setup for writing the animation."""
def grab_frame(self, **kwargs) -> None:
"""Grab the current frame."""
def finish(self) -> None:
"""Finish writing the animation."""
class MovieWriter(Writer):
def __init__(self, fps=5, codec=None, bitrate=None, extra_args=None,
metadata=None):
"""Base class for movie writers using external tools."""
class FFMpegWriter(MovieWriter):
def __init__(self, fps=5, codec=None, bitrate=None, extra_args=None,
metadata=None):
"""Writer using FFmpeg for video encoding."""
class ImageMagickWriter(MovieWriter):
def __init__(self, fps=5, codec=None, bitrate=None, extra_args=None,
metadata=None):
"""Writer using ImageMagick for GIF creation."""
class PillowWriter(Writer):
def __init__(self, fps=5, codec=None, bitrate=None, extra_args=None,
metadata=None):
"""Writer using Pillow for GIF creation."""
class HTMLWriter(Writer):
def __init__(self, fps=5, codec=None, bitrate=None, extra_args=None,
metadata=None, embed_frames=False):
"""Writer for HTML with JavaScript controls."""Interactive controls and widgets for plot manipulation.
from matplotlib.widgets import *
class Button:
def __init__(self, ax, label, image=None, color='0.85', hovercolor='0.95'):
"""Clickable button widget."""
def on_clicked(self, func) -> None:
"""Connect function to button click event."""
class Slider:
def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt=None,
closedmin=True, closedmax=True, slidermin=None, slidermax=None,
dragging=True, valstep=None, orientation='horizontal',
initcolor='r', track_color='lightgrey', handle_style='round'):
"""Slider widget for continuous value selection."""
def on_changed(self, func) -> None:
"""Connect function to slider value change event."""
def set_val(self, val) -> None:
"""Set slider value."""
class CheckButtons:
def __init__(self, ax, labels, actives=None):
"""Check button widget for multiple boolean selections."""
def on_clicked(self, func) -> None:
"""Connect function to check button click event."""
class RadioButtons:
def __init__(self, ax, labels, active=0, activecolor='blue'):
"""Radio button widget for single selection from multiple options."""
def on_clicked(self, func) -> None:
"""Connect function to radio button selection event."""
class TextBox:
def __init__(self, ax, label, initial='', color='.95', hovercolor='1',
label_pad=.01, textalignment='left'):
"""Text input widget."""
def on_text_change(self, func) -> None:
"""Connect function to text change event."""
def on_submit(self, func) -> None:
"""Connect function to text submission event."""import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
# Set up the figure and axis
fig, ax = plt.subplots()
x = np.linspace(0, 2*np.pi, 100)
line, = ax.plot(x, np.sin(x))
ax.set_ylim(-2, 2)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_title('Animated Sine Wave')
def animate(frame):
"""Animation function called sequentially."""
# Update the y data with a phase shift
y = np.sin(x + frame * 0.1)
line.set_ydata(y)
return line,
def init():
"""Initialize animation - return the artists to be animated."""
line.set_ydata(np.sin(x))
return line,
# Create animation
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=200, interval=50, blit=True, repeat=True)
# Display the animation
plt.show()
# Save as GIF (optional)
# anim.save('sine_wave.gif', writer='pillow', fps=20)import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
# Create subplots
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
# Data setup
x = np.linspace(0, 2*np.pi, 100)
line1, = ax1.plot(x, np.sin(x), 'b-', label='sin(x)')
line2, = ax1.plot(x, np.cos(x), 'r-', label='cos(x)')
ax1.set_ylim(-2, 2)
ax1.set_title('Trigonometric Functions')
ax1.legend()
ax1.grid(True)
# Scatter plot setup
scat = ax2.scatter([], [], s=100, alpha=0.7)
ax2.set_xlim(-2, 2)
ax2.set_ylim(-2, 2)
ax2.set_title('Moving Points')
ax2.grid(True)
def animate(frame):
"""Animate both subplots."""
# Update trigonometric plots
phase = frame * 0.1
line1.set_ydata(np.sin(x + phase))
line2.set_ydata(np.cos(x + phase))
# Update scatter plot
n_points = 20
theta = np.linspace(0, 2*np.pi, n_points) + phase
x_scat = 1.5 * np.cos(theta)
y_scat = 1.5 * np.sin(theta)
# Update scatter plot data
scat.set_offsets(np.column_stack((x_scat, y_scat)))
return line1, line2, scat
# Create and run animation
anim = animation.FuncAnimation(fig, animate, frames=200, interval=100, blit=True)
plt.tight_layout()
plt.show()import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
# Generate data for multiple frames
fig, ax = plt.subplots()
# Create list of artists for each frame
artists = []
for i in range(50):
# Generate data for this frame
x = np.linspace(0, 10, 100)
y = np.sin(x + i * 0.2) * np.exp(-x/10)
# Create line artist
line, = ax.plot(x, y, 'b-')
title = ax.text(0.5, 0.9, f'Frame {i+1}', transform=ax.transAxes,
ha='center', fontsize=14)
# Add both line and title to this frame's artists
artists.append([line, title])
ax.set_xlim(0, 10)
ax.set_ylim(-1.5, 1.5)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.grid(True)
# Create artist animation
anim = animation.ArtistAnimation(fig, artists, interval=100, blit=True, repeat=True)
plt.show()import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib.widgets import Slider, Button
import numpy as np
# Create figure and subplots
fig = plt.figure(figsize=(12, 8))
ax_plot = plt.subplot2grid((4, 4), (0, 0), colspan=4, rowspan=3)
ax_slider1 = plt.subplot2grid((4, 4), (3, 0), colspan=2)
ax_slider2 = plt.subplot2grid((4, 4), (3, 2), colspan=2)
# Initial parameters
x = np.linspace(0, 4*np.pi, 200)
freq_init = 1.0
amp_init = 1.0
# Create initial plot
line, = ax_plot.plot(x, amp_init * np.sin(freq_init * x), 'b-', linewidth=2)
ax_plot.set_xlim(0, 4*np.pi)
ax_plot.set_ylim(-3, 3)
ax_plot.set_xlabel('X')
ax_plot.set_ylabel('Amplitude')
ax_plot.set_title('Interactive Animated Sine Wave')
ax_plot.grid(True)
# Animation variables
anim_running = True
phase = 0
# Create sliders
slider_freq = Slider(ax_slider1, 'Frequency', 0.1, 5.0, valinit=freq_init)
slider_amp = Slider(ax_slider2, 'Amplitude', 0.1, 3.0, valinit=amp_init)
def animate(frame):
"""Animation function."""
global phase
if anim_running:
phase += 0.1
freq = slider_freq.val
amp = slider_amp.val
y = amp * np.sin(freq * x + phase)
line.set_ydata(y)
return line,
def update_freq(val):
"""Update frequency from slider."""
pass # Animation function will read slider value
def update_amp(val):
"""Update amplitude from slider."""
pass # Animation function will read slider value
# Connect sliders
slider_freq.on_changed(update_freq)
slider_amp.on_changed(update_amp)
# Create animation
anim = animation.FuncAnimation(fig, animate, frames=1000, interval=50,
blit=True, repeat=True)
plt.tight_layout()
plt.show()import matplotlib.pyplot as plt
import matplotlib.animation as animation
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
# Create 3D plot
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
# Generate 3D data
def generate_data(frame):
"""Generate 3D surface data for given frame."""
x = np.linspace(-5, 5, 50)
y = np.linspace(-5, 5, 50)
X, Y = np.meshgrid(x, y)
# Create animated wave
t = frame * 0.1
Z = np.sin(np.sqrt(X**2 + Y**2) - t) * np.exp(-0.1 * np.sqrt(X**2 + Y**2))
return X, Y, Z
# Initial plot
X, Y, Z = generate_data(0)
surface = ax.plot_surface(X, Y, Z, cmap='viridis', alpha=0.8)
ax.set_xlim(-5, 5)
ax.set_ylim(-5, 5)
ax.set_zlim(-1, 1)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
ax.set_title('3D Animated Wave')
def animate(frame):
"""Animate 3D surface."""
ax.clear()
X, Y, Z = generate_data(frame)
surface = ax.plot_surface(X, Y, Z, cmap='viridis', alpha=0.8)
ax.set_xlim(-5, 5)
ax.set_ylim(-5, 5)
ax.set_zlim(-1, 1)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
ax.set_title(f'3D Animated Wave - Frame {frame}')
return surface,
# Create animation
anim = animation.FuncAnimation(fig, animate, frames=100, interval=100, blit=False)
plt.show()import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
# Create simple animation
fig, ax = plt.subplots()
x = np.linspace(0, 2*np.pi, 100)
line, = ax.plot(x, np.sin(x))
ax.set_ylim(-2, 2)
def animate(frame):
y = np.sin(x + frame * 0.1)
line.set_ydata(y)
return line,
anim = animation.FuncAnimation(fig, animate, frames=100, interval=50, blit=True)
# Save as MP4 (requires ffmpeg)
try:
anim.save('animation.mp4', writer='ffmpeg', fps=20, bitrate=1800)
print("Saved as MP4")
except:
print("FFmpeg not available")
# Save as GIF (requires Pillow or ImageMagick)
try:
anim.save('animation.gif', writer='pillow', fps=20)
print("Saved as GIF")
except:
print("Pillow not available")
# Save as HTML with JavaScript controls
anim.save('animation.html', writer='html', fps=20, embed_frames=True)
print("Saved as HTML")
plt.show()Install with Tessl CLI
npx tessl i tessl/pypi-matplotlib