Plotting 2 stat maps over same template (Nilearn) + asymmetric cbars


I am trying to use nilearn to plot some t maps over a brain template. I have 2 maps and I’d like to plot the activations over the same template, possibly binarising the acvitation maps (meaning I do not need a colour map, I just need to plot one t map in blue and the other one in red) and possibly plot in a third colour the overlap between the two activations.

Has any of you ever done something like that?

Another thing that I cannot do with nilearn is to use asymmetric maps instead of symmetric ones. Any solution for that? The argument symmetric_cbar of the function plot_stat_map does not seem to be working.

Thanks a lot!


Hello I’ve seen this done but cant remenber how. It’s definitely not a feature but can be done. Unless someone comes up with a better solution you can hack the atlas plotting functions that plot different labels in different color.

Either binarize both contrasts and input the voxel activated for each of them in the same 3D nifti with labels 1 and 2, then plotting.plot_roi should work.

Or threshold images, normalize them to values between 0 and 1, concatenate them into a 4D nifti and use plotting.plot_prob_atlas


Hi, for the first one if binarising is ok you could try something like

from matplotlib import pyplot as plt
from matplotlib.colors import ListedColormap
from matplotlib import colorbar, colors

from nilearn import plotting, image
from neuroquery import fetch_neuroquery_model, NeuroQueryModel

# this part is just to get 2 example images, replace with whatever
encoder = NeuroQueryModel.from_data_dir(fetch_neuroquery_model())
auditory_img = encoder("auditory")["brain_map"]
language_img = encoder("language")["brain_map"]

auditory_mask = 1 * (image.get_data(auditory_img) > 3.0)
language_mask = 2 * (image.get_data(language_img) > 3.0)
combined_mask = image.new_img_like(auditory_img, auditory_mask + language_mask)

fig, (img_ax, cbar_ax) = plt.subplots(
    gridspec_kw={"width_ratios": [10.0, 0.1], "wspace": 0.0},
    figsize=(10, 2),

cmap = ListedColormap(["red", "green", "blue"])
plotting.plot_roi(combined_mask, cmap=cmap, axes=img_ax, display_mode="z")
norm = colors.Normalize(vmin=0, vmax=3)
cbar = colorbar.ColorbarBase(
    ticks=[0.5, 1.5, 2.5],
cbar_ax.set_yticklabels(["auditory", "language", "both"])

fig.savefig("/tmp/fig.pdf", bbox_inches="tight")
fig.savefig("/tmp/fig.png", bbox_inches="tight")


Re. symmetric cmaps, plot_stat_map will not, by design, produce plot with an asymmetric cmap (I think mostly to make sure maps that use 2 hues for negative and positive, eg blue and red, stay centered on 0). But you can used directly nilearn.plotting.plot_img which is less specialized and more flexible.

symmetric_cbar has no effect on the colormap but only on the colorbar, which can be truncated to only show the portion of the colormap from vmin to vmax, or show the full colormap from -absvmax to absvmax

Thank you so much! I have done as follow, but I’ll look into your suggestions as they seem to be cleaner.

img_exp1_binarised = image.math_img("np.where(img>=3.5518, 1, 0)", img=img_exp1)
img_exp2_binarised = image.math_img("np.where(img>=3.5518, 1, 0)", img=img_exp2)

# Choose colormap
from matplotlib.colors import ListedColormap
cmap1 =
cmap2 ="cividis_r")

# Get the colormap colors
my_cmap1 = cmap1(np.arange(cmap1.N))
my_cmap2 = cmap2(np.arange(cmap2.N))

# Set alpha
my_cmap1[:,-1] = np.linspace(0, 0.7, cmap1.N)
my_cmap2[:,-1] = np.linspace(0, 0.7, cmap2.N)

# Create new colormap
my_cmap1 = ListedColormap(my_cmap1)
my_cmap2 = ListedColormap(my_cmap2)

display = plotting.plot_img(img_exp1_binarised,
                       cut_coords=(36, -27, 5),
                       vmax = 1, vmin = 0.1,
                       draw_cross = False,
                       black_bg = False, annotate = True,
                       colorbar = False, cmap = my_cmap1

display.add_overlay(img_exp2_binarised, cmap = my_cmap2, vmax = 1, vmin = 0)

MRIcroGL would be an alternative to nilearn. The command “minimal” sets the minimum and maximum intensity for a layer. Setting the minimum and maximum to the save value creates a binary threshold: each voxel either survives or does not survive the threshold. Several default Python scripts are provided in the Scripting/templates menu item. Here is an example of the mosaic script that loads two overlays and applies a binary threshold to each:

import gl
#open background image
#open overlay: show positive regions
gl.minmax(1, 4, 4)
#open overlay: show negative regions
gl.minmax(2, -4, -4)
gl.colorname (2,"3blue")
gl.mosaic("A L+ H -0.2 -24 -16 16 40; 48 56 S X R 0");


Thanks! Can I also ask you if you know how to load a region of interest from the scripting panel, in order to show results only from a specific region?

Thank a lot

You can see a listing of all the inbuilt functions by choosing the Scripting/Templates/help menu item. These functions are designed for visualization, not image processing. Therefore, I think you would want to write a generic python script to mask voxels in a statistical template. Related to your question are the gl.atlasshow and gl.atlashide functions that only display specific regions of an atlas, in the example below I am only showing the right pre central and post central regions from the AAL atlas (in green) and showing the statistical overlay on top in red.

import gl
gl.atlasshow(1, (58, 2))
gl.minmax(2, 4, 4)
gl.mosaic("C L+ H 0.2 -24 -16 0 S X R 0")