WhipperSnapPy is a Python/OpenGL tool to render triangular surface meshes with color overlays or parcellations and generate screenshots — from the command line, in Jupyter notebooks, or via a desktop GUI.
It works with FreeSurfer and FastSurfer brain surfaces as well as any
triangle mesh in OFF, legacy ASCII VTK PolyData, ASCII PLY, or GIfTI (.gii, .surf.gii) format, or
passed directly as a NumPy (vertices, faces) tuple.
pip install whippersnappyFor rotation video support (MP4/WebM):
pip install 'whippersnappy[video]'For the interactive desktop GUI:
pip install 'whippersnappy[gui]'For interactive 3D in Jupyter notebooks:
pip install 'whippersnappy[notebook]'Off-screen (headless) rendering is supported natively via EGL on Linux — no
xvfb required. See the Docker guide for headless usage.
After installation the following commands are available:
Renders lateral and medial views of both hemispheres into a single composed image:
whippersnap4 -lh $LH_OVERLAY \
-rh $RH_OVERLAY \
-sd $SUBJECT_DIR \
--fmax 4 --fthresh 2 \
--caption "Cortical Thickness" \
-o snap4.pngRenders one view of any triangular surface mesh:
whippersnap1 --mesh $SUBJECT_DIR/surf/lh.white \
--overlay $LH_OVERLAY \
--bg-map $SUBJECT_DIR/surf/lh.curv \
--roi $SUBJECT_DIR/label/lh.cortex.label \
--view left \
-o snap1.png
# Also works with OFF / VTK / PLY
whippersnap1 --mesh mesh.off --overlay values.mgh -o snap1.png
whippersnap1 --mesh surface.surf.gii --overlay overlay.func.gii -o snap1.pngRenders a 360° animation of any triangular surface mesh:
whippersnap1 --mesh $SUBJECT_DIR/surf/lh.white \
--overlay $LH_OVERLAY \
--rotate \
-o rotation.mp4Launches an interactive Qt window with live threshold controls.
General mode — any triangular mesh:
pip install 'whippersnappy[gui]'
whippersnap --mesh mesh.off --overlay values.mgh
whippersnap --mesh lh.white --overlay lh.thickness --bg-map lh.curvFreeSurfer shortcut — derive all paths from a subject directory:
whippersnap -sd $SUBJECT_DIR --hemi lh -lh $LH_OVERLAY
whippersnap -sd $SUBJECT_DIR --hemi rh --annot rh.aparc.annotFor all options run whippersnap4 --help, whippersnap1 --help, or whippersnap --help.
from whippersnappy import snap1, snap4, snap_rotate, plot3d| Function | Description |
|---|---|
snap1 |
Single-view snapshot of any triangular mesh → PIL Image |
snap4 |
Four-view composed image (FreeSurfer subject, lateral/medial both hemispheres) |
snap_rotate |
360° rotation video of any triangular surface mesh (MP4, WebM, or GIF) |
plot3d |
Interactive 3D WebGL viewer for Jupyter notebooks |
Supported mesh inputs for snap1, snap_rotate, and plot3d:
FreeSurfer binary surfaces (e.g. lh.white), OFF (.off), legacy ASCII VTK PolyData (.vtk), ASCII PLY (.ply), GIfTI surface (.gii, .surf.gii), or a (vertices, faces) NumPy array tuple.
Supported overlay/label inputs:
FreeSurfer morph (.curv, .thickness), MGH/MGZ, ASCII (.txt, .csv), NumPy (.npy, .npz), GIfTI functional/label (.func.gii, .label.gii, .gii).
from whippersnappy import snap1, snap4
# FreeSurfer surface with overlay
img = snap1('lh.white',
overlay='lh.thickness',
bg_map='lh.curv',
roi='lh.cortex.label')
img.save('snap1.png')
# Four-view overview (FreeSurfer subject directory)
img = snap4(sdir='/path/to/subject',
lh_overlay='/path/to/lh.thickness',
rh_overlay='/path/to/rh.thickness',
colorbar=True, caption='Cortical Thickness (mm)')
img.save('snap4.png')
# OFF / VTK / PLY / GIfTI mesh
img = snap1('mesh.off', overlay='values.mgh')
img = snap1('surface.surf.gii', overlay='overlay.func.gii')
# Array inputs (e.g. from LaPy or trimesh)
import numpy as np
v = np.random.randn(1000, 3).astype(np.float32)
f = np.array([[0, 1, 2]], dtype=np.uint32)
overlay = np.random.randn(1000).astype(np.float32)
img = snap1((v, f), overlay=overlay)See tutorials/whippersnappy_tutorial.ipynb for complete notebook examples.
The Docker image provides a fully headless EGL rendering environment — no
display server or xvfb required. See DOCKER.md for details.
https://deep-mi.org/WhipperSnapPy
Lab webpage: https://deep-mi.org