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.

MNI space as a shared coordinate system

Most brain atlases are defined and distributed in MNI (Montreal Neurological Institute) space: a standardised brain coordinate frame derived from averaging many individual MRI scans into a common template. Every standard head model in Cedalion — Colin27 [HHC+98] and ICBM152 [FEB+11] — carries pre-computed MNI152 coordinates for every brain surface vertex. This means that any volumetric atlas provided as a NIfTI file in MNI space can be transferred to the brain surface without any additional registration step: the shared coordinate system acts as the bridge between the volumetric atlas and the surface model.

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 TwoSurfaceHeadModel and the Schaefer2018 parcellation bundled with the standard models

  • 43b_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:

  1. A NIfTI volume (.nii or .nii.gz) in which every voxel inside a labelled region carries a positive integer, and background voxels carry 0 (or another reserved value).

  2. 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

parcel

Schaefer2018 parcel label [SKG+18]

fsaverage_vertex

Corresponding vertex index in the FreeSurfer fsaverage template

mni152_r/a/s

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:

  1. 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 affine cedalion.dot.utils.mni305_to_mni152 is applied first to bring voxel coordinates into the same MNI152 frame as the head model vertices.

  2. 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_eps mm in MNI152 space are retrieved. Background voxels (label 0 or whichever integer maps to background_label) are excluded, and the closest labelled voxel is selected.

  3. Label assignment: The integer label of the winning voxel is translated to a string via label_mapping and stored as a new vertex coordinate. If no labelled voxel falls within mni_eps mm, the vertex receives background_label.

Key parameters:

Parameter

Effect

coordinate_label

Name of the new vertex coordinate (e.g. 'parcel_aal3')

label_mapping

{int: str} dict mapping numeric voxel labels to region names

voxel_label_niftii

Path to the NIfTI atlas file

voxel_label_crs

MNI variant of the NIfTI: 'mni152' (default) or 'mni305'

mni_eps

Search radius in mm (default 5). Increase if many vertices receive 'Background'

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:

color_mapping value

Behaviour

dict (label → color)

Each label is looked up; vertices not in the dict get default_color

None

A random but deterministic color is generated for every unique label

A single color string (e.g. 'r')

Every vertex whose label is in labels gets that color; the rest get default_color

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)
../../_images/examples_head_models_52_mni_atlas_labels_aal3_brodmann_19_0.png

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)
../../_images/examples_head_models_52_mni_atlas_labels_aal3_brodmann_21_0.png
../../_images/examples_head_models_52_mni_atlas_labels_aal3_brodmann_21_1.png

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)
../../_images/examples_head_models_52_mni_atlas_labels_aal3_brodmann_23_0.png
../../_images/examples_head_models_52_mni_atlas_labels_aal3_brodmann_23_1.png

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)
../../_images/examples_head_models_52_mni_atlas_labels_aal3_brodmann_25_0.png
../../_images/examples_head_models_52_mni_atlas_labels_aal3_brodmann_25_1.png

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)
../../_images/examples_head_models_52_mni_atlas_labels_aal3_brodmann_27_0.png
../../_images/examples_head_models_52_mni_atlas_labels_aal3_brodmann_27_1.png

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)

../../_images/examples_head_models_52_mni_atlas_labels_aal3_brodmann_30_0.png

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)
../../_images/examples_head_models_52_mni_atlas_labels_aal3_brodmann_32_0.png

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

[-10, -90, 0]

Occipital pole / calcarine sulcus (BA17/18)

[-40, -20, 50]

Left somatomotor cortex (BA4/6)

[ 40,  20, 30]

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

atlas_label

Dominant atlas region covering that parcel (plurality vote over vertices)

matching_vertices

Number of vertices whose atlas label equals atlas_label

parcel_vertices

Total number of vertices in the Schaefer parcel

fraction_of_parcel

Coverage fraction (matching_vertices / parcel_vertices)

mni152_r/a/s

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 parcel_summary_from_vertex_coordinate

References

[23]:
cedalion.bib.dump_to_notebook()

Methods used

[1]Holmes1998cedalion.data.get_colin27_headmodel_filesColin 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]Fischl2012cedalion.data.get_colin27_headmodel_files, cedalion.data.get_icbm152_headmodel_filesBruce Fischl. FreeSurfer. NeuroImage, 62(2):774–781, 2012. doi:10.1016/j.neuroimage.2012.01.021.
[3]Schaefer2018cedalion.data.get_colin27_headmodel_files, cedalion.data.get_icbm152_headmodel_filesAlexander 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]Fonov2011cedalion.data.get_icbm152_headmodel_filesVladimir 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]Rolls2020cedalion.data.get_atlas_filesEdmund 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]Mai2017cedalion.data.get_atlas_filesJü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.