Skip to content

Plotting

Choose a plot class for the data you want to display. Each class keeps a scene open while you add data; the methods below provide static figures and 3D views.

SurfacePlot

SurfacePlot(
    *,
    left: PolyData | str | Path | None = None,
    right: PolyData | str | Path | None = None,
    projection_surface: tuple[
        PolyData | str | Path | None,
        PolyData | str | Path | None,
    ]
    | None = None,
    views: str | Sequence[str] = "lateral",
    layout: Literal["grid", "row", "column"] = "grid",
    zoom: float = 1.0,
    color: str = "#979797",
    opacity: float = 1.0,
    window_size: tuple[int, int] = (1000, 600),
    background: str = "white",
)

Bases: _BasePlot

Display cortical hemispheres in named anatomical views.

Initialize hemisphere panels and their shared camera scale.

Parameters:

Name Type Description Default
left PolyData | str | Path | None

Hemisphere meshes or surface files accepted by load_surface. Supply at least one. Coordinates must be RAS millimetres; geometry is copied without translation, registration, or inflation. Panels are ordered left then right; absent hemispheres have no panel.

None
right PolyData | str | Path | None

Hemisphere meshes or surface files accepted by load_surface. Supply at least one. Coordinates must be RAS millimetres; geometry is copied without translation, registration, or inflation. Panels are ordered left then right; absent hemispheres have no panel.

None
projection_surface tuple | None

Anatomical localization surfaces in (left, right) order, each a PolyData or local surface path; use None for an absent hemisphere. Supplied and displayed hemispheres must match and have identical ordered triangles and corresponding vertices. Meshes are copied. Use original pial or midthickness geometry when displaying inflated surfaces. None localizes on the display meshes themselves; it cannot recover anatomical distances from a deformed mesh. This pair is shared by every projected add_contacts call. It is unused when project=False. Supplied meshes are still loaded and validated at construction. Face winding must point outward; names and vertex counts alone cannot verify alignment.

None
views str | Sequence[str]

Anatomical views in display order: lateral, medial, dorsal, ventral, anterior, posterior. Lateral/medial directions depend on hemisphere. All views use RAS axes. Dorsal/ventral views put anterior at the top; other views put superior at the top.

"lateral"
layout str

"grid": rows are views and columns are hemispheres (left then right). "row" or "column": flatten panels in hemisphere-first order, retaining the requested view order within each hemisphere. One hemisphere is supported with the same rules.

"grid"
zoom float

Positive magnification relative to the common fitted parallel scale. Values above one enlarge the surfaces and may crop them.

1.0
color str

Uniform surface color understood by PyVista. The neutral gray matches the midpoint of surfplot's default Greys_r backdrop.

"#979797"
opacity float

Surface opacity from 0 (transparent) to 1 (opaque).

1.0
window_size tuple[int, int]

Total window width and height in pixels, including all panels.

(1000, 600)
background str

PyVista background color.

"white"

Returns:

Type Description
None

Initializes this plot instance and its persistent PyVista scene.

Attributes:

Name Type Description
plotter Plotter

Persistent renderer. Use subplot(row, column) to select a panel before changing its camera. Advanced controls remain native PyVista APIs.

Notes

Starts with the requested cameras and a shared parallel scale. Camera changes affect display only. Use add_layer for vertex data. Contacts default to nearest-surface projection followed by display mapping. Localization uses projection_surface when supplied, otherwise the display meshes themselves.

Surface materials follow surfplot/BrainSpace: ambient 0.05, diffuse 1.0, specular 0.1, and specular power 1.0, with smooth shading and one white camera headlight per panel. These defaults do not depend on PyVista's theme. Materials and lights remain adjustable through plotter.

add_layer

add_layer(
    data: ArrayLike | dict[str, ArrayLike],
    *,
    cmap: str | Colormap = "viridis",
    color_range: tuple[float, float] | None = None,
    cbar: bool = False,
    cbar_label: str = "",
    cbar_kws: dict[str, Any] | None = None,
) -> None

Color surface vertices, covering earlier layers where data are present.

Parameters:

Name Type Description Default
data ArrayLike | dict[str, ArrayLike]

One-dimensional vertex values, in surface vertex order. An array contains all displayed hemispheres, left then right. A dictionary with "left" and/or "right" keys can update individual hemispheres. NaN and masked values retain the previous color. Zero is a normal value; infinity is rejected. Inputs are copied, never resampled.

required
cmap str | Colormap

A PyVista-supported colormap name or Matplotlib colormap. Without color_range, finite values across both supplied hemispheres set the range and constant data use the middle color. Color alpha blends with the previous layer; overall surface opacity is unchanged.

"viridis"
color_range tuple[float, float] | None

Finite increasing (minimum, maximum) for continuous colors. Values outside this range use endpoint colors. None uses finite values across both supplied hemispheres; constant data use the middle color. Reuse a range to compare separate plots.

None
cbar bool

Include this layer's own colorbar in subsequent Figures. Each call adds a separate bar; False leaves earlier requests intact. Bars do not appear in view() or HTML. Masked and NaN values are excluded from automatic ranges.

False
cbar_label str

Colorbar title, such as the statistic name or units.

""
cbar_kws dict | None

Matplotlib Figure.colorbar options for this layer only, such as ticks, format, location, orientation, fraction, pad, or shrink. Requires cbar=True. Options are copied when the layer is added. Default bar length uses shrink=0.5; override it in this dictionary. Bars default to horizontal; location can select another side and its native orientation. The last layer's bar is outermost when bars share a side. Reuse a dictionary for a common style. Mapping, target axes, and label are controlled by anatplot: use cmap, color_range, and cbar_label rather than the colorbar keys mappable, cmap, norm, ax, cax, or label.

None

Returns:

Type Description
None

Updates surface colors in place and records this layer's optional colorbar. Geometry, cameras, and existing Figures are unchanged.

Notes

Colors update every view without changing cameras or adding overlapping meshes. Repeated calls composite colors in order; layers cannot yet be removed or edited independently. The colorbar shows the colormap before alpha blending with earlier layers or shading by scene lights. Use add_parcellation for discrete labels and label-to-color dictionaries. Vertex colors can blend across triangle interiors. Vertex counts alone cannot establish correspondence: templates and vertex ordering must match. File loading and atlas lookup tables remain upstream operations.

add_parcellation

add_parcellation(
    data: ArrayLike | dict[str, ArrayLike],
    *,
    cmap: str | Colormap | dict[int, str] = "tab20",
) -> None

Assign discrete colors to atlas labels, independent of label spacing.

Parameters:

Name Type Description Default
data ArrayLike | dict[str, ArrayLike]

One integer label per surface vertex, in the same ordering as add_layer. Labels may be sparse. NaN and masked values retain previous colors; zero is a normal label and must be masked if it denotes background. No registration or resampling is performed.

required
cmap str | Colormap | dict[int, str]

Assign successive palette entries to sorted unique labels across both supplied hemispheres. Colors repeat when the palette is exhausted; the same ID has the same color in both hemispheres. A dictionary specifies exact colors for every unmasked label.

"tab20"

Returns:

Type Description
None

Updates the existing vertex colors without adding meshes or a colorbar. Geometry, cameras, and source labels are unchanged.

Notes

Palette assignments depend on the labels supplied in this call. Use a fixed dictionary to preserve colors across different label subsets. Colors composite like add_layer and can blend within triangles; exact parcel outlines and colorbars are not provided.

add_contacts

add_contacts(
    xyz: ArrayLike,
    *,
    hemisphere: Literal["left", "right"] | None = None,
    project: bool = True,
    max_distance: float | None = 6.0,
    radius: float = 1.0,
    color: str | Sequence[str] = "crimson",
    lighting: bool = True,
) -> list[Actor]

Add projected or original-coordinate contacts to hemisphere views.

Parameters:

Name Type Description Default
xyz ArrayLike

Finite coordinates of shape (n_contacts, 3), with at least one row. Columns are R, A, S in millimetres, aligned with the localization mesh (or display mesh when project=False). Input coordinates are copied; row order is preserved.

required
hemisphere str | None

None assigns each contact to the closest available localization surface, or display surface when project=False. Exact distance ties select left. A single displayed hemisphere receives all contacts. "left" or "right" overrides assignment for every row. No assignment is inferred from the sign of X.

None
project bool

Project to the nearest point on the selected localization mesh, using the constructor's projection_surface when supplied, otherwise the display mesh. Map its triangle and barycentric position to the display mesh. Move the sphere center outward along the display face normal by radius + 0.05 mm. False retains supplied positions without offset.

True
max_distance float | None

Maximum distance in millimetres from an input contact to its selected localization surface. Contacts farther away are excluded with one summary warning; equality is included. None disables the limit. Ignored when project=False. Distance is measured before display mapping and sphere offset.

6.0
radius float

Positive sphere radius in millimetres, shared by this call's contacts.

1.0
color str | Sequence[str]

One named or hex color, or one color string per contact in row order. Spheres are opaque and participate in normal depth ordering.

"crimson"
lighting bool

Shade sphere colors using scene lights and highlights. False uses unlit colors. Geometry, radius, projection, and depth ordering are identical for both settings.

True

Returns:

Name Type Description
actors list[Actor]

Actors ordered by hemisphere (left then right), then requested view. Only hemispheres receiving contacts create actors. Row and color order are preserved within each group. Repeated calls retain actors. An empty list is returned when every contact exceeds the distance limit.

Notes

Cameras and zoom are preserved. Automatic assignment chooses a display hemisphere, not verified anatomical membership. Projection loses depth and does not establish cortical membership, including for deep contacts. Contacts within the projection distance limit are added, but overlap, far-side occlusion and view clipping can still hide them. The limit is a display selection, not a measure of localization accuracy. Changing radius also changes the outward display offset. No registration or ROI filtering is performed. Use project=False for original or externally prepared display coordinates.

ROIPlot

ROIPlot(
    image: Nifti1Image | Nifti2Image | str | Path,
    *,
    window_size: tuple[int, int] = (900, 650),
    background: str = "white",
)

Bases: _ContactPlot

Display selected region boundaries from a discrete NIfTI image.

Initialize an empty region scene with an anterior-superior camera.

Parameters:

Name Type Description Default
image Nifti1Image | Nifti2Image | str | Path

Binary mask or discrete label image accepted by roi_surface. A path is opened once; the image is retained and must not be modified while adding regions. Call add_roi to select what to display.

required
window_size tuple[int, int]

Window width and height in pixels.

(900, 650)
background str

PyVista background color.

"white"

Returns:

Type Description
None

Initializes this plot instance and its persistent PyVista scene.

Attributes:

Name Type Description
plotter Plotter

Persistent scene. Region actors and camera controls are native PyVista.

Notes

The initial parallel view looks from anterior and superior toward the regions, with superior as view-up. In RAS this uses camera offset (0, 1, 1) and view-up (0, 0, 1); anatomical left appears on the viewer's right. The first region or contact batch fits the camera. Later additions preserve framing; use plotter.reset_camera() to include all actors again. For reproducible figures, set PyVista camera parameters in Python before to_figure(). Use view() to explore the anatomy.

add_roi

add_roi(
    labels: ArrayLike,
    *,
    color: str = "#D98C70",
    opacity: float = 0.1,
    smoothing: bool = True,
) -> Actor

Add the outer boundary of selected labels, preserving existing framing.

Parameters:

Name Type Description Default
labels Sequence[int]

Positive IDs present in the image, merged into one display region. For a binary mask, use [1]. Separate calls retain separate actors.

required
color str

Uniform PyVista surface color.

"#D98C70"
opacity float

Surface opacity from 0 to 1. The default is a translucent anatomical background for displaying internal structures.

0.1
smoothing bool

Enable SurfaceNets smoothing; see roi_surface for limitations.

True

Returns:

Name Type Description
actor Actor

Added surface actor. Its properties can be adjusted with PyVista.

Notes

Original voxel labels and the image affine are never modified. The first addition to an empty scene fits the camera. Later additions preserve camera position, direction, projection, and zoom; only the depth clipping range is updated. New regions outside the current frame may remain offscreen. Use plotter.reset_camera() to fit all actors when needed.

add_contacts

add_contacts(
    xyz: ArrayLike,
    *,
    radius: float = 1.0,
    color: str | Sequence[str] = "crimson",
    lighting: bool = True,
) -> Actor

Add opaque contact spheres at their supplied coordinates.

Parameters:

Name Type Description Default
xyz ArrayLike

Finite coordinates with shape (n_contacts, 3), with at least one contact. Columns are R, A, S in millimetres, in the same coordinate frame as the displayed anatomy. Input order is preserved.

required
radius float

Positive finite sphere radius in millimetres, shared by all contacts. This is a display size, not an estimate of electrode dimensions.

1.0
color str | Sequence[str]

One named or hex color for all contacts, or exactly one color string per contact in xyz order. Examples: "crimson" or ["red", "#3366CC"]. Colors are interpreted by PyVista; spheres are opaque.

"crimson"
lighting bool

Shade sphere colors using scene lights and highlights. False uses unlit colors. Geometry, radius, coordinates, and depth ordering are identical for both settings.

True

Returns:

Name Type Description
actor Actor

One actor containing all contact spheres added by this call. Subsequent calls add separate actors without replacing earlier ones.

Notes

Coordinates are copied and never projected, registered, filtered by ROI membership, or moved to avoid occlusion. Contacts outside an ROI remain visible at their supplied locations. Spheres use real mesh geometry so their physical size and colors are retained in PNG and HTML exports. The first contact batch in an empty scene fits the camera. Later additions preserve camera position, direction, projection, and zoom; only the depth clipping range is updated. Contacts outside the current frame may remain offscreen. Use plotter.reset_camera() to fit all actors when needed. Surface transparency affects visibility; contacts obey normal depth order.

VolumePlot

VolumePlot(
    *,
    left: PolyData | str | Path | None = None,
    right: PolyData | str | Path | None = None,
    color: str = "#D8D8D8",
    opacity: float = 0.1,
    window_size: tuple[int, int] = (900, 650),
    background: str = "white",
)

Bases: _ContactPlot

Display a translucent whole-brain surface background in one scene.

Initialize the whole-brain background and its dorsal camera.

Parameters:

Name Type Description Default
left PolyData | str | Path | None

Anatomical hemisphere surfaces accepted by load_surface. Supply at least one, normally both pial meshes. Meshes must already share one RAS coordinate frame in millimetres. Positions are retained exactly.

None
right PolyData | str | Path | None

Anatomical hemisphere surfaces accepted by load_surface. Supply at least one, normally both pial meshes. Meshes must already share one RAS coordinate frame in millimetres. Positions are retained exactly.

None
color str

Uniform PyVista surface color.

"#D8D8D8"
opacity float

Brain background opacity from 0 to 1.

0.1
window_size tuple[int, int]

Window width and height in pixels.

(900, 650)
background str

PyVista background color.

"white"

Returns:

Type Description
None

Initializes this plot instance and its persistent PyVista scene.

Attributes:

Name Type Description
plotter Plotter

Persistent renderer, including the shared scene camera.

Notes

Uses surface meshes, not voxel volume rendering or slices. The initial top (dorsal) view puts anterior at the top and anatomical left on the left. The translucent background provides whole-brain context. Inflated meshes do not represent physical anatomy. Contact coordinates must already match the anatomical surfaces; no projection or registration is performed. Adding contacts preserves the initial or manually adjusted camera framing.

add_contacts

add_contacts(
    xyz: ArrayLike,
    *,
    radius: float = 1.0,
    color: str | Sequence[str] = "crimson",
    lighting: bool = True,
) -> Actor

Add opaque contact spheres at their supplied coordinates.

Parameters:

Name Type Description Default
xyz ArrayLike

Finite coordinates with shape (n_contacts, 3), with at least one contact. Columns are R, A, S in millimetres, in the same coordinate frame as the displayed anatomy. Input order is preserved.

required
radius float

Positive finite sphere radius in millimetres, shared by all contacts. This is a display size, not an estimate of electrode dimensions.

1.0
color str | Sequence[str]

One named or hex color for all contacts, or exactly one color string per contact in xyz order. Examples: "crimson" or ["red", "#3366CC"]. Colors are interpreted by PyVista; spheres are opaque.

"crimson"
lighting bool

Shade sphere colors using scene lights and highlights. False uses unlit colors. Geometry, radius, coordinates, and depth ordering are identical for both settings.

True

Returns:

Name Type Description
actor Actor

One actor containing all contact spheres added by this call. Subsequent calls add separate actors without replacing earlier ones.

Notes

Coordinates are copied and never projected, registered, filtered by ROI membership, or moved to avoid occlusion. Contacts outside an ROI remain visible at their supplied locations. Spheres use real mesh geometry so their physical size and colors are retained in PNG and HTML exports. The first contact batch in an empty scene fits the camera. Later additions preserve camera position, direction, projection, and zoom; only the depth clipping range is updated. Contacts outside the current frame may remain offscreen. Use plotter.reset_camera() to fit all actors when needed. Surface transparency affects visibility; contacts obey normal depth order.

Display and export

These methods apply to SurfacePlot, ROIPlot, and VolumePlot.

to_figure

to_figure(
    *,
    ax: Axes | None = None,
    figsize: tuple[float, float] | None = None,
    dpi: float | None = None,
    render_dpi: float = 600,
) -> Figure

Create an independent Matplotlib snapshot of the current scene.

Parameters:

Name Type Description Default
ax Axes | None

Target 2D Axes. None creates a Figure; supplied axes retain existing artists and siblings. Each call adds a snapshot and the requested colorbars.

None
figsize tuple[float, float] | None

New Figure width and height in inches, default window_size / 100. Only valid when ax is None.

None
dpi float | None

New Figure canvas DPI, default 150. Only valid when ax is None; supplied figures retain their size and DPI.

None
render_dpi float

Finite positive brain-image pixels per inch, measured after layout and rounded up to whole pixels. Lower values provide lighter previews.

600

Returns:

Name Type Description
figure Figure

New or supplied Figure, without displaying or saving. Use pyplot.show() or figure.savefig(). The brain occupies one Axes with its aspect preserved.

Notes

The snapshot keeps scene cameras and window state unchanged and survives close(). Later scene edits, Figure resizing, or export at higher DPI do not rerender it; create another snapshot at the intended size and render_dpi. PNG dimensions follow Figure size and export DPI. PDF/SVG embed the original brain pixels with vector titles and colorbars. Rendering requires a working VTK graphics context.

view

view(
    *,
    jupyter_backend: Literal["trame", "server", "client"]
    | None = None,
) -> None

Open the current scene for three-dimensional exploration.

Parameters:

Name Type Description Default
jupyter_backend (trame, server, client)

Notebook viewer backend. None selects Trame in Notebooks, allowing server/client switching. Server streams VTK images; client renders geometry in the browser. Explicit backends require Notebook mode.

"trame"

Returns:

Type Description
None

Displays the viewer while retaining this scene for later additions or export. The viewer return value is not exposed.

Notes

Displays geometry without Matplotlib titles or colorbars. Desktop use opens a native window; on macOS it requires the main thread. Press Q to return to Python while retaining the scene. Closing via OS controls may destroy its graphics context. Notebook viewers require an open scene. Browser rendering may differ from VTK. Use to_figure() for a publication snapshot and export_html() for an independent browser scene.

export_html

export_html(
    path: str | Path | None = None,
) -> StringIO | None

Export a self-contained interactive browser scene.

Parameters:

Name Type Description Default
path str | Path | None

Destination HTML file; its parent directory must exist. PyVista changes the suffix to .html. If omitted, return an in-memory buffer.

None

Returns:

Type Description
StringIO | None

HTML buffer when path is None, otherwise None after writing the file.

Notes

Uses Trame scene export and its offline viewer, preserving camera projection and zoom. The exported file embeds geometry and a VTK.js viewer: readers need WebGL, but no Python server or installation. Browser lighting and transparency can differ from native VTK screenshots. Browser camera changes do not update the original Python scene.

close

close() -> None

Release the scene's graphics resources.

Returns:

Type Description
None

Closes the underlying PyVista plotter. Existing Matplotlib snapshots and independent HTML exports remain usable; this scene cannot be rendered again.