PIVPy Visualization & Animations
PIVPy provides an intuitive, publication-ready visualization and animation suite for particle image velocimetry (PIV) vector fields and derived flow diagnostics.
Overview
The primary visualization entry points are:
pivpy.graphics.plot(andxarray.Dataset.piv.plot): High-level zero-effort publication-quality figure combining smooth scalar fluid contours (vorticity, speed, KE), streamlines, auto-scaled vector arrows, colorbar, and reference arrow key.pivpy.graphics.animate(andxarray.Dataset.piv.animate): High-performance interactive and exportable flow animations using in-place vector artist updates (quiver.set_UVC) and dynamic fluid gradient tracking.pivpy.graphics.quiver/xarray.Dataset.piv.quiver: Clean vector quiver plots with subsampling, scaling, and custom arrow colors.pivpy.graphics.streamplot/xarray.Dataset.piv.streamplot: Flow streamlines tracing instantaneous flow trajectories.pivpy.graphics.showf/xarray.Dataset.piv.showf: PIVMat-compatible multi-purpose field viewer.pivpy.graphics.to_movie/xarray.Dataset.piv.to_movie: Direct batch movie file exporter for time-series datasets.
Try it live
The two cells below run right here in the page (via marimo + Pyodide) -- drag the slider and the plot redraws immediately.
High-Level Plotting (ds.piv.plot)
Zero-effort publication-grade visualization out-of-the-box:
import matplotlib.pyplot as plt
import pivpy.pivpy # registers Dataset.piv accessor
from pivpy import synthetic
# Load data or generate a synthetic 2D turbulence field
ds = synthetic.multivortex(n_frames=1, n=128, n_vortices=8, two_d=True, seed=42)
# Render with one call
fig, ax = ds.piv.plot()
plt.show()
{ width="80%" }
Customizing Visual Layers
All layers (background contour, quiver arrows, streamlines, color limits, Gaussian smoothing) can be tailored or toggled:
# Velocity magnitude background with vectors only (no streamlines)
fig, ax = ds.piv.plot(
background="mag", # 'vorticity' (default), 'mag', 'ke', 'divergence', or None
streamlines=False, # toggle flow streamlines
quiver=True, # toggle velocity vectors
blur=1.5, # Gaussian smoothing sigma for smooth fluid contours
arrow_scale=0.75, # custom vector arrow scale
arrow_color="#1a1a1a", # custom arrow color
arrow_alpha=0.8, # arrow transparency
title="Velocity Magnitude & Vectors",
)
Flow Animations (ds.piv.animate)
How PIVPy Animations Work
Traditional Matplotlib animations that redraw the axes on every frame can be slow and cause visual flickering. PIVPy implements high-performance artist updating techniques:
- In-place Vector Updates: The velocity quiver artist is initialized once on frame 0. For subsequent time steps, vector components are updated directly in-place via
quiver.set_UVC(U, V)without recreating artists. - Dynamic Smooth Scalar Fields: Background fluid scalar fields (such as evolving vorticity or kinetic energy) are rendered as Gouraud-shaded meshes and updated via
mesh.set_array(...)across frames. - Consistent Global Scaling: Color limits (
clim) and arrow scaling are calculated robustly across the entire dataset duration, preventing colorbar jumps and flickering between frames.
Quickstart Animation Example
import pivpy.pivpy
from pivpy import synthetic
# 1. Generate or load time-series flow data (e.g. interacting vortex pair)
ds = synthetic.vortex_pair(n_frames=24, n=128)
# 2. Create the animation object
anim = ds.piv.animate(interval=80)
# 3. Save as GIF or MP4
anim.save("vortex_pair.gif", writer="pillow")
{ width="80%" }
Displaying in Jupyter and Marimo Notebooks
In interactive environments, display the animation inline as HTML5 video or interactive JS player:
from IPython.display import HTML
anim = ds.piv.animate(interval=80)
HTML(anim.to_jshtml())
Tuning Animation Parameters
The pivpy.graphics.animate function exposes fine-grained control:
anim = ds.piv.animate(
background="vorticity", # 'vorticity', 'mag', 'ke', 'divergence', or variable name
quiver=True, # overlay velocity vectors
blur=1.5, # Gaussian smoothing sigma
skip=8, # arrow subsampling step (e.g. every 8th vector)
arrow_width=0.007, # shaft width of vector arrows
arrow_color="#1a1a1a", # arrow color
arrow_alpha=0.75, # arrow opacity
cmap="RdBu_r", # colormap for background
interval=60, # delay between frames in milliseconds (~16 fps)
repeat=True, # loop animation
title_fmt="Vortex Interaction (t = {t:.2f} s)", # custom dynamic title
)
Saving High-Quality Videos (MP4 / GIF)
You can export animations using Pillow (GIF) or FFmpeg (MP4 / WebM):
from matplotlib.animation import FFMpegWriter, PillowWriter
# High-quality GIF
anim.save("flow.gif", writer=PillowWriter(fps=15))
# High-definition MP4 (requires ffmpeg installed)
anim.save("flow.mp4", writer=FFMpegWriter(fps=24, metadata=dict(artist="PIVPy"), bitrate=2000))
Batch Video Export (ds.piv.to_movie)
For very large datasets or out-of-core file sequences on disk where holding full animations in memory is undesirable, use pivpy.graphics.to_movie or pivpy.graphics.imvectomovie:
# In-memory time series
ds.piv.to_movie("output.mp4", background="vorticity", fps=15)
# Out-of-core disk file sequences
from pivpy.graphics import imvectomovie
imvectomovie("data_run_*.vec", output="run_movie.mp4", background="mag", fps=20)
Gallery of Static Visualizations
![]() |
![]() |
![]() |
![]() |



