Making a surface plot of a 3D statistical map

In this example, we will project a 3D statistical map onto a cortical mesh using vol_to_surf, display a surface plot of the projected map using plot_surf_stat_map with different plotting engines, and add contours of regions of interest using plot_surf_contours.

Get a statistical map

from nilearn import datasets

stat_img = datasets.load_sample_motor_activation_image()

Get a cortical mesh

Use mesh curvature to display useful anatomical information on inflated meshes

Here, we load the curvature map of the hemisphere under study, and define a surface map whose value for a given vertex is 1 if the curvature is positive, -1 if the curvature is negative.

import numpy as np

from nilearn import surface

curv_right = surface.load_surf_data(fsaverage.curv_right)
curv_right_sign = np.sign(curv_right)

Sample the 3D data around each node of the mesh

Plot the result

You can visualize the texture on the surface using the function plot_surf_stat_map which uses matplotlib as the default plotting engine.

from nilearn import plotting

fig = plotting.plot_surf_stat_map(
    fsaverage.infl_right,
    texture,
    hemi="right",
    title="Surface right hemisphere",
    colorbar=True,
    threshold=1.0,
    bg_map=curv_right_sign,
)
fig.show()
Surface right hemisphere

Interactive plotting with Plotly

If you have a recent version of Nilearn (>=0.8.2), and if you have plotly installed, you can easily configure plot_surf_stat_map to use plotly instead of matplotlib:

engine = "plotly"
# If plotly is not installed, use matplotlib
try:
    import plotly.graph_objects as go  # noqa: F401
except ImportError:
    engine = "matplotlib"

print(f"Using plotting engine {engine}.")

fig = plotting.plot_surf_stat_map(
    fsaverage.infl_right,
    texture,
    hemi="right",
    title="Surface right hemisphere",
    colorbar=True,
    threshold=1.0,
    bg_map=curv_right_sign,
    bg_on_data=True,
    engine=engine,  # Specify the plotting engine here
)

# Display the figure as with matplotlib figures
# fig.show()
Using plotting engine plotly.
/opt/hostedtoolcache/Python/3.12.6/x64/lib/python3.12/site-packages/nilearn/plotting/surf_plotting.py:980: UserWarning: vmin cannot be chosen when cmap is symmetric
  fig = _plot_surf_plotly(

When using matplotlib as the plotting engine, a standard matplotlib.figure.Figure is returned. With plotly as the plotting engine, a custom PlotlySurfaceFigure is returned which provides a similar API to the Figure. For example, you can save a static version of the figure to file (this option requires to have kaleido installed):

# Save the figure as we would do with a matplotlib figure
# Uncomment the following line to save the previous figure to file
# fig.savefig("right_hemisphere.png")

Plot 3D image for comparison

plotting.plot_glass_brain(
    stat_img,
    display_mode="r",
    plot_abs=False,
    title="Glass brain",
    threshold=2.0,
)

plotting.plot_stat_map(
    stat_img,
    display_mode="x",
    threshold=1.0,
    cut_coords=range(0, 51, 10),
    title="Slices",
)
  • plot 3d map to surface projection
  • plot 3d map to surface projection
<nilearn.plotting.displays._slicers.XSlicer object at 0x7f6ee2f63230>

Use an atlas and choose regions to outline

destrieux_atlas = datasets.fetch_atlas_surf_destrieux()
parcellation = destrieux_atlas["map_right"]

# these are the regions we want to outline
regions_dict = {
    b"G_postcentral": "Postcentral gyrus",
    b"G_precentral": "Precentral gyrus",
}

# get indices in atlas for these labels
regions_indices = [
    np.where(np.array(destrieux_atlas["labels"]) == region)[0][0]
    for region in regions_dict
]

labels = list(regions_dict.values())
[get_dataset_dir] Dataset found in /home/runner/work/nilearn/nilearn/nilearn_data/destrieux_surface

Display outlines of the regions of interest on top of a statistical map

figure = plotting.plot_surf_stat_map(
    fsaverage.infl_right,
    texture,
    hemi="right",
    title="Surface right hemisphere",
    colorbar=True,
    threshold=1.0,
    bg_map=fsaverage.sulc_right,
)

plotting.plot_surf_contours(
    fsaverage.infl_right,
    parcellation,
    labels=labels,
    levels=regions_indices,
    figure=figure,
    legend=True,
    colors=["g", "k"],
)
plotting.show()
Surface right hemisphere

Plot with higher-resolution mesh

fetch_surf_fsaverage takes a mesh argument which specifies whether to fetch the low-resolution fsaverage5 mesh, or the high-resolution fsaverage mesh. Using mesh="fsaverage" will result in more memory usage and computation time, but finer visualizations.

big_fsaverage = datasets.fetch_surf_fsaverage("fsaverage")
big_texture = surface.vol_to_surf(stat_img, big_fsaverage.pial_right)

plotting.plot_surf_stat_map(
    big_fsaverage.infl_right,
    big_texture,
    hemi="right",
    colorbar=True,
    title="Surface right hemisphere: fine mesh",
    threshold=1.0,
    bg_map=big_fsaverage.sulc_right,
)
Surface right hemisphere: fine mesh
[get_dataset_dir] Dataset found in /home/runner/work/nilearn/nilearn/nilearn_data/fsaverage

<Figure size 470x500 with 2 Axes>

Plot multiple views of the 3D volume on a surface

plot_img_on_surf takes a statistical map and projects it onto a surface. It supports multiple choices of orientations, and can plot either one or both hemispheres. If no surf_mesh is given, plot_img_on_surf projects the images onto FreeSurfer's fsaverage5.

plotting.plot_img_on_surf(
    stat_img,
    views=["lateral", "medial"],
    hemispheres=["left", "right"],
    colorbar=True,
)
plotting.show()
plot 3d map to surface projection

3D visualization in a web browser

An alternative to nilearn.plotting.plot_surf_stat_map is to use nilearn.plotting.view_surf or nilearn.plotting.view_img_on_surf that give more interactive visualizations in a web browser. See 3D Plots of statistical maps or atlases on the cortical surface for more details.

view = plotting.view_surf(
    fsaverage.infl_right, texture, threshold="90%", bg_map=fsaverage.sulc_right
)

# In a Jupyter notebook, if ``view`` is the output of a cell, it will
# be displayed below the cell
view