netneurotools.plotting.pv_plot_surface
- netneurotools.plotting.pv_plot_surface(vertex_data, template, surf='inflated', hemi='both', layout='default', mask_medial=True, cmap='viridis', clim=None, zoom_ratio=1.25, show_colorbar=True, cbar_title=None, show_plot=True, jupyter_backend='html', lighting_style='default', save_fig=None, plotter_kws=None, mesh_kws=None, cbar_kws=None, silhouette_kws=None, data_dir=None, verbose=0)[source]
Plot surface data using PyVista.
This function provides a flexible interface for visualizing cortical surface data on standard neuroimaging templates. It supports multiple hemispheres, layouts, lighting styles, and customization options.
- Parameters:
vertex_data (array-like or tuple of array-like) – Data array(s) to be plotted on the surface. If hemi is “both”, this should be a tuple of two arrays (left, right) or a single concatenated array. For single hemisphere, provide a single array matching the number of vertices in that hemisphere.
template (str) – Template to use for plotting. Options include ‘fsaverage’, ‘fsaverage6’, ‘fsaverage5’, ‘fsaverage4’, ‘fslr4k’, ‘fslr8k’, ‘fslr32k’, ‘fslr164k’, ‘civet41k’, ‘civet164k’.
surf (str, optional) – Surface type to plot. Available options depend on template:
fsaverage templates: ‘midthickness’, ‘pial’, ‘white’, ‘inflated’, ‘sphere’
fslr templates: ‘midthickness’, ‘pial’, ‘white’, ‘inflated’, ‘veryinflated’, ‘sphere’
civet templates: ‘midthickness’, ‘white’, ‘inflated’
Default is ‘inflated’.
hemi (str, optional) – Hemisphere to plot. Options: ‘L’ (left), ‘R’ (right), ‘both’. Default is ‘both’.
layout (str, optional) – Layout of the plot panels:
‘default’: 2x2 grid for both hemispheres, 1x2 for single hemisphere
‘single’: Single panel (useful for custom views)
‘row’: Horizontal arrangement of all views
‘column’: Vertical arrangement of all views
Default is ‘default’.
mask_medial (bool, optional) – Whether to mask the medial wall (set to NaN). Only applies to templates with medial wall annotations. Default is True.
cmap (str, optional) – Matplotlib colormap name. Default is ‘viridis’.
clim (tuple of float, optional) – Colorbar limits as (vmin, vmax). If None, will be set to 2.5th and 97.5th percentiles of the data. Default is None.
zoom_ratio (float, optional) – Camera zoom level. Values > 1.0 zoom in, < 1.0 zoom out. Default is 1.25.
show_colorbar (bool, optional) – Whether to display the colorbar. Default is True.
cbar_title (str, optional) – Title text for the colorbar. Default is None.
show_plot (bool, optional) – Whether to display the plot immediately. Set to False to return the plotter object for further customization. Default is True.
jupyter_backend (str, optional) – Backend for Jupyter notebook rendering. See PyVista documentation for available options (‘html’, ‘static’, ‘trame’, etc.). Set to None for non-notebook environments. Default is ‘html’.
lighting_style (str, optional) – Lighting style preset:
‘default’, ‘lightkit’: Standard three-point lighting
‘threelights’: Alternative three-light setup
‘silhouette’: High-contrast silhouette rendering
‘metallic’, ‘plastic’, ‘shiny’, ‘glossy’: Material presets
‘ambient’, ‘plain’: Flat lighting styles
Default is ‘default’.
save_fig (str or Path, optional) – Path to save the figure. Supported formats: .png, .jpeg, .jpg, .bmp, .tif, .tiff (raster); .svg, .eps, .ps, .pdf, .tex (vector). Default is None (no save).
- Returns:
pl – PyVista plotter object. Can be further customized before calling pl.show() if show_plot=False.
- Return type:
- Other Parameters:
plotter_kws (dict, optional) – Additional keyword arguments to pass to
pyvista.Plotter. Default is None.mesh_kws (dict, optional) – Additional keyword arguments to pass to
pyvista.Plotter.add_mesh(). Default is None.cbar_kws (dict, optional) – Additional keyword arguments to pass to
pyvista.Plotter.add_scalar_bar(). Default is None.silhouette_kws (dict, optional) – Additional keyword arguments to pass to
pyvista.Plotter.add_silhouette(). Only used when lighting_style=’silhouette’. Default is None.data_dir (str or Path, optional) – Path to use as data directory. If not specified, will check for environmental variable ‘NNT_DATA’; if that is not set, will use ~/nnt-data instead. Default: None
verbose (int, optional) – Modifies verbosity of download, where higher numbers mean more updates. Default: 0
Notes
Template and surface compatibility:
Not all surface types are available for all templates. The function will automatically fetch the appropriate template data from neuromaps or use locally cached data.
Layouts:
‘default’: Shows medial and lateral views for each hemisphere
‘single’: Shows only one view (useful for custom camera angles)
‘row’/’column’: Linear arrangements of all standard views
Data format:
The vertex_data array(s) must match the number of vertices in the surface template. For example, fsaverage5 has 10,242 vertices per hemisphere.
When hemi=’both’, vertex_data can be:
A tuple/list: (left_data, right_data)
A concatenated array: np.concatenate([left_data, right_data])
The function automatically handles data splitting based on template vertex counts.
Parcellated data:
If you have parcellated/regional data rather than vertex-wise data, use
netneurotools.interface.parcels_to_vertices()to convert it to vertex-level data before plotting. Always verify the data before and after transformation to ensure correct mapping.Lighting styles:
Different lighting presets affect surface appearance through ambient, diffuse, specular, and specular_power parameters:
Metallic: Low ambient (0.1), high specular (1.0)
Plastic: Balanced properties, moderate specular (0.3)
Shiny: High specular (0.8), high specular_power (50)
Silhouette: Adds white edge outlines for enhanced contrast. Note that silhouette rendering often needs tuning based on data geometry to achieve the best result, which can be done via silhouette_kws (e.g., adjusting feature_angle or color).
Jupyter notebooks:
When using in Jupyter, the function automatically sets notebook=True and off_screen=True for proper rendering.
There can be various issues when plotting in Jupyter notebooks depending on your environment. For troubleshooting and detailed configuration options, see:
Backend selection:
Choose the appropriate jupyter_backend for your use case:
‘trame’: Best performance and interactivity (recommended)
‘html’: Good interactivity, works in most environments
‘static’: No interactivity but reliable fallback option
If trame does not work in your environment, try html. The static option should always work as a last resort.
Customization with keyword arguments:
The plotter_kws, mesh_kws, cbar_kws, and silhouette_kws parameters allow flexible overriding of default settings. For example:
plotter_kws={‘window_size’: (2000, 1500)} for higher resolution
mesh_kws={‘smooth_shading’: False} to disable smooth shading
cbar_kws={‘n_labels’: 5} for more colorbar labels
silhouette_kws={‘feature_angle’: 30} to adjust edge detection sensitivity
Examples
Basic usage:
Plot random data on fsaverage5 pial surface:
>>> from netneurotools.plotting import pv_plot_surface >>> import numpy as np >>> data_L = np.random.random((10242,)) >>> data_R = np.random.random((10242,)) >>> pl = pv_plot_surface( ... (data_L, data_R), ... template="fsaverage5", ... surf="pial" ... )
Available template/surface combinations:
>>> # fsaverage templates (all densities) >>> templates = ["fsaverage", "fsaverage6", "fsaverage5", "fsaverage4"] >>> surfaces = ["midthickness", "pial", "white", "inflated", "sphere"] >>> >>> # fslr templates >>> templates = ["fslr4k", "fslr8k", "fslr32k", "fslr164k"] >>> surfaces = ["midthickness", "pial", "white", "inflated", ... "veryinflated", "sphere"] >>> >>> # civet templates >>> templates = ["civet41k", "civet164k"] >>> surfaces = ["midthickness", "white", "inflated"]
Different layouts:
Compare all layout options:
>>> for layout in ["default", "single", "row", "column"]: ... pl = pv_plot_surface( ... (data_L, data_R), ... template="fsaverage5", ... surf="inflated", ... layout=layout, ... cbar_title=f"Layout: {layout}" ... )
Adjusting zoom:
Control the camera zoom level:
>>> pl = pv_plot_surface( ... (data_L, data_R), ... template="fsaverage5", ... surf="inflated", ... zoom_ratio=1.7, # Closer view ... )
Colorbar control:
Customize colorbar display and title:
>>> pl = pv_plot_surface( ... (data_L, data_R), ... template="fsaverage5", ... surf="inflated", ... show_colorbar=True, ... cbar_title="Activation (z-score)", ... )
Hide the colorbar:
>>> pl = pv_plot_surface( ... (data_L, data_R), ... template="fsaverage5", ... surf="inflated", ... show_colorbar=False, ... )
Colormap and limits:
Use different colormaps and set explicit color limits:
>>> pl = pv_plot_surface( ... (data_L, data_R), ... template="fsaverage5", ... surf="inflated", ... cmap="RdBu_r", # Reverse red-blue colormap ... clim=(-3, 3), # Symmetric limits ... )
Sequential colormap for positive-only data:
>>> pl = pv_plot_surface( ... (data_L, data_R), ... template="fsaverage5", ... surf="inflated", ... cmap="plasma", ... clim=(0, 1), ... )
Saving figures:
Save as high-resolution PNG:
>>> pl = pv_plot_surface( ... (data_L, data_R), ... template="fsaverage5", ... surf="inflated", ... save_fig="brain_plot.png", ... )
Save as vector graphics (SVG):
>>> pl = pv_plot_surface( ... (data_L, data_R), ... template="fsaverage5", ... surf="inflated", ... save_fig="brain_plot.svg", ... )
Lighting styles:
Explore different lighting presets:
>>> for style in ["metallic", "plastic", "shiny", "glossy"]: ... pl = pv_plot_surface( ... (data_L, data_R), ... template="fsaverage5", ... surf="inflated", ... lighting_style=style, ... cbar_title=f"Style: {style}", ... save_fig=f"brain_{style}.png", ... )
Silhouette style for presentations (often needs tuning):
>>> pl = pv_plot_surface( ... (data_L, data_R), ... template="fsaverage5", ... surf="inflated", ... lighting_style="silhouette", # High-contrast edges ... cmap="coolwarm", ... silhouette_kws={'feature_angle': 30, 'color': 'black'}, ... )
Customizing with keyword arguments:
Override default settings for higher resolution figures:
>>> pl = pv_plot_surface( ... (data_L, data_R), ... template="fsaverage5", ... surf="inflated", ... plotter_kws={'window_size': (2000, 1500)}, # Higher resolution ... )
Disable smooth shading for sharper vertex transitions:
>>> pl = pv_plot_surface( ... (data_L, data_R), ... template="fsaverage5", ... surf="inflated", ... mesh_kws={'smooth_shading': False}, ... )
Advanced customization:
Combine multiple options:
>>> pl = pv_plot_surface( ... (data_L, data_R), ... template="fslr32k", ... surf="veryinflated", ... layout="row", ... mask_medial=True, ... cmap="viridis", ... clim=(0.2, 0.8), ... zoom_ratio=1.5, ... show_colorbar=True, ... cbar_title="Correlation", ... lighting_style="shiny", ... save_fig="publication_figure.png", ... jupyter_backend=None, # For script usage ... )
Use plotter object for further customization:
>>> pl = pv_plot_surface( ... (data_L, data_R), ... template="fsaverage5", ... surf="inflated", ... show_plot=False, # Don't show yet ... ) >>> # Add custom annotations, lights, etc. >>> pl.add_text("Custom Title", position="upper_edge") >>> pl.show()