Assigning AAL3 and Brodmann Atlas Labels to Brain Surfaces
This notebook assigns AAL3 and Brodmann atlas labels to the Colin27 and ICBM152 brain surfaces, visualizes the labels, and summarizes their overlap with the Schaefer2018 parcels.
Overview
Neuroimaging atlases — parcellations that divide the cerebral cortex into anatomically or functionally defined regions — are a cornerstone of group-level fNIRS and DOT analysis. Atlases allow researchers to:
Report results in a standardised anatomical vocabulary that is comparable across studies and laboratories.
Aggregate channel or vertex signals into region-of-interest (ROI) time series, reducing the multiple-comparisons burden.
Cross-reference DOT activations with the large fMRI literature, where the same atlas labels are widely used.
The two MNI spaces: MNI152 and MNI305
Two MNI variants are in common use and it is important to keep them distinct:
Space |
Template |
Typical users |
|---|---|---|
MNI152 |
Average of 152 adult brains (ICBM152 template) |
FSL, recent SPM, most modern atlases |
MNI305 |
Average of 305 brains; the original MNI reference |
FreeSurfer, older SPM, some legacy atlases |
MNI152 and MNI305 differ by a small affine shift (a few millimetres in some regions) and are not interchangeable. Cedalion stores a pre-computed affine transform (cedalion.dot.utils.mni305_to_mni152) and applies it automatically when a NIfTI is declared as voxel_label_crs='mni305', so you do not need to handle the conversion manually. Both spaces are fully supported; you simply specify which one your NIfTI file uses.
What this notebook demonstrates
This notebook shows the general workflow for applying any user-supplied parcellation scheme — provided as a NIfTI label volume in either MNI152 or MNI305 space — to the Cedalion head models. The workflow is illustrated with two widely used atlases:
AAL3 (Automated Anatomical Labelling atlas, version 3) [RHL+20] — 170 macro-anatomical regions covering the entire cerebral cortex and subcortex.
Brodmann areas (Mai–Majtanik atlas) [MM17] — the classical cytoarchitectonic map, available as a volumetric MNI label file.
Both atlases are bundled with Cedalion and loaded via cedalion.data.get_atlas_files(). The same code applies unchanged to any other NIfTI atlas you supply.
For more detail, see also:
43a_head_models_overview.ipynb — introduction to
TwoSurfaceHeadModeland the Schaefer2018 parcellation bundled with the standard models43b_individualized_head_models.ipynb — building an individualized head model from a subject’s own MRI using FreeSurfer, which yields surface-native parcel labels with sharper boundaries than the volumetric approach shown here
[1]:
import json
import numpy as np
import pyvista as pv
from scipy.spatial import KDTree
import cedalion
import cedalion.dot
from cedalion.vis.anatomy import get_vertex_colors_from_coord, plot_brain_views_grid
pv.set_jupyter_backend("static")
Loading Colin27 and ICBM152 Head Models
We load both standard atlas head models. Each is stored in voxel space (crs='ijk'); assign_parcels_via_mni_coords works in MNI152 space internally so the coordinate system of the loaded head model does not need to match that of the atlas.
Both models carry pre-computed mni152_r/a/s vertex coordinates on the brain surface, which is what makes the atlas transfer possible. The inflated cortex surfaces are loaded for visualization: inflation removes sulci and gyri so that buried cortex becomes visible, making parcel boundaries much easier to inspect.
[2]:
colin_ijk = cedalion.dot.get_standard_headmodel("colin27")
colin_inflated = cedalion.dot.get_inflated_cortex_surface("colin27")
icbm_ijk = cedalion.dot.get_standard_headmodel("icbm152")
icbm_inflated = cedalion.dot.get_inflated_cortex_surface("icbm152")
Loading Atlases
Atlases distributed for use with standard MNI templates typically come in two files:
A NIfTI volume (
.niior.nii.gz) in which every voxel inside a labelled region carries a positive integer, and background voxels carry 0 (or another reserved value).A label mapping (
.json,.csv, or.txt) that translates those integers to human-readable region names.
cedalion.data.get_atlas_files(name) returns both paths for the bundled atlases. For a custom atlas you can pass any NIfTI path you have downloaded or created.
AAL3 — Automated Anatomical Labelling atlas (version 3)
AAL3 [RHL+20] divides the cerebral cortex and subcortical structures into 170 macro-anatomical regions based on sulcal and gyral landmarks visible in the MNI152 template. It is one of the most widely used atlases in the fMRI and fNIRS literature and provides a common vocabulary for reporting results. The NIfTI file bundled with Cedalion is defined in MNI152 space.
[3]:
aal3_voxel_label_niftii, aal3_labels_json = cedalion.data.get_atlas_files("aal3")
# dictionary to map numeric voxel labels in nifti to string labels
with aal3_labels_json.open("r") as fin:
aal3_num2label = json.load(fin)
aal3_num2label = {i["index"] : i["name"] for i in aal3_num2label["labels"]}
aal3_num2label
Downloading file 'atlas_aal3.zip' from 'https://doc.ibs.tu-berlin.de/cedalion/datasets/dev/atlas_aal3.zip' to '/home/runner/.cache/cedalion/dev'.
Unzipping contents of '/home/runner/.cache/cedalion/dev/atlas_aal3.zip' to '/home/runner/.cache/cedalion/dev/atlas_aal3.zip.unzip'
[3]:
{1: 'Precentral_L',
2: 'Precentral_R',
3: 'Frontal_Sup_2_L',
4: 'Frontal_Sup_2_R',
5: 'Frontal_Mid_2_L',
6: 'Frontal_Mid_2_R',
7: 'Frontal_Inf_Oper_L',
8: 'Frontal_Inf_Oper_R',
9: 'Frontal_Inf_Tri_L',
10: 'Frontal_Inf_Tri_R',
11: 'Frontal_Inf_Orb_2_L',
12: 'Frontal_Inf_Orb_2_R',
13: 'Rolandic_Oper_L',
14: 'Rolandic_Oper_R',
15: 'Supp_Motor_Area_L',
16: 'Supp_Motor_Area_R',
17: 'Olfactory_L',
18: 'Olfactory_R',
19: 'Frontal_Sup_Medial_L',
20: 'Frontal_Sup_Medial_R',
21: 'Frontal_Med_Orb_L',
22: 'Frontal_Med_Orb_R',
23: 'Rectus_L',
24: 'Rectus_R',
25: 'OFCmed_L',
26: 'OFCmed_R',
27: 'OFCant_L',
28: 'OFCant_R',
29: 'OFCpost_L',
30: 'OFCpost_R',
31: 'OFClat_L',
32: 'OFClat_R',
33: 'Insula_L',
34: 'Insula_R',
37: 'Cingulate_Mid_L',
38: 'Cingulate_Mid_R',
39: 'Cingulate_Post_L',
40: 'Cingulate_Post_R',
41: 'Hippocampus_L',
42: 'Hippocampus_R',
43: 'ParaHippocampal_L',
44: 'ParaHippocampal_R',
45: 'Amygdala_L',
46: 'Amygdala_R',
47: 'Calcarine_L',
48: 'Calcarine_R',
49: 'Cuneus_L',
50: 'Cuneus_R',
51: 'Lingual_L',
52: 'Lingual_R',
53: 'Occipital_Sup_L',
54: 'Occipital_Sup_R',
55: 'Occipital_Mid_L',
56: 'Occipital_Mid_R',
57: 'Occipital_Inf_L',
58: 'Occipital_Inf_R',
59: 'Fusiform_L',
60: 'Fusiform_R',
61: 'Postcentral_L',
62: 'Postcentral_R',
63: 'Parietal_Sup_L',
64: 'Parietal_Sup_R',
65: 'Parietal_Inf_L',
66: 'Parietal_Inf_R',
67: 'SupraMarginal_L',
68: 'SupraMarginal_R',
69: 'Angular_L',
70: 'Angular_R',
71: 'Precuneus_L',
72: 'Precuneus_R',
73: 'Paracentral_Lobule_L',
74: 'Paracentral_Lobule_R',
75: 'Caudate_L',
76: 'Caudate_R',
77: 'Putamen_L',
78: 'Putamen_R',
79: 'Pallidum_L',
80: 'Pallidum_R',
83: 'Heschl_L',
84: 'Heschl_R',
85: 'Temporal_Sup_L',
86: 'Temporal_Sup_R',
87: 'Temporal_Pole_Sup_L',
88: 'Temporal_Pole_Sup_R',
89: 'Temporal_Mid_L',
90: 'Temporal_Mid_R',
91: 'Temporal_Pole_Mid_L',
92: 'Temporal_Pole_Mid_R',
93: 'Temporal_Inf_L',
94: 'Temporal_Inf_R',
95: 'Cerebelum_Crus1_L',
96: 'Cerebelum_Crus1_R',
97: 'Cerebelum_Crus2_L',
98: 'Cerebelum_Crus2_R',
99: 'Cerebelum_3_L',
100: 'Cerebelum_3_R',
101: 'Cerebelum_4_5_L',
102: 'Cerebelum_4_5_R',
103: 'Cerebelum_6_L',
104: 'Cerebelum_6_R',
105: 'Cerebelum_7b_L',
106: 'Cerebelum_7b_R',
107: 'Cerebelum_8_L',
108: 'Cerebelum_8_R',
109: 'Cerebelum_9_L',
110: 'Cerebelum_9_R',
111: 'Cerebelum_10_L',
112: 'Cerebellum_10_R',
113: 'Vermis_1_2',
114: 'Vermis_3',
115: 'Vermis_4_5',
116: 'Vermis_6',
117: 'Vermis_7',
118: 'Vermis_8',
119: 'Vermis_9',
120: 'Vermis_10',
121: 'Thal_AV_L',
122: 'Thal_AV_R',
123: 'Thal_LP_L',
124: 'Thal_LP_R',
125: 'Thal_VA_L',
126: 'Thal_VA_R',
127: 'Thal_VL_L',
128: 'Thal_VL_R',
129: 'Thal_VPL_L',
130: 'Thal_VPL_R',
131: 'Thal_IL_L',
132: 'Thal_IL_R',
133: 'Thal_Re_L',
134: 'Thal_Re_R',
135: 'Thal_MDm_L',
136: 'Thal_MDm_R',
137: 'Thal_MDl_L',
138: 'Thal_MDl_R',
139: 'Thal_LGN_L',
140: 'Thal_LGN_R',
141: 'Thal_MGN_L',
142: 'Thal_MGN_R',
143: 'Thal_PuI_L',
144: 'Thal_PuI_R',
145: 'Thal_PuM_L',
146: 'Thal_PuM_R',
147: 'Thal_PuA_L',
148: 'Thal_PuA_R',
149: 'Thal_PuL_L',
150: 'Thal_PuL_R',
151: 'ACC_sub_L',
152: 'ACC_sub_R',
153: 'ACC_pre_L',
154: 'ACC_pre_R',
155: 'ACC_sup_L',
156: 'ACC_sup_R',
157: 'Vent_Str_L',
158: 'Vent_Str_R',
159: 'VTA_L',
160: 'VTA_R',
161: 'SN_pc_L',
162: 'SN_pc_R',
163: 'SN_pr_L',
164: 'SN_pr_R',
165: 'Red_N_L',
166: 'Red_N_R',
167: 'LC_L',
168: 'LC_R',
169: 'Raphe_D',
170: 'Raphe_M'}
Brodmann Areas — Mai–Majtanik Atlas
Brodmann areas are the classical cytoarchitectonic map of the human cortex, originally defined by Korbinian Brodmann in 1909 from histological sections and still widely used to communicate the location of activations in the neuroscience literature. The Mai–Majtanik atlas [MM17] provides these areas as a digitised volumetric label map registered to MNI152 space, making it directly compatible with the Cedalion head models. Areas such as BA44/45 (Broca’s area) or BA17 (primary visual cortex) are convenient reference landmarks when linking fNIRS results to the broader neuroimaging literature.
[4]:
brodmann_voxel_label_niftii, brodmann_labels_json = cedalion.data.get_atlas_files("brodmann")
# dictionary to map numeric voxel labels in nifti to string labels
with brodmann_labels_json.open("r") as fin:
brodmann_num2label = json.load(fin)
brodmann_num2label = {i["index"] : i["name"] for i in brodmann_num2label["labels"]}
brodmann_num2label
Downloading file 'atlas_brodmann.zip' from 'https://doc.ibs.tu-berlin.de/cedalion/datasets/dev/atlas_brodmann.zip' to '/home/runner/.cache/cedalion/dev'.
Unzipping contents of '/home/runner/.cache/cedalion/dev/atlas_brodmann.zip' to '/home/runner/.cache/cedalion/dev/atlas_brodmann.zip.unzip'
[4]:
{1: 'right_Ent',
2: 'right_BA20',
3: 'right_BA38',
4: 'right_BA21',
5: 'right_BA36',
6: 'right_BA11',
7: 'right_BA37',
8: 'right_BA25',
9: 'right_BA12',
10: 'right_BA19',
11: 'right_BA47',
12: 'right_BA22',
13: 'right_BA18',
14: 'right_BA10',
15: 'right_BA17',
16: 'right_BA32',
17: 'right_BA24',
18: 'right_BA46',
19: 'right_BA45',
20: 'right_BA33',
21: 'right_BA44',
22: 'right_BA6',
23: 'right_BA23',
24: 'right_BA42',
25: 'right_BA43',
26: 'right_BA30',
27: 'right_BA41',
28: 'right_BA29',
29: 'right_BA26',
30: 'right_BA31',
31: 'right_BA4',
32: 'right_BA1',
33: 'right_BA9',
34: 'right_BA39',
35: 'right_BA2',
36: 'right_BA3',
37: 'right_BA40',
38: 'right_BA7',
39: 'right_BA8',
40: 'right_BA5',
41: 'right_BA52',
42: 'right_BA35',
43: 'right_BA34',
101: 'left_Ent',
102: 'left_BA20',
103: 'left_BA38',
104: 'left_BA21',
105: 'left_BA36',
106: 'left_BA11',
107: 'left_BA37',
108: 'left_BA25',
109: 'left_BA12',
110: 'left_BA19',
111: 'left_BA47',
112: 'left_BA22',
113: 'left_BA18',
114: 'left_BA10',
115: 'left_BA17',
116: 'left_BA32',
117: 'left_BA24',
118: 'left_BA46',
119: 'left_BA45',
120: 'left_BA33',
121: 'left_BA44',
122: 'left_BA6',
123: 'left_BA23',
124: 'left_BA42',
125: 'left_BA43',
126: 'left_BA30',
127: 'left_BA41',
128: 'left_BA29',
129: 'left_BA26',
130: 'left_BA31',
131: 'left_BA4',
132: 'left_BA1',
133: 'left_BA9',
134: 'left_BA39',
135: 'left_BA2',
136: 'left_BA3',
137: 'left_BA40',
138: 'left_BA7',
139: 'left_BA8',
140: 'left_BA5',
141: 'left_BA52',
142: 'left_BA35',
143: 'left_BA34'}
Brain Vertex Coordinates Before Atlas Assignment
The brain.vertices xarray DataArray already carries several vertex coordinates set when the head model was built from FreeSurfer outputs:
Coordinate |
Meaning |
|---|---|
|
Schaefer2018 parcel label [SKG+18] |
|
Corresponding vertex index in the FreeSurfer |
|
MNI152 RAS coordinates of the vertex in mm |
Calling assign_parcels_via_mni_coords will add a new named coordinate to this DataArray without removing or modifying any existing one. Multiple atlas labels can therefore coexist on the same vertex, which is what we exploit below.
[5]:
colin_ijk.brain.vertices
[5]:
<xarray.DataArray (label: 25000, ijk: 3)> Size: 600kB <Quantity([[ 82.522325 19.841515 68.313221] [ 83.516588 20.319351 65.886337] [ 78.524571 20.543388 63.648142] ... [127.025612 152.660339 99.546274] [ 96.280465 105.252083 86.734898] [127.619801 34.463676 60.37505 ]], 'dimensionless')> Coordinates: * label (label) int64 200kB 0 1 2 3 4 ... 24996 24997 24998 24999 * fsaverage_vertex (label) int64 200kB 42 61 75 89 ... 333018 333020 333066 * parcel (label) object 200kB 'VisCent_ExStr_8_LH' ... 'VisCent_... * mni152_r (label) float64 200kB -6.792 -5.846 -10.87 ... 6.633 37.95 * mni152_a (label) float64 200kB -104.8 -104.3 ... -19.16 -89.49 * mni152_s (label) float64 200kB -1.408 -3.845 ... 15.99 -10.04 Dimensions without coordinates: ijk
Assigning Atlas Labels to Brain Vertices
TwoSurfaceHeadModel.assign_parcels_via_mni_coords transfers labels from a volumetric NIfTI atlas to the brain surface by exploiting the MNI152 coordinates shared by both. The algorithm works as follows:
Coordinate alignment: The NIfTI affine transform is used to compute the MNI coordinate of every voxel centre. If the atlas is in MNI305 space (
voxel_label_crs='mni305'), the pre-computed affinecedalion.dot.utils.mni305_to_mni152is applied first to bring voxel coordinates into the same MNI152 frame as the head model vertices.Nearest-labelled-voxel search: A KD-tree is built from the voxel centres. For each brain surface vertex, all voxels within a ball of radius
mni_epsmm in MNI152 space are retrieved. Background voxels (label 0 or whichever integer maps tobackground_label) are excluded, and the closest labelled voxel is selected.Label assignment: The integer label of the winning voxel is translated to a string via
label_mappingand stored as a new vertex coordinate. If no labelled voxel falls withinmni_epsmm, the vertex receivesbackground_label.
Key parameters:
Parameter |
Effect |
|---|---|
|
Name of the new vertex coordinate (e.g. |
|
|
|
Path to the NIfTI atlas file |
|
MNI variant of the NIfTI: |
|
Search radius in mm (default |
Each call returns a new head model object; the original is not modified (immutable-style API). We chain two calls to assign both atlases in sequence.
Assigning AAL3 and Brodmann labels to the Colin27 head:
[6]:
# Colin27
colin_ijk_labeled = colin_ijk.assign_parcels_via_mni_coords(
coordinate_label="parcel_aal3",
label_mapping=aal3_num2label,
voxel_label_niftii=aal3_voxel_label_niftii,
voxel_label_crs="mni152",
mni_eps=5
)
colin_ijk_labeled = colin_ijk_labeled.assign_parcels_via_mni_coords(
coordinate_label="parcel_brodmann",
label_mapping=brodmann_num2label,
voxel_label_niftii=brodmann_voxel_label_niftii,
voxel_label_crs="mni152",
mni_eps=5
)
colin_ijk_labeled.brain.vertices
[6]:
<xarray.DataArray (label: 25000, ijk: 3)> Size: 600kB <Quantity([[ 82.522325 19.841515 68.313221] [ 83.516588 20.319351 65.886337] [ 78.524571 20.543388 63.648142] ... [127.025612 152.660339 99.546274] [ 96.280465 105.252083 86.734898] [127.619801 34.463676 60.37505 ]], 'dimensionless')> Coordinates: * label (label) int64 200kB 0 1 2 3 4 ... 24996 24997 24998 24999 * fsaverage_vertex (label) int64 200kB 42 61 75 89 ... 333018 333020 333066 * parcel (label) object 200kB 'VisCent_ExStr_8_LH' ... 'VisCent_... * mni152_r (label) float64 200kB -6.792 -5.846 -10.87 ... 6.633 37.95 * mni152_a (label) float64 200kB -104.8 -104.3 ... -19.16 -89.49 * mni152_s (label) float64 200kB -1.408 -3.845 ... 15.99 -10.04 * parcel_aal3 (label) <U20 2MB 'Calcarine_L' ... 'Occipital_Inf_R' * parcel_brodmann (label) <U10 1MB 'left_BA17' 'left_BA17' ... 'right_BA18' Dimensions without coordinates: ijk
Because ICBM152 and Colin27 share the same MNI152 coordinate frame, the identical NIfTI atlas files and label dictionaries work unchanged for both head models. This is the practical benefit of the shared coordinate system: you write the atlas assignment code once and it applies to any head model that has MNI152 vertex coordinates.
Assigning AAL3 and Brodmann labels to the ICBM152 head:
[7]:
# ICBM-152
icbm_ijk_labeled = icbm_ijk.assign_parcels_via_mni_coords(
coordinate_label="parcel_aal3",
label_mapping=aal3_num2label,
voxel_label_niftii=aal3_voxel_label_niftii,
voxel_label_crs="mni152",
mni_eps=5
)
icbm_ijk_labeled = icbm_ijk_labeled.assign_parcels_via_mni_coords(
coordinate_label="parcel_brodmann",
label_mapping=brodmann_num2label,
voxel_label_niftii=brodmann_voxel_label_niftii,
voxel_label_crs="mni152",
mni_eps=5
)
icbm_ijk_labeled.brain.vertices
[7]:
<xarray.DataArray (label: 25000, ijk: 3)> Size: 600kB <Quantity([[ 81.244216 26.627602 150.621031] [ 81.577181 27.302513 157.143576] [ 77.826448 27.459724 154.566914] ... [118.580717 84.619659 208.0373 ] [143.100407 63.906384 138.08789 ] [133.577629 151.8062 150.919106]], 'dimensionless')> Coordinates: * label (label) int64 200kB 0 1 2 3 4 ... 24996 24997 24998 24999 * fsaverage_vertex (label) int64 200kB 29 66 101 141 ... 320360 320363 320364 * parcel (label) object 200kB 'VisCent_Striate_2_LH' ... 'SalVen... * mni152_r (label) float64 200kB -14.76 -14.42 -18.17 ... 47.1 37.58 * mni152_a (label) float64 200kB -105.4 -104.7 ... -68.09 19.81 * mni152_s (label) float64 200kB 2.621 9.144 6.567 ... -9.912 2.919 * parcel_aal3 (label) <U20 2MB 'Calcarine_L' ... 'Insula_R' * parcel_brodmann (label) <U10 1MB 'left_BA17' 'left_BA18' ... 'Background' Dimensions without coordinates: ijk
Plotting Parcellation Schemes
Cedalion’s surface plotting functions accept a list of per-vertex colors (RGB tuples or matplotlib color specs), one entry per vertex in vertex order. The helper cedalion.vis.anatomy.get_vertex_colors_from_coord builds this list from a named vertex coordinate and a color_mapping that translates string labels to colors.
Three color_mapping modes are supported:
|
Behaviour |
|---|---|
|
Each label is looked up; vertices not in the dict get |
|
A random but deterministic color is generated for every unique label |
A single color string (e.g. |
Every vertex whose label is in |
We first demonstrate with the Schaefer2018 parcellation that is bundled with the head model and has an official color map:
[8]:
# example: Schaefer parcel colors
schaefer_color_dict = cedalion.data.get_colin27_headmodel_files().load_parcel_colors()
display(schaefer_color_dict)
{'VisCent_Striate_1_LH': [120, 18, 135],
'VisCent_Striate_2_LH': [120, 18, 136],
'VisCent_Striate_3_LH': [120, 18, 137],
'VisCent_ExStr_1_LH': [120, 18, 128],
'VisCent_ExStr_2_LH': [120, 18, 129],
'VisCent_ExStr_3_LH': [120, 18, 130],
'VisCent_ExStr_4_LH': [120, 18, 131],
'VisCent_ExStr_5_LH': [120, 18, 132],
'VisCent_ExStr_6_LH': [120, 18, 133],
'VisCent_ExStr_7_LH': [120, 18, 134],
'VisCent_ExStr_8_LH': [120, 18, 138],
'VisCent_ExStr_9_LH': [120, 18, 139],
'VisCent_ExStr_10_LH': [120, 18, 140],
'VisCent_ExStr_11_LH': [120, 18, 141],
'VisCent_ExStr_12_LH': [120, 18, 142],
'VisCent_ExStr_13_LH': [120, 19, 135],
'VisCent_ExStr_14_LH': [120, 19, 136],
'VisCent_ExStr_15_LH': [120, 19, 137],
'VisCent_ExStr_16_LH': [120, 19, 138],
'VisCent_ExStr_17_LH': [120, 19, 139],
'VisPeri_StriCal_1_LH': [255, 0, 1],
'VisPeri_StriCal_2_LH': [255, 0, 2],
'VisPeri_StriCal_3_LH': [255, 0, 3],
'VisPeri_StriCal_4_LH': [255, 0, 4],
'VisPeri_StriCal_5_LH': [255, 0, 5],
'VisPeri_ExStrInf_1_LH': [255, 0, 0],
'VisPeri_ExStrInf_2_LH': [255, 0, 6],
'VisPeri_ExStrInf_3_LH': [255, 0, 7],
'VisPeri_ExStrInf_4_LH': [255, 0, 8],
'VisPeri_ExStrInf_5_LH': [255, 1, 1],
'VisPeri_ExStrSup_1_LH': [255, 1, 2],
'VisPeri_ExStrSup_2_LH': [255, 1, 3],
'VisPeri_ExStrSup_3_LH': [255, 1, 4],
'VisPeri_ExStrSup_4_LH': [255, 1, 5],
'VisPeri_ExStrSup_5_LH': [255, 1, 6],
'VisPeri_ExStrSup_6_LH': [255, 1, 7],
'VisPeri_ExStrSup_7_LH': [255, 2, 0],
'SomMotA_1_LH': [70, 129, 175],
'SomMotA_2_LH': [70, 129, 176],
'SomMotA_3_LH': [70, 129, 177],
'SomMotA_4_LH': [70, 129, 178],
'SomMotA_5_LH': [70, 129, 179],
'SomMotA_6_LH': [70, 129, 180],
'SomMotA_7_LH': [70, 130, 173],
'SomMotA_8_LH': [70, 130, 174],
'SomMotA_9_LH': [70, 130, 175],
'SomMotA_10_LH': [70, 130, 176],
'SomMotA_11_LH': [70, 130, 177],
'SomMotA_12_LH': [70, 130, 178],
'SomMotA_13_LH': [70, 130, 179],
'SomMotA_14_LH': [70, 130, 181],
'SomMotA_15_LH': [70, 130, 182],
'SomMotA_16_LH': [70, 130, 183],
'SomMotA_17_LH': [70, 130, 184],
'SomMotA_18_LH': [70, 130, 185],
'SomMotA_19_LH': [70, 130, 186],
'SomMotA_20_LH': [70, 130, 187],
'SomMotA_21_LH': [70, 131, 180],
'SomMotA_22_LH': [70, 131, 181],
'SomMotA_23_LH': [70, 131, 182],
'SomMotA_24_LH': [70, 131, 183],
'SomMotA_25_LH': [70, 131, 184],
'SomMotA_26_LH': [70, 131, 185],
'SomMotA_27_LH': [70, 131, 186],
'SomMotA_28_LH': [70, 131, 187],
'SomMotA_29_LH': [70, 132, 180],
'SomMotB_Cent_1_LH': [42, 204, 162],
'SomMotB_Cent_2_LH': [42, 204, 163],
'SomMotB_Cent_3_LH': [42, 204, 165],
'SomMotB_Cent_4_LH': [42, 204, 166],
'SomMotB_Cent_5_LH': [42, 204, 167],
'SomMotB_Cent_6_LH': [42, 204, 168],
'SomMotB_Cent_7_LH': [42, 204, 169],
'SomMotB_Cent_8_LH': [42, 204, 170],
'SomMotB_S2_1_LH': [42, 204, 164],
'SomMotB_S2_2_LH': [42, 204, 171],
'SomMotB_S2_3_LH': [42, 204, 172],
'SomMotB_S2_4_LH': [42, 205, 165],
'SomMotB_S2_5_LH': [42, 205, 166],
'SomMotB_S2_6_LH': [42, 205, 167],
'SomMotB_S2_7_LH': [42, 205, 168],
'SomMotB_S2_8_LH': [42, 205, 169],
'SomMotB_Ins_1_LH': [42, 205, 170],
'SomMotB_Aud_1_LH': [43, 204, 162],
'SomMotB_Aud_2_LH': [43, 204, 163],
'SomMotB_Aud_3_LH': [43, 204, 165],
'SomMotB_Aud_4_LH': [43, 204, 166],
'SomMotB_Aud_5_LH': [43, 204, 167],
'SomMotB_Aud_6_LH': [43, 204, 168],
'SomMotB_Aud_7_LH': [43, 204, 169],
'DorsAttnA_TempOcc_1_LH': [74, 155, 59],
'DorsAttnA_TempOcc_2_LH': [74, 155, 61],
'DorsAttnA_TempOcc_3_LH': [74, 155, 62],
'DorsAttnA_TempOcc_4_LH': [74, 155, 63],
'DorsAttnA_TempOcc_5_LH': [74, 155, 64],
'DorsAttnA_TempOcc_6_LH': [74, 155, 65],
'DorsAttnA_ParOcc_1_LH': [74, 155, 66],
'DorsAttnA_ParOcc_2_LH': [74, 155, 67],
'DorsAttnA_ParOcc_3_LH': [74, 155, 68],
'DorsAttnA_ParOcc_4_LH': [74, 156, 61],
'DorsAttnA_SPL_1_LH': [74, 156, 56],
'DorsAttnA_SPL_2_LH': [74, 156, 57],
'DorsAttnA_SPL_3_LH': [74, 156, 58],
'DorsAttnA_SPL_4_LH': [74, 156, 59],
'DorsAttnA_SPL_5_LH': [74, 156, 62],
'DorsAttnA_SPL_6_LH': [74, 156, 63],
'DorsAttnA_SPL_7_LH': [74, 156, 64],
'DorsAttnA_SPL_8_LH': [74, 156, 65],
'DorsAttnA_SPL_9_LH': [74, 156, 66],
'DorsAttnA_SPL_10_LH': [74, 156, 67],
'DorsAttnA_SPL_11_LH': [74, 157, 60],
'DorsAttnB_PostC_1_LH': [0, 118, 12],
'DorsAttnB_PostC_2_LH': [0, 118, 13],
'DorsAttnB_PostC_3_LH': [0, 118, 14],
'DorsAttnB_PostC_4_LH': [0, 118, 16],
'DorsAttnB_PostC_5_LH': [0, 118, 17],
'DorsAttnB_PostC_6_LH': [0, 118, 18],
'DorsAttnB_PostC_7_LH': [0, 118, 19],
'DorsAttnB_PostC_8_LH': [0, 118, 20],
'DorsAttnB_PostC_9_LH': [0, 118, 21],
'DorsAttnB_PostC_10_LH': [0, 118, 22],
'DorsAttnB_FEF_1_LH': [0, 119, 15],
'DorsAttnB_FEF_2_LH': [0, 119, 16],
'DorsAttnB_FEF_3_LH': [0, 119, 17],
'DorsAttnB_FEF_4_LH': [0, 119, 18],
'DorsAttnB_PrCv_1_LH': [0, 119, 19],
'SalVentAttnA_ParOper_1_LH': [196, 58, 249],
'SalVentAttnA_ParOper_2_LH': [196, 58, 251],
'SalVentAttnA_ParOper_3_LH': [196, 58, 252],
'SalVentAttnA_ParOper_4_LH': [196, 58, 253],
'SalVentAttnA_ParOper_5_LH': [196, 58, 254],
'SalVentAttnA_FrOper_1_LH': [196, 58, 255],
'SalVentAttnA_FrOper_2_LH': [193, 51, 250],
'SalVentAttnA_FrOper_3_LH': [193, 51, 251],
'SalVentAttnA_FrOper_4_LH': [193, 52, 244],
'SalVentAttnA_Ins_1_LH': [196, 59, 249],
'SalVentAttnA_Ins_2_LH': [196, 59, 251],
'SalVentAttnA_Ins_3_LH': [196, 59, 252],
'SalVentAttnA_Ins_4_LH': [196, 59, 253],
'SalVentAttnA_Ins_5_LH': [196, 59, 254],
'SalVentAttnA_Ins_6_LH': [196, 59, 255],
'SalVentAttnA_ParMed_1_LH': [196, 59, 250],
'SalVentAttnA_ParMed_2_LH': [193, 52, 249],
'SalVentAttnA_ParMed_3_LH': [193, 52, 250],
'SalVentAttnA_ParMed_4_LH': [193, 52, 251],
'SalVentAttnA_ParMed_5_LH': [193, 53, 244],
'SalVentAttnA_ParMed_6_LH': [193, 53, 245],
'SalVentAttnA_FrMed_1_LH': [197, 58, 249],
'SalVentAttnA_FrMed_2_LH': [197, 58, 251],
'SalVentAttnA_FrMed_3_LH': [197, 58, 252],
'SalVentAttnA_FrMed_4_LH': [197, 58, 253],
'SalVentAttnA_FrMed_5_LH': [197, 58, 254],
'SalVentAttnB_PFCd_1_LH': [255, 152, 215],
'SalVentAttnB_PFCl_1_LH': [255, 153, 214],
'SalVentAttnB_PFCl_2_LH': [255, 153, 215],
'SalVentAttnB_PFCl_3_LH': [255, 153, 216],
'SalVentAttnB_PFCl_4_LH': [255, 153, 217],
'SalVentAttnB_Ins_1_LH': [255, 153, 218],
'SalVentAttnB_Ins_2_LH': [255, 153, 219],
'SalVentAttnB_Ins_3_LH': [255, 153, 220],
'SalVentAttnB_Ins_4_LH': [255, 153, 221],
'SalVentAttnB_PFCmp_1_LH': [255, 151, 214],
'SalVentAttnB_PFCmp_2_LH': [255, 151, 215],
'SalVentAttnB_PFCmp_3_LH': [255, 151, 216],
'LimbicB_OFC_1_LH': [122, 135, 47],
'LimbicB_OFC_2_LH': [122, 135, 48],
'LimbicB_OFC_3_LH': [122, 135, 49],
'LimbicB_OFC_4_LH': [122, 135, 51],
'LimbicB_OFC_5_LH': [122, 135, 52],
'LimbicB_OFC_6_LH': [122, 135, 53],
'LimbicB_OFC_7_LH': [122, 135, 54],
'LimbicB_OFC_8_LH': [122, 135, 55],
'LimbicB_OFC_9_LH': [122, 135, 56],
'LimbicB_OFC_10_LH': [122, 135, 57],
'LimbicA_TempPole_1_LH': [220, 248, 160],
'LimbicA_TempPole_2_LH': [220, 248, 161],
'LimbicA_TempPole_3_LH': [220, 248, 162],
'LimbicA_TempPole_4_LH': [220, 248, 163],
'LimbicA_TempPole_5_LH': [220, 248, 165],
'LimbicA_TempPole_6_LH': [220, 248, 166],
'LimbicA_TempPole_7_LH': [220, 248, 167],
'LimbicA_TempPole_8_LH': [220, 248, 168],
'LimbicA_TempPole_9_LH': [220, 248, 169],
'LimbicA_TempPole_10_LH': [220, 248, 170],
'LimbicA_TempPole_11_LH': [220, 248, 171],
'LimbicA_TempPole_12_LH': [220, 249, 164],
'ContA_Temp_1_LH': [230, 148, 35],
'ContA_Temp_2_LH': [230, 148, 36],
'ContA_IPS_1_LH': [230, 148, 34],
'ContA_IPS_2_LH': [230, 148, 37],
'ContA_IPS_3_LH': [230, 148, 38],
'ContA_IPS_4_LH': [230, 148, 39],
'ContA_IPS_5_LH': [230, 148, 40],
'ContA_IPS_6_LH': [230, 148, 41],
'ContA_PFCd_1_LH': [230, 149, 35],
'ContA_PFCd_2_LH': [230, 149, 36],
'ContA_PFCl_1_LH': [230, 149, 34],
'ContA_PFCl_2_LH': [230, 149, 37],
'ContA_PFCl_3_LH': [230, 149, 38],
'ContA_PFCl_4_LH': [230, 149, 39],
'ContA_PFCl_5_LH': [230, 149, 40],
'ContA_PFCl_6_LH': [230, 149, 41],
'ContA_PFClv_1_LH': [231, 148, 35],
'ContA_PFClv_2_LH': [231, 148, 36],
'ContA_Cingm_1_LH': [231, 148, 37],
'ContB_Temp_1_LH': [135, 50, 75],
'ContB_Temp_2_LH': [135, 50, 76],
'ContB_IPL_1_LH': [135, 50, 74],
'ContB_IPL_2_LH': [135, 50, 77],
'ContB_IPL_3_LH': [135, 50, 78],
'ContB_IPL_4_LH': [135, 50, 79],
'ContB_IPL_5_LH': [135, 50, 80],
'ContB_PFCd_1_LH': [135, 51, 75],
'ContB_PFCl_1_LH': [135, 51, 76],
'ContB_PFCl_2_LH': [135, 51, 77],
'ContB_PFClv_1_LH': [136, 50, 75],
'ContB_PFClv_2_LH': [136, 50, 76],
'ContB_PFClv_3_LH': [136, 50, 77],
'ContB_PFCmp_1_LH': [136, 50, 78],
'ContC_pCun_1_LH': [119, 140, 175],
'ContC_pCun_2_LH': [119, 140, 177],
'ContC_pCun_3_LH': [119, 140, 178],
'ContC_pCun_4_LH': [119, 140, 179],
'ContC_pCun_5_LH': [119, 140, 180],
'ContC_pCun_6_LH': [119, 140, 181],
'ContC_Cingp_1_LH': [119, 140, 182],
'ContC_Cingp_2_LH': [119, 140, 183],
'DefaultA_IPL_1_LH': [255, 255, 1],
'DefaultA_IPL_2_LH': [255, 255, 2],
'DefaultA_IPL_3_LH': [255, 255, 3],
'DefaultA_IPL_4_LH': [255, 255, 4],
'DefaultA_PFCd_1_LH': [255, 255, 5],
'DefaultA_PFCd_2_LH': [255, 255, 6],
'DefaultA_PFCd_3_LH': [255, 255, 7],
'DefaultA_pCunPCC_1_LH': [255, 254, 1],
'DefaultA_pCunPCC_2_LH': [255, 254, 2],
'DefaultA_pCunPCC_3_LH': [255, 254, 3],
'DefaultA_pCunPCC_4_LH': [255, 254, 4],
'DefaultA_pCunPCC_5_LH': [255, 254, 5],
'DefaultA_pCunPCC_6_LH': [255, 254, 6],
'DefaultA_pCunPCC_7_LH': [255, 254, 7],
'DefaultA_pCunPCC_8_LH': [255, 255, 0],
'DefaultA_pCunPCC_9_LH': [252, 249, 0],
'DefaultA_pCunPCC_10_LH': [252, 250, 0],
'DefaultA_pCunPCC_11_LH': [252, 251, 0],
'DefaultA_pCunPCC_12_LH': [252, 252, 0],
'DefaultA_PFCm_1_LH': [254, 255, 1],
'DefaultA_PFCm_2_LH': [254, 255, 2],
'DefaultA_PFCm_3_LH': [254, 255, 3],
'DefaultA_PFCm_4_LH': [254, 255, 4],
'DefaultA_PFCm_5_LH': [254, 255, 5],
'DefaultA_PFCm_6_LH': [254, 255, 6],
'DefaultA_PFCm_7_LH': [254, 255, 7],
'DefaultA_PFCm_8_LH': [251, 249, 0],
'DefaultB_Temp_1_LH': [205, 62, 76],
'DefaultB_Temp_2_LH': [205, 62, 77],
'DefaultB_Temp_3_LH': [205, 62, 79],
'DefaultB_Temp_4_LH': [205, 62, 80],
'DefaultB_Temp_5_LH': [205, 62, 81],
'DefaultB_Temp_6_LH': [205, 62, 82],
'DefaultB_Temp_7_LH': [205, 62, 83],
'DefaultB_IPL_1_LH': [205, 62, 84],
'DefaultB_IPL_2_LH': [205, 62, 85],
'DefaultB_IPL_3_LH': [205, 62, 86],
'DefaultB_IPL_4_LH': [205, 63, 79],
'DefaultB_PFCd_1_LH': [205, 63, 76],
'DefaultB_PFCd_2_LH': [205, 63, 77],
'DefaultB_PFCd_3_LH': [205, 63, 80],
'DefaultB_PFCd_4_LH': [205, 63, 81],
'DefaultB_PFCd_5_LH': [205, 63, 82],
'DefaultB_PFCd_6_LH': [205, 63, 83],
'DefaultB_PFCd_7_LH': [205, 63, 84],
'DefaultB_PFCl_1_LH': [205, 63, 85],
'DefaultB_PFCl_2_LH': [205, 63, 86],
'DefaultB_PFCv_1_LH': [206, 62, 76],
'DefaultB_PFCv_2_LH': [206, 62, 77],
'DefaultB_PFCv_3_LH': [206, 62, 79],
'DefaultB_PFCv_4_LH': [206, 62, 80],
'DefaultB_PFCv_5_LH': [206, 62, 81],
'DefaultB_PFCv_6_LH': [206, 62, 82],
'DefaultB_PFCv_7_LH': [206, 62, 83],
'DefaultC_IPL_1_LH': [0, 0, 131],
'DefaultC_IPL_2_LH': [0, 0, 132],
'DefaultC_Rsp_1_LH': [0, 0, 133],
'DefaultC_Rsp_2_LH': [0, 0, 134],
'DefaultC_Rsp_3_LH': [0, 0, 135],
'DefaultC_Rsp_4_LH': [0, 0, 136],
'DefaultC_PHC_1_LH': [0, 1, 129],
'DefaultC_PHC_2_LH': [0, 1, 131],
'DefaultC_PHC_3_LH': [0, 1, 132],
'DefaultC_PHC_4_LH': [0, 1, 133],
'DefaultC_PHC_5_LH': [0, 1, 134],
'TempPar_1_LH': [12, 48, 253],
'TempPar_2_LH': [12, 48, 254],
'TempPar_3_LH': [9, 41, 249],
'TempPar_4_LH': [9, 41, 250],
'TempPar_5_LH': [9, 41, 251],
'TempPar_6_LH': [9, 41, 252],
'TempPar_7_LH': [9, 41, 253],
'TempPar_8_LH': [9, 41, 254],
'VisCent_Striate_1_RH': [120, 19, 135],
'VisCent_Striate_2_RH': [120, 19, 136],
'VisCent_Striate_3_RH': [120, 19, 137],
'VisCent_ExStr_1_RH': [120, 19, 128],
'VisCent_ExStr_2_RH': [120, 19, 129],
'VisCent_ExStr_3_RH': [120, 19, 130],
'VisCent_ExStr_4_RH': [120, 19, 131],
'VisCent_ExStr_5_RH': [120, 19, 132],
'VisCent_ExStr_6_RH': [120, 19, 133],
'VisCent_ExStr_7_RH': [120, 19, 134],
'VisCent_ExStr_8_RH': [120, 19, 138],
'VisCent_ExStr_9_RH': [120, 19, 139],
'VisCent_ExStr_10_RH': [120, 19, 140],
'VisCent_ExStr_11_RH': [120, 19, 141],
'VisCent_ExStr_12_RH': [120, 19, 142],
'VisCent_ExStr_13_RH': [120, 20, 135],
'VisCent_ExStr_14_RH': [120, 20, 136],
'VisCent_ExStr_15_RH': [120, 20, 137],
'VisCent_ExStr_16_RH': [120, 20, 138],
'VisCent_ExStr_17_RH': [120, 20, 139],
'VisCent_ExStr_18_RH': [120, 20, 140],
'VisPeri_StriCal_1_RH': [255, 1, 2],
'VisPeri_StriCal_2_RH': [255, 1, 3],
'VisPeri_StriCal_3_RH': [255, 1, 4],
'VisPeri_StriCal_4_RH': [255, 1, 5],
'VisPeri_ExStrInf_1_RH': [254, 0, 1],
'VisPeri_ExStrInf_2_RH': [254, 0, 2],
'VisPeri_ExStrInf_3_RH': [254, 0, 3],
'VisPeri_ExStrInf_4_RH': [254, 0, 4],
'VisPeri_ExStrInf_5_RH': [254, 0, 5],
'VisPeri_ExStrSup_1_RH': [254, 0, 0],
'VisPeri_ExStrSup_2_RH': [254, 0, 6],
'VisPeri_ExStrSup_3_RH': [254, 0, 7],
'VisPeri_ExStrSup_4_RH': [254, 0, 8],
'VisPeri_ExStrSup_5_RH': [254, 1, 1],
'VisPeri_ExStrSup_6_RH': [254, 1, 2],
'SomMotA_1_RH': [70, 130, 177],
'SomMotA_2_RH': [70, 130, 178],
'SomMotA_3_RH': [70, 130, 179],
'SomMotA_4_RH': [70, 130, 180],
'SomMotA_5_RH': [70, 130, 181],
'SomMotA_6_RH': [70, 131, 174],
'SomMotA_7_RH': [70, 131, 175],
'SomMotA_8_RH': [70, 131, 176],
'SomMotA_9_RH': [70, 131, 177],
'SomMotA_10_RH': [70, 131, 178],
'SomMotA_11_RH': [70, 131, 179],
'SomMotA_12_RH': [70, 131, 180],
'SomMotA_13_RH': [70, 131, 182],
'SomMotA_14_RH': [70, 131, 183],
'SomMotA_15_RH': [70, 131, 184],
'SomMotA_16_RH': [70, 131, 185],
'SomMotA_17_RH': [70, 131, 186],
'SomMotA_18_RH': [70, 131, 187],
'SomMotA_19_RH': [70, 131, 188],
'SomMotA_20_RH': [70, 132, 181],
'SomMotA_21_RH': [70, 132, 182],
'SomMotA_22_RH': [70, 132, 183],
'SomMotA_23_RH': [70, 132, 184],
'SomMotA_24_RH': [70, 132, 185],
'SomMotA_25_RH': [70, 132, 186],
'SomMotA_26_RH': [70, 132, 187],
'SomMotA_27_RH': [70, 132, 188],
'SomMotB_Cent_1_RH': [43, 204, 164],
'SomMotB_Cent_2_RH': [43, 204, 166],
'SomMotB_Cent_3_RH': [43, 204, 167],
'SomMotB_Cent_4_RH': [43, 204, 168],
'SomMotB_Cent_5_RH': [43, 204, 169],
'SomMotB_Cent_6_RH': [43, 204, 170],
'SomMotB_S2_1_RH': [43, 205, 162],
'SomMotB_S2_2_RH': [43, 205, 163],
'SomMotB_S2_3_RH': [43, 205, 165],
'SomMotB_S2_4_RH': [43, 205, 166],
'SomMotB_S2_5_RH': [43, 205, 167],
'SomMotB_S2_6_RH': [43, 205, 168],
'SomMotB_S2_7_RH': [43, 205, 169],
'SomMotB_S2_8_RH': [43, 205, 170],
'SomMotB_Ins_1_RH': [43, 205, 171],
'SomMotB_Aud_1_RH': [42, 204, 164],
'SomMotB_Aud_2_RH': [42, 204, 165],
'SomMotB_Aud_3_RH': [42, 204, 166],
'SomMotB_Aud_4_RH': [42, 204, 167],
'DorsAttnA_TempOcc_1_RH': [74, 156, 62],
'DorsAttnA_TempOcc_2_RH': [74, 156, 63],
'DorsAttnA_TempOcc_3_RH': [74, 156, 64],
'DorsAttnA_ParOcc_1_RH': [75, 155, 61],
'DorsAttnA_ParOcc_2_RH': [75, 155, 62],
'DorsAttnA_ParOcc_3_RH': [75, 155, 63],
'DorsAttnA_ParOcc_4_RH': [75, 155, 64],
'DorsAttnA_SPL_1_RH': [75, 155, 57],
'DorsAttnA_SPL_2_RH': [75, 155, 58],
'DorsAttnA_SPL_3_RH': [75, 155, 59],
'DorsAttnA_SPL_4_RH': [75, 155, 60],
'DorsAttnA_SPL_5_RH': [75, 155, 65],
'DorsAttnA_SPL_6_RH': [75, 155, 66],
'DorsAttnA_SPL_7_RH': [75, 155, 67],
'DorsAttnA_SPL_8_RH': [75, 155, 68],
'DorsAttnA_SPL_9_RH': [75, 156, 61],
'DorsAttnA_SPL_10_RH': [75, 156, 62],
'DorsAttnA_SPL_11_RH': [75, 156, 63],
'DorsAttnA_SPL_12_RH': [75, 156, 64],
'DorsAttnB_TempOcc_1_RH': [1, 118, 15],
'DorsAttnB_PostC_1_RH': [1, 118, 11],
'DorsAttnB_PostC_2_RH': [1, 118, 12],
'DorsAttnB_PostC_3_RH': [1, 118, 13],
'DorsAttnB_PostC_4_RH': [1, 118, 14],
'DorsAttnB_PostC_5_RH': [1, 118, 16],
'DorsAttnB_PostC_6_RH': [1, 118, 17],
'DorsAttnB_PostC_7_RH': [1, 118, 18],
'DorsAttnB_PostC_8_RH': [1, 118, 19],
'DorsAttnB_PostC_9_RH': [1, 118, 20],
'DorsAttnB_PostC_10_RH': [1, 118, 21],
'DorsAttnB_PostC_11_RH': [1, 118, 22],
'DorsAttnB_PostC_12_RH': [1, 119, 15],
'DorsAttnB_FEF_1_RH': [1, 119, 16],
'DorsAttnB_FEF_2_RH': [1, 119, 17],
'DorsAttnB_FEF_3_RH': [1, 119, 18],
'DorsAttnB_FEF_4_RH': [1, 119, 19],
'DorsAttnB_PrCv_1_RH': [1, 119, 20],
'SalVentAttnA_ParOper_1_RH': [196, 58, 248],
'SalVentAttnA_ParOper_2_RH': [196, 58, 250],
'SalVentAttnA_ParOper_3_RH': [196, 58, 251],
'SalVentAttnA_ParOper_4_RH': [196, 58, 252],
'SalVentAttnA_ParOper_5_RH': [196, 58, 253],
'SalVentAttnA_PrC_1_RH': [196, 57, 251],
'SalVentAttnA_FrOper_1_RH': [196, 57, 248],
'SalVentAttnA_FrOper_2_RH': [196, 57, 250],
'SalVentAttnA_FrOper_3_RH': [196, 57, 252],
'SalVentAttnA_FrOper_4_RH': [196, 57, 253],
'SalVentAttnA_FrOper_5_RH': [196, 57, 254],
'SalVentAttnA_Ins_1_RH': [195, 58, 249],
'SalVentAttnA_Ins_2_RH': [195, 58, 251],
'SalVentAttnA_Ins_3_RH': [195, 58, 252],
'SalVentAttnA_Ins_4_RH': [195, 58, 253],
'SalVentAttnA_Ins_5_RH': [195, 58, 254],
'SalVentAttnA_Ins_6_RH': [195, 58, 255],
'SalVentAttnA_ParMed_1_RH': [195, 58, 248],
'SalVentAttnA_ParMed_2_RH': [195, 58, 250],
'SalVentAttnA_ParMed_3_RH': [192, 51, 249],
'SalVentAttnA_ParMed_4_RH': [192, 52, 242],
'SalVentAttnA_ParMed_5_RH': [192, 52, 243],
'SalVentAttnA_ParMed_6_RH': [192, 52, 244],
'SalVentAttnA_FrMed_1_RH': [195, 57, 248],
'SalVentAttnA_FrMed_2_RH': [195, 57, 249],
'SalVentAttnA_FrMed_3_RH': [195, 57, 251],
'SalVentAttnA_FrMed_4_RH': [195, 57, 252],
'SalVentAttnA_FrMed_5_RH': [195, 57, 253],
'SalVentAttnA_FrMed_6_RH': [195, 57, 254],
'SalVentAttnA_FrMed_7_RH': [195, 57, 255],
'SalVentAttnB_IPL_1_RH': [254, 152, 214],
'SalVentAttnB_IPL_2_RH': [254, 152, 215],
'SalVentAttnB_PFCd_1_RH': [254, 152, 213],
'SalVentAttnB_PFCd_2_RH': [254, 152, 216],
'SalVentAttnB_PFCl_1_RH': [254, 151, 214],
'SalVentAttnB_PFCl_2_RH': [254, 151, 215],
'SalVentAttnB_PFCl_3_RH': [254, 151, 216],
'SalVentAttnB_PFClv_1_RH': [254, 151, 213],
'SalVentAttnB_PFClv_2_RH': [254, 151, 217],
'SalVentAttnB_Ins_1_RH': [254, 152, 217],
'SalVentAttnB_Ins_2_RH': [254, 152, 218],
'SalVentAttnB_Ins_3_RH': [254, 152, 219],
'SalVentAttnB_Ins_4_RH': [254, 152, 220],
'SalVentAttnB_PFCmp_1_RH': [254, 153, 214],
'SalVentAttnB_PFCmp_2_RH': [254, 153, 215],
'SalVentAttnB_PFCmp_3_RH': [254, 153, 216],
'SalVentAttnB_PFCmp_4_RH': [254, 153, 217],
'SalVentAttnB_Cinga_1_RH': [255, 151, 213],
'LimbicB_OFC_1_RH': [122, 135, 47],
'LimbicB_OFC_2_RH': [122, 135, 48],
'LimbicB_OFC_3_RH': [122, 135, 49],
'LimbicB_OFC_4_RH': [122, 135, 50],
'LimbicB_OFC_5_RH': [122, 135, 52],
'LimbicB_OFC_6_RH': [122, 135, 53],
'LimbicB_OFC_7_RH': [122, 135, 54],
'LimbicB_OFC_8_RH': [122, 135, 55],
'LimbicB_OFC_9_RH': [122, 135, 56],
'LimbicB_OFC_10_RH': [122, 135, 57],
'LimbicB_OFC_11_RH': [122, 135, 58],
'LimbicA_TempPole_1_RH': [220, 248, 162],
'LimbicA_TempPole_2_RH': [220, 248, 163],
'LimbicA_TempPole_3_RH': [220, 248, 164],
'LimbicA_TempPole_4_RH': [220, 248, 166],
'LimbicA_TempPole_5_RH': [220, 248, 167],
'LimbicA_TempPole_6_RH': [220, 248, 168],
'LimbicA_TempPole_7_RH': [220, 248, 169],
'LimbicA_TempPole_8_RH': [220, 248, 170],
'LimbicA_TempPole_9_RH': [220, 248, 171],
'ContA_IPS_1_RH': [230, 147, 32],
'ContA_IPS_2_RH': [230, 147, 33],
'ContA_IPS_3_RH': [230, 147, 35],
'ContA_IPS_4_RH': [230, 147, 36],
'ContA_IPS_5_RH': [230, 147, 37],
'ContA_IPS_6_RH': [230, 147, 38],
'ContA_IPS_7_RH': [230, 147, 39],
'ContA_IPS_8_RH': [230, 147, 40],
'ContA_PFCd_1_RH': [230, 147, 34],
'ContA_PFCd_2_RH': [230, 148, 33],
'ContA_PFCl_1_RH': [229, 148, 32],
'ContA_PFCl_2_RH': [229, 148, 33],
'ContA_PFCl_3_RH': [229, 148, 35],
'ContA_PFCl_4_RH': [229, 148, 36],
'ContA_PFCl_5_RH': [229, 148, 37],
'ContA_PFCl_6_RH': [229, 148, 38],
'ContA_PFCl_7_RH': [229, 148, 39],
'ContA_Cingm_1_RH': [229, 148, 34],
'ContB_Temp_1_RH': [136, 51, 76],
'ContB_Temp_2_RH': [136, 51, 77],
'ContB_Temp_3_RH': [136, 51, 78],
'ContB_IPL_1_RH': [135, 50, 72],
'ContB_IPL_2_RH': [135, 50, 74],
'ContB_IPL_3_RH': [135, 50, 75],
'ContB_IPL_4_RH': [135, 50, 76],
'ContB_IPL_5_RH': [135, 50, 77],
'ContB_PFCld_1_RH': [135, 49, 72],
'ContB_PFCld_2_RH': [135, 49, 73],
'ContB_PFCld_3_RH': [135, 49, 75],
'ContB_PFCld_4_RH': [135, 49, 76],
'ContB_PFCld_5_RH': [135, 49, 77],
'ContB_PFCld_6_RH': [135, 49, 78],
'ContB_PFCld_7_RH': [135, 49, 79],
'ContB_PFClv_1_RH': [135, 49, 74],
'ContB_PFClv_2_RH': [135, 49, 80],
'ContB_PFClv_3_RH': [135, 50, 73],
'ContB_PFClv_4_RH': [135, 50, 78],
'ContB_PFClv_5_RH': [135, 50, 79],
'ContB_PFClv_6_RH': [135, 50, 80],
'ContB_PFCmp_1_RH': [134, 50, 75],
'ContC_pCun_1_RH': [119, 141, 175],
'ContC_pCun_2_RH': [119, 141, 177],
'ContC_pCun_3_RH': [119, 141, 178],
'ContC_pCun_4_RH': [119, 141, 179],
'ContC_pCun_5_RH': [119, 141, 180],
'ContC_pCun_6_RH': [119, 141, 181],
'ContC_Cingp_1_RH': [119, 141, 182],
'ContC_Cingp_2_RH': [119, 141, 183],
'ContC_Cingp_3_RH': [119, 141, 184],
'DefaultA_Temp_1_RH': [254, 255, 2],
'DefaultA_IPL_1_RH': [255, 254, 2],
'DefaultA_IPL_2_RH': [255, 254, 3],
'DefaultA_IPL_3_RH': [255, 254, 4],
'DefaultA_IPL_4_RH': [255, 254, 5],
'DefaultA_PFCd_1_RH': [255, 255, 3],
'DefaultA_PFCd_2_RH': [255, 255, 4],
'DefaultA_PFCd_3_RH': [255, 255, 5],
'DefaultA_pCunPCC_1_RH': [255, 253, 1],
'DefaultA_pCunPCC_2_RH': [255, 253, 2],
'DefaultA_pCunPCC_3_RH': [255, 253, 3],
'DefaultA_pCunPCC_4_RH': [255, 253, 4],
'DefaultA_pCunPCC_5_RH': [255, 253, 5],
'DefaultA_pCunPCC_6_RH': [255, 253, 6],
'DefaultA_pCunPCC_7_RH': [255, 253, 7],
'DefaultA_pCunPCC_8_RH': [255, 254, 0],
'DefaultA_pCunPCC_9_RH': [255, 254, 1],
'DefaultA_pCunPCC_10_RH': [255, 254, 6],
'DefaultA_PFCm_1_RH': [253, 255, 1],
'DefaultA_PFCm_2_RH': [253, 255, 2],
'DefaultA_PFCm_3_RH': [253, 255, 3],
'DefaultA_PFCm_4_RH': [253, 255, 4],
'DefaultA_PFCm_5_RH': [253, 255, 5],
'DefaultA_PFCm_6_RH': [253, 255, 6],
'DefaultA_PFCm_7_RH': [253, 255, 7],
'DefaultA_PFCm_8_RH': [250, 249, 0],
'DefaultB_Temp_1_RH': [206, 62, 80],
'DefaultB_Temp_2_RH': [206, 62, 81],
'DefaultB_AntTemp_1_RH': [206, 63, 79],
'DefaultB_AntTemp_2_RH': [206, 63, 80],
'DefaultB_AntTemp_3_RH': [206, 63, 81],
'DefaultB_PFCd_1_RH': [206, 63, 78],
'DefaultB_PFCd_2_RH': [206, 63, 82],
'DefaultB_PFCd_3_RH': [206, 63, 83],
'DefaultB_PFCd_4_RH': [206, 63, 84],
'DefaultB_PFCd_5_RH': [206, 63, 85],
'DefaultB_PFCd_6_RH': [206, 63, 86],
'DefaultB_PFCv_1_RH': [205, 62, 76],
'DefaultB_PFCv_2_RH': [205, 62, 78],
'DefaultB_PFCv_3_RH': [205, 62, 79],
'DefaultB_PFCv_4_RH': [205, 62, 80],
'DefaultB_PFCv_5_RH': [205, 62, 81],
'DefaultC_IPL_1_RH': [0, 1, 132],
'DefaultC_IPL_2_RH': [0, 1, 133],
'DefaultC_IPL_3_RH': [0, 1, 134],
'DefaultC_Rsp_1_RH': [1, 0, 131],
'DefaultC_Rsp_2_RH': [1, 0, 132],
'DefaultC_Rsp_3_RH': [1, 0, 133],
'DefaultC_PHC_1_RH': [1, 0, 134],
'DefaultC_PHC_2_RH': [1, 0, 135],
'DefaultC_PHC_3_RH': [1, 0, 136],
'TempPar_1_RH': [12, 48, 249],
'TempPar_2_RH': [12, 48, 250],
'TempPar_3_RH': [12, 48, 251],
'TempPar_4_RH': [12, 48, 252],
'TempPar_5_RH': [12, 48, 253],
'TempPar_6_RH': [12, 48, 255],
'TempPar_7_RH': [9, 41, 250],
'TempPar_8_RH': [9, 41, 251],
'TempPar_9_RH': [9, 41, 252],
'TempPar_10_RH': [9, 41, 253],
'TempPar_11_RH': [9, 41, 254],
'TempPar_12_RH': [9, 42, 247],
'TempPar_13_RH': [9, 42, 248]}
get_vertex_colors_from_coord iterates over every brain surface vertex, reads its label from the named coordinate, and returns the corresponding color from the mapping. Vertices whose label is not found in the mapping receive default_color (grey by default). The result is a list in the same vertex order as brain.vertices, ready to pass directly to any of the cedalion.vis plotting functions.
[9]:
vertex_colors = get_vertex_colors_from_coord(colin_ijk_labeled.brain, "parcel", color_mapping=schaefer_color_dict)
print(f"The brain surface has {colin_ijk_labeled.brain.nvertices} vertices.")
print(f"The list vertex_colors has {len(vertex_colors)} entries. These are the first entries:")
vertex_colors[:4]
The brain surface has 25000 vertices.
The list vertex_colors has 25000 entries. These are the first entries:
[9]:
[(0.47058823529411764, 0.07058823529411765, 0.5411764705882353),
(0.47058823529411764, 0.07058823529411765, 0.5333333333333333),
(0.47058823529411764, 0.07058823529411765, 0.5411764705882353),
(0.47058823529411764, 0.07058823529411765, 0.5411764705882353)]
plot_brain_views_grid renders the brain surface from five standard viewpoints (superior, left, right, anterior, posterior) in a single figure. We pass the inflated surface here — which has the same vertex order as the pial surface — so sulcal cortex is unfolded and every parcel is visible at once.
The Schaefer2018 parcellation on the inflated Colin27 cortex:
[10]:
plot_brain_views_grid(colin_inflated, vertex_colors, reset_camera=True)
AAL3 Labels on Colin27
We now visualize the freshly assigned AAL3 labels. Because AAL3 does not ship with a canonical per-region color map, we pass color_mapping=None to let get_vertex_colors_from_coord generate colors automatically. The algorithm uses a deterministic golden-ratio hue spacing so colors are consistent across calls.
We show both the pial (folded) and the inflated surface. The inflated view makes buried sulcal cortex visible and allows you to judge where parcel boundaries fall relative to major anatomical landmarks. Notice that compared to the Schaefer2018 map above, some AAL3 borders appear slightly less crisp — this is the expected consequence of the volumetric-to-surface transfer (discussed in detail at the end of this notebook).
[11]:
vertex_colors = get_vertex_colors_from_coord(colin_ijk_labeled.brain, "parcel_aal3", color_mapping=None, default_color="magenta")
plot_brain_views_grid(colin_ijk_labeled.brain, vertex_colors)
plot_brain_views_grid(colin_inflated, vertex_colors, reset_camera=True)
Brodmann Labels on Colin27
The same workflow applied to the Brodmann atlas. Brodmann areas are fewer and larger than AAL3 regions. On the inflated surface the classical areas are clearly recognisable: BA4/6 along the central sulcus (motor/premotor), BA17/18/19 in the occipital lobe (visual cortex), and BA44/45 in the left inferior frontal gyrus (Broca’s area).
[12]:
vertex_colors = get_vertex_colors_from_coord(colin_ijk_labeled.brain, "parcel_brodmann", color_mapping=None)
plot_brain_views_grid(colin_ijk_labeled.brain, vertex_colors)
plot_brain_views_grid(colin_inflated, vertex_colors, reset_camera=True)
AAL3 Labels on ICBM152
The same atlas applied to the ICBM152 head model. Any differences from the Colin27 result reflect genuine anatomical differences between the two templates (single-subject average vs. group average) rather than any difference in the atlas or the transfer procedure.
[13]:
vertex_colors = get_vertex_colors_from_coord(icbm_ijk_labeled.brain, "parcel_aal3", color_mapping=None)
plot_brain_views_grid(icbm_ijk_labeled.brain, vertex_colors)
plot_brain_views_grid(icbm_inflated, vertex_colors, reset_camera=True)
Brodmann Labels on ICBM152
[14]:
vertex_colors = get_vertex_colors_from_coord(icbm_ijk_labeled.brain, "parcel_brodmann", color_mapping=None)
plot_brain_views_grid(icbm_ijk_labeled.brain, vertex_colors)
plot_brain_views_grid(icbm_inflated, vertex_colors, reset_camera=True)
Customizing Colors for ROI Highlighting
In practice you will often want to highlight a small set of regions of interest rather than visualize the entire atlas at once. get_vertex_colors_from_coord supports two convenience patterns for this.
Pattern 1 — selected parcels with distinct colors:
Pass a partial color_mapping dict containing only the regions you care about. All other vertices receive default_color (grey). Use this when the highlighted regions should be distinguished from one another by color — for example when comparing two adjacent AAL3 frontal regions.
[15]:
# select only two parcels and specify colors (any matplotlib color spec works)
# parcels not contained in the mapping get the default color
aal3_color_mapping = {"Frontal_Inf_Oper_R" : "r", "Frontal_Inf_Tri_R" : "g"}
vertex_colors = get_vertex_colors_from_coord(colin_ijk_labeled.brain, "parcel_aal3", aal3_color_mapping)
plot_brain_views_grid(colin_ijk_labeled.brain, vertex_colors)
Pattern 2 — highlight a set of parcels in a single color:
Pass a single color string as color_mapping and provide a labels list. Every vertex whose coordinate matches a label in the list gets the specified color; all other vertices get default_color. This gives the clearest signal-vs-background contrast when you want to show, for example, bilateral Broca’s area (BA44 + BA45) against a neutral grey background.
[16]:
# specify only a single color, that will be used for all parcels. Then select only a subset of parcels to color.
vertex_colors = get_vertex_colors_from_coord(
colin_ijk_labeled.brain,
"parcel_brodmann",
color_mapping="r",
labels=["right_BA44", "right_BA45"],
)
plot_brain_views_grid(colin_ijk_labeled.brain, vertex_colors)
Spot-Check: Verifying Label Assignments at Known MNI Coordinates
As a sanity check we verify that the assigned labels are anatomically plausible at three well-known MNI152 locations. We find the nearest brain surface vertex in MNI152 space and read off its Brodmann label.
MNI coordinate |
Expected region |
|---|---|
|
Occipital pole / calcarine sulcus (BA17/18) |
|
Left somatomotor cortex (BA4/6) |
|
Right prefrontal cortex (BA44/45/46) |
[17]:
tests = np.asarray([
[-10, -90, 0],
[-40, -20, 50],
[40, 20, 30],
], dtype=float)
vertex_coords = icbm_ijk_labeled.get_brain_mni152_coords().pint.dequantify().values
vertex_labels = icbm_ijk_labeled.brain.vertices.coords["parcel_brodmann"].values
_, nearest = KDTree(vertex_coords).query(tests)
for mni, vertex_idx in zip(tests, nearest):
print(f"MNI {mni.tolist()} -> nearest surface label {vertex_labels[vertex_idx]}")
MNI [-10.0, -90.0, 0.0] -> nearest surface label left_BA17
MNI [-40.0, -20.0, 50.0] -> nearest surface label left_BA3
MNI [40.0, 20.0, 30.0] -> nearest surface label right_BA44
Parcel-Level Summary Tables
TwoSurfaceHeadModel.parcel_summary_from_vertex_coordinate converts the per-vertex atlas labels into a compact table with one row per Schaefer2018 parcel (the parcellation bundled with the head model). For each Schaefer parcel it reports:
Column |
Meaning |
|---|---|
|
Dominant atlas region covering that parcel (plurality vote over vertices) |
|
Number of vertices whose atlas label equals |
|
Total number of vertices in the Schaefer parcel |
|
Coverage fraction ( |
|
MNI152 centroid of a representative vertex from that parcel |
Medial-wall and background parcels are excluded by default because they do not correspond to cortical tissue. The function returns a pandas.DataFrame that can be saved with .to_csv(..., sep='\t') for use in downstream analyses or supplementary tables in manuscripts.
[18]:
colin_ijk_labeled.parcel_summary_from_vertex_coordinate("parcel_aal3", "colin27")
[18]:
| model | parcel | atlas_label | vertex | fsaverage_vertex | mni152_r | mni152_a | mni152_s | matching_vertices | parcel_vertices | fraction_of_parcel | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | colin27 | ContA_Cingm_1_LH | Cingulate_Mid_L | 5953 | 81987 | -3.695 | -8.988 | 33.489 | 11 | 12 | 0.916667 |
| 1 | colin27 | ContA_Cingm_1_RH | Cingulate_Mid_R | 18590 | 250973 | 5.049 | -6.508 | 33.139 | 13 | 15 | 0.866667 |
| 2 | colin27 | ContA_IPS_1_LH | Parietal_Inf_L | 1444 | 19061 | -27.228 | -68.913 | 47.734 | 6 | 19 | 0.315789 |
| 3 | colin27 | ContA_IPS_1_RH | Angular_R | 13939 | 185393 | 34.677 | -68.207 | 52.250 | 15 | 20 | 0.750000 |
| 4 | colin27 | ContA_IPS_2_LH | Parietal_Inf_L | 4293 | 56365 | -62.354 | -32.738 | 40.339 | 19 | 25 | 0.760000 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 595 | colin27 | VisPeri_StriCal_3_LH | Calcarine_L | 245 | 3564 | -1.727 | -91.388 | 10.820 | 30 | 44 | 0.681818 |
| 596 | colin27 | VisPeri_StriCal_3_RH | Calcarine_R | 13063 | 174754 | 14.374 | -80.162 | 13.916 | 109 | 109 | 1.000000 |
| 597 | colin27 | VisPeri_StriCal_4_LH | Calcarine_L | 586 | 8177 | -2.947 | -83.303 | 14.432 | 79 | 81 | 0.975309 |
| 598 | colin27 | VisPeri_StriCal_4_RH | Calcarine_R | 13732 | 183013 | 24.182 | -69.494 | 7.446 | 65 | 69 | 0.942029 |
| 599 | colin27 | VisPeri_StriCal_5_LH | Calcarine_L | 367 | 5267 | -1.144 | -89.130 | 7.586 | 18 | 48 | 0.375000 |
600 rows × 11 columns
[19]:
colin_ijk_labeled.parcel_summary_from_vertex_coordinate("parcel_brodmann", "colin27")
[19]:
| model | parcel | atlas_label | vertex | fsaverage_vertex | mni152_r | mni152_a | mni152_s | matching_vertices | parcel_vertices | fraction_of_parcel | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | colin27 | ContA_Cingm_1_LH | left_BA24 | 6094 | 84170 | -1.647 | -7.011 | 33.495 | 9 | 12 | 0.750000 |
| 1 | colin27 | ContA_Cingm_1_RH | right_BA24 | 18590 | 250973 | 5.049 | -6.508 | 33.139 | 12 | 15 | 0.800000 |
| 2 | colin27 | ContA_IPS_1_LH | left_BA39 | 1249 | 16617 | -28.384 | -72.183 | 42.951 | 13 | 19 | 0.684211 |
| 3 | colin27 | ContA_IPS_1_RH | right_BA39 | 13939 | 185393 | 34.677 | -68.207 | 52.250 | 16 | 20 | 0.800000 |
| 4 | colin27 | ContA_IPS_2_LH | left_BA40 | 3953 | 51685 | -62.581 | -36.589 | 38.899 | 25 | 25 | 1.000000 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 595 | colin27 | VisPeri_StriCal_3_LH | left_BA17 | 246 | 3586 | -3.473 | -90.929 | 10.449 | 28 | 44 | 0.636364 |
| 596 | colin27 | VisPeri_StriCal_3_RH | right_BA17 | 13063 | 174754 | 14.374 | -80.162 | 13.916 | 109 | 109 | 1.000000 |
| 597 | colin27 | VisPeri_StriCal_4_LH | left_BA17 | 634 | 8858 | -10.089 | -82.331 | 8.929 | 70 | 81 | 0.864198 |
| 598 | colin27 | VisPeri_StriCal_4_RH | right_BA17 | 13732 | 183013 | 24.182 | -69.494 | 7.446 | 57 | 69 | 0.826087 |
| 599 | colin27 | VisPeri_StriCal_5_LH | left_BA18 | 403 | 5726 | -0.299 | -88.728 | 20.022 | 14 | 48 | 0.291667 |
600 rows × 11 columns
[20]:
icbm_ijk_labeled.parcel_summary_from_vertex_coordinate("parcel_aal3", "icbm152")
[20]:
| model | parcel | atlas_label | vertex | fsaverage_vertex | mni152_r | mni152_a | mni152_s | matching_vertices | parcel_vertices | fraction_of_parcel | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | icbm152 | ContA_Cingm_1_LH | Cingulate_Mid_L | 6129 | 81297 | -0.838 | -5.418 | 33.876 | 14 | 16 | 0.875000 |
| 1 | icbm152 | ContA_Cingm_1_RH | Cingulate_Mid_R | 18978 | 245771 | 3.545 | -1.956 | 30.677 | 7 | 8 | 0.875000 |
| 2 | icbm152 | ContA_IPS_1_LH | Occipital_Mid_L | 698 | 10674 | -30.355 | -76.836 | 36.564 | 10 | 16 | 0.625000 |
| 3 | icbm152 | ContA_IPS_1_RH | Occipital_Mid_R | 13350 | 171347 | 31.845 | -75.410 | 38.541 | 7 | 12 | 0.583333 |
| 4 | icbm152 | ContA_IPS_2_LH | Parietal_Inf_L | 2963 | 39596 | -60.495 | -47.388 | 48.498 | 31 | 33 | 0.939394 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 595 | icbm152 | VisPeri_StriCal_3_LH | Calcarine_L | 163 | 2604 | -6.507 | -90.724 | 4.645 | 23 | 33 | 0.696970 |
| 596 | icbm152 | VisPeri_StriCal_3_RH | Calcarine_R | 12877 | 164667 | 9.716 | -85.851 | 7.381 | 84 | 95 | 0.884211 |
| 597 | icbm152 | VisPeri_StriCal_4_LH | Calcarine_L | 448 | 6885 | -11.809 | -81.804 | 7.778 | 63 | 75 | 0.840000 |
| 598 | icbm152 | VisPeri_StriCal_4_RH | Calcarine_R | 13412 | 172367 | 20.590 | -75.303 | 9.519 | 31 | 46 | 0.673913 |
| 599 | icbm152 | VisPeri_StriCal_5_LH | Calcarine_L | 318 | 4717 | -3.824 | -85.535 | 2.495 | 21 | 28 | 0.750000 |
600 rows × 11 columns
[21]:
icbm_ijk_labeled.parcel_summary_from_vertex_coordinate("parcel_brodmann", "icbm152")
[21]:
| model | parcel | atlas_label | vertex | fsaverage_vertex | mni152_r | mni152_a | mni152_s | matching_vertices | parcel_vertices | fraction_of_parcel | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | icbm152 | ContA_Cingm_1_LH | left_BA24 | 6129 | 81297 | -0.838 | -5.418 | 33.876 | 13 | 16 | 0.812500 |
| 1 | icbm152 | ContA_Cingm_1_RH | right_BA24 | 18978 | 245771 | 3.545 | -1.956 | 30.677 | 8 | 8 | 1.000000 |
| 2 | icbm152 | ContA_IPS_1_LH | left_BA39 | 698 | 10674 | -30.355 | -76.836 | 36.564 | 15 | 16 | 0.937500 |
| 3 | icbm152 | ContA_IPS_1_RH | right_BA7 | 13350 | 171347 | 31.845 | -75.410 | 38.541 | 10 | 12 | 0.833333 |
| 4 | icbm152 | ContA_IPS_2_LH | left_BA40 | 2963 | 39596 | -60.495 | -47.388 | 48.498 | 33 | 33 | 1.000000 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 595 | icbm152 | VisPeri_StriCal_3_LH | left_BA17 | 163 | 2604 | -6.507 | -90.724 | 4.645 | 31 | 33 | 0.939394 |
| 596 | icbm152 | VisPeri_StriCal_3_RH | right_BA17 | 12877 | 164667 | 9.716 | -85.851 | 7.381 | 90 | 95 | 0.947368 |
| 597 | icbm152 | VisPeri_StriCal_4_LH | left_BA17 | 448 | 6885 | -11.809 | -81.804 | 7.778 | 73 | 75 | 0.973333 |
| 598 | icbm152 | VisPeri_StriCal_4_RH | right_BA17 | 13412 | 172367 | 20.590 | -75.303 | 9.519 | 39 | 46 | 0.847826 |
| 599 | icbm152 | VisPeri_StriCal_5_LH | left_BA17 | 318 | 4717 | -3.824 | -85.535 | 2.495 | 23 | 28 | 0.821429 |
600 rows × 11 columns
Optional: Save Summary Tables
The summary tables above are ordinary pandas.DataFrame objects. To write them to disk, set SAVE_TABLES = True in the next cell. Files are saved in the atlas_parcel_summaries/ folder relative to the notebook kernel’s current working directory.
[22]:
from pathlib import Path
SAVE_TABLES = False
OUTPUT_DIR = Path("atlas_parcel_summaries")
if SAVE_TABLES:
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
summaries = {
"aal3_parcel_summary_colin27.tsv": colin_ijk_labeled.parcel_summary_from_vertex_coordinate("parcel_aal3", "colin27"),
"brodmann_parcel_summary_colin27.tsv": colin_ijk_labeled.parcel_summary_from_vertex_coordinate("parcel_brodmann", "colin27"),
"aal3_parcel_summary_icbm152.tsv": icbm_ijk_labeled.parcel_summary_from_vertex_coordinate("parcel_aal3", "icbm152"),
"brodmann_parcel_summary_icbm152.tsv": icbm_ijk_labeled.parcel_summary_from_vertex_coordinate("parcel_brodmann", "icbm152"),
}
for filename, summary in summaries.items():
summary.to_csv(OUTPUT_DIR / filename, sep="\t", index=False)
print(f"Saved {len(summaries)} summary tables to {OUTPUT_DIR.resolve()}")
Limitations of the Volumetric MNI Approach
Why parcel borders appear fuzzy on the inflated surface
The volumetric-to-surface label transfer is inherently approximate. The label of a brain surface vertex is determined by the nearest labelled voxel in 3-D MNI152 space. Because sulcal folds can bring two cortically distant regions to within a few millimetres of each other in 3-D, vertices near a sulcal wall may be assigned the label of the anatomically adjacent — but cortically distant — region instead of their own.
This artefact is most visible on the inflated surface: inflation changes vertex positions in 3-D while leaving labels fixed. Vertices that sit at the fundus (bottom) of a deep sulcus can therefore show “bleeding” — incorrect labels — at the inflated parcel border, even though the label assignment on the folded pial surface appears correct.
The mni_eps search radius controls the trade-off: a smaller radius reduces cross-sulcal contamination but increases the number of vertices that receive 'Background' (no labelled voxel found within reach). The default of 5 mm is a practical compromise for atlases with 1 mm isotropic voxels.
When to use FreeSurfer-based labeling instead
For applications where parcel boundary precision matters — for example when comparing fine-grained DOT image reconstruction results to specific cortical regions, or when building a classifier that relies on exact parcel membership — surface-native labeling via FreeSurfer is the more accurate alternative.
FreeSurfer [Fis12] assigns parcels directly on the cortical surface mesh by registering each vertex to the fsaverage template, where parcel boundaries are defined as vertex-level annotations. Because the boundary is expressed in the same surface space as the vertex, no voxel-lookup approximation is introduced and region borders are exact, even on the inflated surface.
Cedalion provides a complete FreeSurfer-based pipeline for individualized head models in 43b_individualized_head_models.ipynb, which walks through FreeSurfer cortical reconstruction, registration to fsaverage, and surface-native parcel annotation. The standard Colin27 and ICBM152 models were built with exactly this pipeline; their bundled parcel coordinate (Schaefer2018) is a surface-native annotation — which is why Schaefer borders look sharper
than AAL3 or Brodmann borders on the same inflated surface.
Practical guidance:
Use case |
Recommended approach |
|---|---|
Quick atlas comparison, ROI definitions, group-level reporting |
Volumetric MNI lookup (this notebook) |
High-precision boundary analysis, individual MRI available |
FreeSurfer surface-native labeling |
Bridging a new atlas to an existing surface-native parcellation |
Volumetric MNI lookup, compare overlap with Schaefer via |
References
[23]:
cedalion.bib.dump_to_notebook()
Methods used
| [1] | Holmes1998 | cedalion.data.get_colin27_headmodel_files | Colin J. Holmes, Rick Hoge, Louis Collins, Roger Woods, Arthur W. Toga, and Alan C. Evans. Enhancement of mr images using registration for signal averaging. Journal of Computer Assisted Tomography, 22(2):324–333, March 1998. doi:10.1097/00004728-199803000-00032. |
| [2] | Fischl2012 | cedalion.data.get_colin27_headmodel_files, cedalion.data.get_icbm152_headmodel_files | Bruce Fischl. FreeSurfer. NeuroImage, 62(2):774–781, 2012. doi:10.1016/j.neuroimage.2012.01.021. |
| [3] | Schaefer2018 | cedalion.data.get_colin27_headmodel_files, cedalion.data.get_icbm152_headmodel_files | Alexander Schaefer, Ru Kong, Evan M Gordon, Timothy O Laumann, Xi-Nian Zuo, Avram J Holmes, Simon B Eickhoff, and BT Thomas Yeo. Local-global parcellation of the human cerebral cortex from intrinsic functional connectivity mri. Cerebral cortex, 28(9):3095–3114, 2018. doi:10.1093/cercor/bhx179. |
| [4] | Fonov2011 | cedalion.data.get_icbm152_headmodel_files | Vladimir Fonov, Alan C. Evans, Kelly Botteron, C. Robert Almli, Robert C. McKinstry, and D. Louis Collins. Unbiased average age-appropriate atlases for pediatric studies. NeuroImage, 54(1):313–327, January 2011. doi:10.1016/j.neuroimage.2010.07.033. |
| [5] | Rolls2020 | cedalion.data.get_atlas_files | Edmund T. Rolls, Chu-Chung Huang, Ching-Po Lin, Jianfeng Feng, and Marc Joliot. Automated anatomical labelling atlas 3. NeuroImage, 206:116189, 2020. doi:https://doi.org/10.1016/j.neuroimage.2019.116189. |
| [6] | Mai2017 | cedalion.data.get_atlas_files | Jürgen K. Mai and Milan Majtanik. Human Brain in Standard MNI Space: Structure and Function: A Comprehensive Pocket Atlas. Academic Press, an imprint of Elsevier, London ; San Diego, CA, 2017. ISBN 978-0-12-811275-5. |