Atlas-based seed connectivity maps¶
This example computes voxel-wise seed-based functional connectivity maps: register a
single-slice fUSI recording to an Allen-space template, bring an SeedBasedMaps. Each resulting map is
displayed with plot_stat_map, using the
resampled Allen reference volume as background.
We use an awake freely-running acquisition from subject CR022, session 20201007,
in the Nunez-Elizalde 2022 dataset,
and the
Fetch the recording and register to the Allen atlas¶
The recording is a single coronal slice imaged for approximately 4 minutes at 3.33 Hz. Registration works on a static anatomical image, so we use the temporal mean, converted to decibels for a more stable dynamic range.
from pathlib import Path
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
import xarray as xr
import confusius as cf
# Adapt background color to the current Matplotlib style.
bg_color = mpl.colors.to_hex(mpl.rcParams["figure.facecolor"])
xr.set_options(display_expand_data=False)
template = cf.datasets.fetch_template_pepe_mariani_2026().compute()
bids_root = cf.datasets.fetch_nunez_elizalde_2022(
subjects="CR022", sessions="20201007", tasks="spontaneous", acqs="slice02"
)
If you use this template in your work, please cite the following source: Pepe, C., Mariani, J.-C., Urosevic, M., Gini, S., Stuefer, A., Ricci, F., Galbusera, A., Iurilli, G., & Gozzi, A. (2026). Structural and dynamic embedding of the mouse functional connectome revealed by functional ultrasound imaging (fUSI). bioRxiv. https://doi.org/10.64898/2026.02.05.704055
If you use this dataset in your work, please cite the following source: Nunez-Elizalde, A. O., Krumin, M., Reddy, C. B., Montaldo, G., Urban, A., Harris, K. D., & Carandini, M. (2022). Neural correlates of blood flow measured by ultrasound. Neuron, 110(10), 1631–1640.e4. https://doi.org/10.1016/j.neuron.2022.02.012
data_path = (
Path(bids_root)
/ "sub-CR022"
/ "ses-20201007"
/ "fusi"
/ "sub-CR022_ses-20201007_task-spontaneous_acq-slice02_pwd.nii.gz"
)
# The recording's timepoints are not perfectly uniformly spaced so we resample to a
# uniform grid before any time-domain processing (filtering below requires it).
data = cf.timing.resample_to_uniform_time(cf.load(data_path))
moving = data.mean(dim="time").fusi.scale.db().compute()
We don't describe the registration process here to keep the notebook focused on seed-based connectivity, but the key steps are:
- Get an initial affine transform using napari's "Transform" tool.
- Use
register_volumeto refine the alignment. - Resample the Allen atlas into the recording's native space with
[
resample_like][confusius.atlas.Atlas.resample_like].
For the full walkthrough, see Register a recording to an Allen fUSI template.
Registration and atlas resampling
napari_affine = np.array(
[
[1.0, 0.0, 0.0, 5.594638656430411],
[0.0, 1.0, 0.0, -2.50293925701927],
[0.0, 0.0, 1.0, 5.6650243788545875],
[0.0, 0.0, 0.0, 1.0],
]
)
initialization = np.linalg.inv(napari_affine)
target_z = napari_affine[0, 3] + float(moving.z.values[0])
fixed = template.sel(z=slice(target_z - 1.0, target_z + 1.0))
registered, affine, diagnostics = cf.registration.register_volume(
moving=moving,
fixed=fixed,
transform_type="affine",
metric="correlation",
convergence_window_size=100,
number_of_iterations=500,
learning_rate=1,
initialization=initialization,
show_progress=False,
)
physical_to_sform = template.attrs["affines"]["physical_to_sform"]
subject_to_atlas = physical_to_sform @ np.linalg.inv(affine)
atlas = cf.datasets.fetch_brainglobe_atlas("allen_mouse_100um", check_latest=False)
atlas_native = atlas.atlas.resample_like(moving, subject_to_atlas)
Choose seed regions¶
We pick one seed from each of four functional systems, to contrast their
connectivity patterns: the primary somatosensory barrel field cortex ("SSp-bfd"), a
classic resting-state seed with a strong, well-documented bilateral
(interhemispheric) correlation signature; the retrosplenial cortex ("RSP"), a
default-mode-like hub expected to correlate broadly across much of cortex; the
hippocampus ("HIP"), which should instead correlate with a more localized,
hippocampal-formation-restricted network; and the ventral posteromedial thalamic
nucleus ("VPM"), a somatosensory relay nucleus expected to correlate with
"SSp-bfd" through the thalamocortical pathway. All seeds are taken from the right
hemisphere only, so that any left-hemisphere correlation in the resulting maps
reflects genuine interhemispheric connectivity rather than the seed leaking into its
own mask.
get_masks returns a stacked
(mask, z, y, x) integer DataArray—one layer per requested region—which
SeedBasedMaps accepts directly as
seed_masks.
Smooth and compute nuisance regressors¶
We lightly smooth the recording spatially with
smooth_volume (0.1 mm FWHM) to improve the
voxel-wise SNR before extracting confound signals and fitting the seed-based maps.
As in the correlation-matrix example, we regress out an
aCompCor component extracted from
white-matter voxels (the Allen ontology's "fiber tracts" division) together with a
low_cutoff high-pass cosine filter for slow drift. Both are passed to
SeedBasedMaps via clean_kwargs, which cleans the full voxel-wise recording
before extracting the seed signals, so seeds and voxels are preprocessed
consistently.
data = cf.spatial.smooth_volume(data, fwhm=0.1)
white_matter = atlas_native.atlas.get_masks("fiber tracts").isel(mask=0)
acompcor = cf.signal.compute_compcor_confounds(
data, noise_mask=white_matter, n_components=1, variance_threshold=0.95
)
Compute the seed-based correlation maps¶
SeedBasedMaps extracts each seed's average
signal, correlates it against every voxel in the recording, and returns one Pearson r
map per seed, stacked along a region dimension.
mapper = cf.connectivity.SeedBasedMaps(
seed_masks=seed_masks,
clean_kwargs={"low_cutoff": 0.01, "filter_method": "cosine", "confounds": acompcor},
)
mapper.fit(data)
mapper.maps_
- region: 4
- z: 1
- y: 125
- x: 80
- dask.array<chunksize=(4, 1, 125, 80), meta=np.ndarray>
Array Chunk Bytes 312.50 kiB 312.50 kiB Shape (4, 1, 125, 80) (4, 1, 125, 80) Dask graph 1 chunks in 52 graph layers Data type float64 numpy.ndarray - region(region)<U9'SSp-bfd_R' 'RSP_R' 'HIP_R' 'VPM_R'
array(['SSp-bfd_R', 'RSP_R', 'HIP_R', 'VPM_R'], dtype='<U9')
- z(z)float640.4
array([0.4])
- y(y)float642.996 3.044 3.092 ... 8.939 8.988
array([2.99584, 3.04416, 3.09248, 3.1408 , 3.18912, 3.23744, 3.28576, 3.33408, 3.3824 , 3.43072, 3.47904, 3.52736, 3.57568, 3.624 , 3.67232, 3.72064, 3.76896, 3.81728, 3.8656 , 3.91392, 3.96224, 4.01056, 4.05888, 4.1072 , 4.15552, 4.20384, 4.25216, 4.30048, 4.3488 , 4.39712, 4.44544, 4.49376, 4.54208, 4.5904 , 4.63872, 4.68704, 4.73536, 4.78368, 4.832 , 4.88032, 4.92864, 4.97696, 5.02528, 5.0736 , 5.12192, 5.17024, 5.21856, 5.26688, 5.3152 , 5.36352, 5.41184, 5.46016, 5.50848, 5.5568 , 5.60512, 5.65344, 5.70176, 5.75008, 5.7984 , 5.84672, 5.89504, 5.94336, 5.99168, 6.04 , 6.08832, 6.13664, 6.18496, 6.23328, 6.2816 , 6.32992, 6.37824, 6.42656, 6.47488, 6.5232 , 6.57152, 6.61984, 6.66816, 6.71648, 6.7648 , 6.81312, 6.86144, 6.90976, 6.95808, 7.0064 , 7.05472, 7.10304, 7.15136, 7.19968, 7.248 , 7.29632, 7.34464, 7.39296, 7.44128, 7.4896 , 7.53792, 7.58624, 7.63456, 7.68288, 7.7312 , 7.77952, 7.82784, 7.87616, 7.92448, 7.9728 , 8.02112, 8.06944, 8.11776, 8.16608, 8.2144 , 8.26272, 8.31104, 8.35936, 8.40768, 8.456 , 8.50432, 8.55264, 8.60096, 8.64928, 8.6976 , 8.74592, 8.79424, 8.84256, 8.89088, 8.9392 , 8.98752]) - x(x)float64-3.95 -3.85 -3.75 ... 3.85 3.95
array([-3.95, -3.85, -3.75, -3.65, -3.55, -3.45, -3.35, -3.25, -3.15, -3.05, -2.95, -2.85, -2.75, -2.65, -2.55, -2.45, -2.35, -2.25, -2.15, -2.05, -1.95, -1.85, -1.75, -1.65, -1.55, -1.45, -1.35, -1.25, -1.15, -1.05, -0.95, -0.85, -0.75, -0.65, -0.55, -0.45, -0.35, -0.25, -0.15, -0.05, 0.05, 0.15, 0.25, 0.35, 0.45, 0.55, 0.65, 0.75, 0.85, 0.95, 1.05, 1.15, 1.25, 1.35, 1.45, 1.55, 1.65, 1.75, 1.85, 1.95, 2.05, 2.15, 2.25, 2.35, 2.45, 2.55, 2.65, 2.75, 2.85, 2.95, 3.05, 3.15, 3.25, 3.35, 3.45, 3.55, 3.65, 3.75, 3.85, 3.95])
- long_name :
- Pearson r
- cmap :
- coolwarm
- norm :
- <matplotlib.colors.Normalize object at 0x7f640d02b8c0>
Plot the seed maps¶
Each seed's map is plotted with plot_stat_map
over the resampled Allen reference volume, with vmax=0.8 fixing the colormap to a
shared range so the four seeds are directly comparable. mapper.maps_ stacks all
four seed maps along a region dimension, so a single plot_stat_map call with
slice_mode="region" plots one panel per seed as long as the background is broadcast
to the same region dimension first. We outline each seed's own ROI with
VolumePlotter.add_contours, leaving
colors unset so each region is drawn in its canonical Allen color (read from the
atlas mask's attrs["cmap"]/attrs["norm"], the same convention used by
get_masks elsewhere).
# coolwarm's white midpoint reads as a washed-out hole on a dark background, so switch
# to berlin (Crameri's perceptually uniform diverging colormap, black midpoint) when the
# current Matplotlib style is dark.
is_dark_theme = sum(mpl.colors.to_rgb(bg_color)) / 3 < 0.5
cmap = "berlin" if is_dark_theme else None
# Broadcast the shared background and brain outline across a "region" dimension
# matching mapper.maps_, so plot_stat_map can slice both by region in one call.
bg_by_region = atlas_native.reference.expand_dims(region=mapper.maps_.region)
fig, axes = plt.subplots(2, 2, figsize=(8, 6), constrained_layout=True)
fig.patch.set_facecolor(bg_color)
plotter = cf.plotting.plot_stat_map(
mapper.maps_,
bg_volume=bg_by_region,
slice_mode="region",
cmap=cmap,
vmax=0.8,
threshold=0.2,
cbar_label="Pearson correlation",
show_axes=False,
figure=fig,
axes=axes,
bg_color=bg_color,
)
plotter.add_contours(seed_masks.rename(mask="region"), linewidths=1.5)
_ = fig.suptitle("Seed-based connectivity maps", fontsize=16)
Total running time: 16.8 s

