netneurotools.plotting.pv_plot_subcortex
- netneurotools.plotting.pv_plot_subcortex(parcel_data, template, include_keys=None, custom_surfaces=None, hemi='both', layout='default', cmap='viridis', clim=None, panel_size=(500, 400), zoom_ratio=1.4, show_colorbar=True, show_silhouette=False, parallel_projection=True, cbar_title=None, show_plot=True, jupyter_backend='static', lighting_style='default', save_fig=None, plotter_kws=None, mesh_kws=None, cbar_kws=None, silhouette_kws=None, force_fetch=False, data_dir=None, verbose=0)[source]
Plot subcortical data using PyVista.
This function provides a flexible interface for visualizing parcellated subcortical data on standard neuroimaging atlases. It supports custom surfaces, multiple layouts, and various customization options for publication-quality visualizations.
- Parameters:
parcel_data (dict) – Dictionary mapping region identifiers to data values. Keys should match the region identifiers in the selected template atlas (e.g., ‘10’ for a specific region in aseg template).
template (str) – Atlas template to use for subcortical visualization. A pre-computed subcortical surface or a custom surface can be used. Options:
‘aseg’: FreeSurfer automatic segmentation
‘tianS1’, ‘tianS2’, ‘tianS3’, ‘tianS4’: Tian et al. subcortical atlas
‘custom’: User-provided custom surfaces (requires custom_surfaces)
include_keys (list or tuple of lists, optional) – Region identifiers to include in the visualization. If hemi is “both”, this should be a tuple of two lists (left, right). If None, will use all keys from parcel_data. Default is None.
custom_surfaces (dict, optional) – Dictionary mapping region identifiers (as strings) to PyVista mesh objects. Only used when template=’custom’. Should be generated with
_pv_make_subcortex_surfaces()or similar. Default is None.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’.
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.
panel_size (tuple of int, optional) – Size of each panel in pixels as (width, height). Default is (500, 400).
zoom_ratio (float, optional) – Camera zoom level. Values > 1.0 zoom in, < 1.0 zoom out. Default is 1.4.
show_colorbar (bool, optional) – Whether to display the colorbar. Default is True.
show_silhouette (bool, optional) – Whether to add silhouette edges to the meshes for enhanced visibility. Default is False.
parallel_projection (bool, optional) – Whether to use parallel projection for the camera. 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 ‘static’.
lighting_style (str, optional) – Lighting style preset:
‘default’, ‘lightkit’: Standard three-point lighting
‘threelights’: Alternative three-light setup
‘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 show_silhouette=True. Default is None.force_fetch (bool, optional) – If True, will re-download template data even if cached locally. Recommended to use periodically to refresh data. Default is False.
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
Available templates:
‘aseg’: FreeSurfer’s automatic brain segmentation, includes major subcortical structures (thalamus, striatum, hippocampus, etc.) Generated from
tpl-MNI152NLin2009cAsym_res-01_seg-aseg_dseg.nii.gzfrom TemplateFlow. See FreeSurferColorLUT for region IDs.‘tianS1-S4’: Multi-level atlases from Tian et al. [1] providing finer subdivisions of subcortical structures. Generated from
Group-Parcellation/3T/Subcortex-Only/Tian_Subcortex_S{1,2,3,4}_3T_2009cAsym.nii.gz.‘custom’: User-provided atlas generated from volumetric data using
_pv_make_subcortex_surfaces()
Template data updates:
Subcortical surface templates are periodically updated to add new atlases and optimize existing surface quality. To ensure you have the latest versions, it’s recommended to set
force_fetch=Trueoccasionally to re-download and refresh your local cached data. This is especially important when:New atlas templates are announced
Surface quality improvements are released
You encounter rendering issues with cached surfaces
Starting a new publication project
Data format:
The parcel_data dictionary maps region identifiers to scalar values:
>>> parcel_data = { ... '10': 0.5, # thalamus ... '11': 0.7, # caudate ... '12': 0.6, # putamen ... }
Region identifiers depend on the selected template (integer IDs from FreeSurfer, Tian atlas, etc.).
There is no intrinsic left/right distinction in subcortical atlases, so include_keys must specify which regions to plot for each hemisphere.
For example, this is usually how you would set include_keys, when you want left and right structures plotted in their respective hemisphere panels. >>> include_keys = ([‘10’, ‘11’, ‘12’], [‘49’, ‘50’, ‘51’]) # doctest: +SKIP
In contrast, the following will display BOTH left and right structures in BOTH hemisphere panels: >>> include_keys = ([‘10’, ‘11’, ‘12’, ‘49’, ‘50’, ‘51’]) # doctest: +SKIP
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
Parallel projection:
When comparing subcortical structures of very different sizes (e.g., thalamus vs. amygdala), parallel_projection=True provides scale-invariant visualization, while parallel_projection=False uses perspective projection.
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)
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={‘ambient’: 0.5} to adjust material properties
cbar_kws={‘n_labels’: 5} for more colorbar labels
silhouette_kws={‘feature_angle’: 30} to adjust edge detection sensitivity
References
Examples
Basic usage:
Plot random data on aseg template:
>>> from netneurotools.plotting import pv_plot_subcortex >>> parcel_data = { ... '10': 0.5, '11': 0.7, '12': 0.6, '13': 0.8, ... '49': 0.4, '50': 0.6, '51': 0.5, '52': 0.7 ... } >>> pl = pv_plot_subcortex( ... parcel_data, ... template="aseg" ... include_keys=(['10', '11', '12', '13'], ['49', '50', '51', '52']) ... )
Different atlases:
Use Tian atlas with finer subcortical subdivisions:
>>> parcel_data_tian = {str(k+1): v for k, v in enumerate( ... np.random.random(16) ... )} >>> pl = pv_plot_subcortex( ... parcel_data_tian, ... template="tianS2" # Tian level 2 atlas ... )
Single hemisphere:
Plot only left hemisphere with custom include_keys:
>>> include_keys = ['10', '11', '12'] # thalamus, caudate, putamen >>> pl = pv_plot_subcortex( ... parcel_data, ... template="aseg", ... hemi="L", ... include_keys=include_keys, ... )
Different layouts:
Compare all layout options:
>>> for layout in ["default", "single", "row", "column"]: ... pl = pv_plot_subcortex( ... parcel_data, ... template="aseg", ... layout=layout, ... cbar_title=f"Layout: {layout}" ... )
Custom colorbar and limits:
Set explicit color limits and colorbar title:
>>> pl = pv_plot_subcortex( ... parcel_data, ... template="aseg", ... cmap="RdBu_r", ... clim=(-1, 1), # Symmetric limits ... cbar_title="Activation (z-score)", ... )
Silhouette edges:
Add edge outlines for clarity, for example, this simulates the 2D flat drawing style:
>>> pl = pv_plot_subcortex( ... parcel_data, ... template="aseg", ... lighting_style="none", ... show_silhouette=True, ... silhouette_kws={'color': 'black', 'line_width': 5}, ... )
Saving figures:
Save as high-resolution PNG:
>>> pl = pv_plot_subcortex( ... parcel_data, ... template="aseg", ... save_fig="subcortex_plot.png", ... )
Save as vector graphics (SVG):
>>> pl = pv_plot_subcortex( ... parcel_data, ... template="aseg", ... save_fig="subcortex_plot.svg", ... )
Lighting styles:
Explore different lighting presets:
>>> for style in ["metallic", "plastic", "shiny", "glossy"]: ... pl = pv_plot_subcortex( ... parcel_data, ... template="aseg", ... lighting_style=style, ... cbar_title=f"Style: {style}", ... save_fig=f"subcortex_{style}.png", ... )
Advanced customization:
Combine multiple options for publication-quality figures:
>>> pl = pv_plot_subcortex( ... parcel_data, ... template="tianS2", ... hemi="both", ... layout="row", ... cmap="plasma", ... clim=(0, 1), ... zoom_ratio=1.6, ... show_colorbar=True, ... cbar_title="Regional Connectivity", ... lighting_style="shiny", ... parallel_projection=True, ... save_fig="publication_figure.png", ... jupyter_backend=None, # For script usage ... )
Custom surfaces:
Use user-defined subcortical surfaces generated from volumetric data:
>>> from netneurotools.plotting import _pv_make_subcortex_surfaces >>> # Assuming atlas.nii.gz contains custom volumetric segmentation >>> custom_surfs = _pv_make_subcortex_surfaces( ... "atlas.nii.gz", ... include_keys=[1, 2, 3] ... ) >>> pl = pv_plot_subcortex( ... parcel_data, ... template="custom", ... custom_surfaces=custom_surfs, ... )
Plotter customization for further manipulation:
Return plotter object without showing to add custom elements:
>>> pl = pv_plot_subcortex( ... parcel_data, ... template="aseg", ... show_plot=False, # Don't show yet ... ) >>> # Add custom annotations >>> pl.add_text("Custom Title", position="upper_edge") >>> pl.show()