spectralbrain.io.loaders#
Unified loaders for neuroimaging and geometry formats.
Every loader returns plain NumPy arrays using the canonical type
aliases from spectralbrain.runtime. No loader returns
library-specific objects (nibabel images, PyVista meshes, etc.) —
downstream modules receive only arrays and dicts.
The auto-detection function load() inspects the file extension
(and, when ambiguous, magic bytes) to dispatch to the correct
format-specific loader.
Dependencies#
nibabel — required for FreeSurfer, GIfTI, NIfTI, MGZ. Lazy-imported so
import spectralbrainworks without it.pyvista — core dependency; reads generic meshes (.ply / .obj / .stl / .vtk / .vtp) natively via VTK.
h5py — core dependency, for HDF5 cache files.
Module Attributes
Map from Desikan-Killiany (aparc) region names to lobe labels. |
|
Map from Schaefer parcel network prefixes to Yeo 7/17 network names. |
Functions
|
Aggregate vertex-wise data per parcellation region. |
|
Split a surface into sub-meshes according to a parcellation. |
|
Identify the geometry format of a file. |
|
Extract the sub-mesh defined by a vertex mask. |
|
Extract a point cloud from a volumetric segmentation. |
|
Auto-detect format and load a neuroimaging / geometry file. |
|
Load a FreeSurfer annotation (parcellation overlay). |
|
Load a FreeSurfer per-vertex scalar overlay. |
|
Load a FreeSurfer surface file. |
|
Load a GIfTI functional / shape overlay. |
|
Load a GIfTI label overlay. |
|
Load a GIfTI surface file. |
|
Load a mesh from a generic format (.ply, .obj, .stl, .vtk, .vtp). |
|
Load a NIfTI or MGZ volume. |
|
Remap per-vertex parcellation labels to a coarser grouping. |
- spectralbrain.io.loaders.aggregate_by_parcellation(data, labels, *, stat='mean', ignore_labels=None, label_names=None)[source]#
Aggregate vertex-wise data per parcellation region.
Compute summary statistics of a vertex-wise array (e.g. thickness, HKS, z-score) within each parcel defined by labels.
- Parameters:
data (ndarray, shape (V,) or (V, D)) – Vertex-wise data. If 2-D, each column is aggregated independently.
labels (ndarray, shape (V,)) – Per-vertex integer labels.
stat (str or callable) – Aggregation function. Built-in options:
"mean","median","std","min","max","sum","count","iqr"(interquartile range). Or pass a callable that accepts an array and returns a scalar.ignore_labels (list of int, optional) – Labels to exclude (e.g.
[0]for medial wall).label_names (dict of {int: str}, optional) – Mapping from label integer to name. If provided, the returned DataFrame uses region names as the index.
- Returns:
pandas.DataFrame – One row per parcel, columns are
"label"(or region name) plus one column per data dimension ("d0","d1", … or"value"for 1-D input).- Return type:
pd.DataFrame
Examples
Mean cortical thickness per Desikan region:
>>> thickness = sb.io.load_freesurfer_morph("lh.thickness") >>> labels, _, names = sb.io.load_freesurfer_annot("lh.aparc.annot") >>> df = sb.io.aggregate_by_parcellation( ... thickness, labels, stat="mean", ignore_labels=[0], ... ) >>> df.head()
Mean HKS per Yeo network (after remapping):
>>> hks = sb.spectral.compute_hks(decomp, n_times=16) >>> net_labels, net_names = sb.io.remap_parcellation( ... labels, names, sb.io.SCHAEFER_NETWORK_MAP, match="contains", ... ) >>> df = sb.io.aggregate_by_parcellation( ... hks, net_labels, stat="mean", ... ignore_labels=[0], label_names=net_names, ... )
- spectralbrain.io.loaders.apply_parcellation(vertices, faces, labels, *, ignore_labels=None)[source]#
Split a surface into sub-meshes according to a parcellation.
Given a cortical mesh and a per-vertex label array (e.g. from a Schaefer
.annot), extracts one sub-mesh per parcel.- Parameters:
- Returns:
dict of {int ((vertices, faces)}) – Mapping from label ID to the corresponding sub-mesh. Each sub-mesh has re-indexed faces starting from 0.
- Return type:
dict[int, tuple[ndarray[tuple[Any, …], dtype[floating]], ndarray[tuple[Any, …], dtype[int64]]]]
Notes
This is the building block for the geometric connectome: apply a Schaefer-200 parcellation, compute spectral descriptors per parcel, and build a 200×200 similarity matrix.
Examples
>>> verts, faces = sb.io.load_freesurfer_surface("lh.white") >>> labels, _, names = sb.io.load_freesurfer_annot( ... "lh.Schaefer2018_200Parcels_7Networks_order.annot") >>> parcels = sb.io.apply_parcellation(verts, faces, labels, ... ignore_labels=[0]) >>> len(parcels) 100 # 100 left-hemisphere parcels >>> parcels[1][0].shape # vertices of parcel 1 (823, 3)
- spectralbrain.io.loaders.detect_format(path)[source]#
Identify the geometry format of a file.
- Parameters:
path (PathLike) – File to inspect.
- Returns:
GeometryFormat
- Raises:
ValueError – If the format cannot be determined.
- Return type:
- spectralbrain.io.loaders.extract_submesh(vertices, faces, vertex_mask)[source]#
Extract the sub-mesh defined by a vertex mask.
- Parameters:
vertices (ndarray, shape (N, 3)) – Full mesh vertices.
faces (ndarray, shape (F, 3)) – Full mesh faces.
vertex_mask (ndarray, shape (N,), bool) –
Truefor vertices to keep.
- Returns:
sub_vertices (ndarray, shape (M, 3)) – Subset of vertices.
sub_faces (ndarray, shape (G, 3)) – Re-indexed faces referencing sub_vertices.
- Return type:
tuple[ndarray[tuple[Any, …], dtype[floating]], ndarray[tuple[Any, …], dtype[int64]]]
- spectralbrain.io.loaders.labels_to_pointcloud(label_volume, affine, label_id, *, jitter=False, jitter_scale=0.25, seed=None)[source]#
Extract a point cloud from a volumetric segmentation.
Given a 3D integer label volume (e.g. FreeSurfer
aseg.mgz) and a target label ID, returns the world-space (RAS) coordinates of all voxels with that label.This is the pathway ③ from the SpectralBrain I/O diagram: volumetric segmentation → point cloud → spectral descriptors.
- Parameters:
label_volume (ndarray, shape (X, Y, Z)) – Integer label volume.
affine (ndarray, shape (4, 4)) – Voxel-to-world affine matrix.
label_id (int) – Target label (e.g. 17 for left hippocampus in aseg).
jitter (bool) – Add sub-voxel Gaussian jitter to break the grid pattern. Useful for point-cloud Laplacian estimation, where a regular grid causes degenerate eigenvalues.
jitter_scale (float) – Standard deviation of the jitter in voxel units (default 0.25 — i.e. ±0.25 voxels).
seed (int, optional) – RNG seed for reproducible jitter.
- Returns:
points (ndarray, shape (N, 3)) – World-space coordinates of the extracted voxels.
- Raises:
ValueError – If label_id is not found in the volume.
- Return type:
Examples
>>> data, affine = sb.io.load_nifti("aseg.mgz") >>> hippo_L = sb.io.labels_to_pointcloud(data, affine, label_id=17) >>> hippo_L.shape (4231, 3)
- spectralbrain.io.loaders.load(path, *, fmt=None)[source]#
Auto-detect format and load a neuroimaging / geometry file.
This is the recommended entry point for users who don’t want to think about file formats. The returned dict always contains a
"format"key; other keys depend on the format.- Parameters:
path (PathLike) – File to load.
fmt (GeometryFormat, optional) – Force a specific format (skip auto-detection).
- Returns:
dict – Contents vary by format. Guaranteed keys:
"format":GeometryFormat
Surface files add
"vertices"and"faces". Scalar overlays add"scalars". Annotations add"labels","ctab","names". Volumes add"data","affine".- Raises:
ValueError – Unknown format or failed auto-detection.
FileNotFoundError – Path does not exist.
- Return type:
Examples
>>> result = sb.io.load("lh.white") >>> verts, faces = result["vertices"], result["faces"]
>>> result = sb.io.load("lh.aparc.annot") >>> labels, names = result["labels"], result["names"]
- spectralbrain.io.loaders.load_freesurfer_annot(path)[source]#
Load a FreeSurfer annotation (parcellation overlay).
- Parameters:
path (PathLike) – Path to
.annotfile (e.g.lh.aparc.annot).- Returns:
labels (ndarray, shape (N,)) – Per-vertex parcel index.
ctab (ndarray, shape (n_labels, 5)) – Colour table (RGBT + label ID).
names (list of str) – Region names, one per row of ctab.
- Return type:
tuple[ndarray[tuple[Any, …], dtype[integer]], ndarray, list[str]]
Examples
>>> labels, ctab, names = sb.io.load_freesurfer_annot( ... "lh.aparc.a2009s.annot") >>> set(labels) # unique parcel IDs
- spectralbrain.io.loaders.load_freesurfer_morph(path)[source]#
Load a FreeSurfer per-vertex scalar overlay.
- spectralbrain.io.loaders.load_freesurfer_surface(path)[source]#
Load a FreeSurfer surface file.
- Parameters:
path (PathLike) – Path to a FreeSurfer surface (
.white,.pial,.inflated,.sphere, …).- Returns:
vertices (ndarray, shape (N, 3)) – Vertex coordinates in TkRAS mm.
faces (ndarray, shape (F, 3)) – Triangle indices, 0-indexed.
- Return type:
tuple[ndarray[tuple[Any, …], dtype[floating]], ndarray[tuple[Any, …], dtype[int64]]]
Examples
>>> verts, faces = sb.io.load_freesurfer_surface("lh.white") >>> verts.shape (163842, 3)
- spectralbrain.io.loaders.load_mesh(path)[source]#
Load a mesh from a generic format (.ply, .obj, .stl, .vtk, .vtp).
Backed by PyVista, so every listed format works with a default install (no optional dependency required).
- spectralbrain.io.loaders.remap_parcellation(labels, names, mapping, *, match='exact', unmapped='unmapped')[source]#
Remap per-vertex parcellation labels to a coarser grouping.
Takes the label array and region names from a FreeSurfer
.annot(or any atlas) and remaps each region to a new group according to mapping.- Parameters:
labels (ndarray, shape (V,)) – Per-vertex integer labels (as returned by
load_freesurfer_annot()).names (sequence of str or bytes) – Region names, one per unique label in the annotation colour table. Index i corresponds to label integer i.
mapping (dict of {str: str}) – Source region name → target group name.
match (
"exact"or"contains") –How to match region names to mapping keys.
"exact"— the region name (lowered, stripped) must equal a mapping key."contains"— the region name is assigned to the first mapping key that appears as a substring. Useful for Schaefer parcels whose names embed the network prefix (e.g."7Networks_LH_Vis_1"matches key"Vis").
unmapped (str) – Group name for regions that do not match any mapping key.
- Returns:
new_labels (ndarray, shape (V,)) – Remapped per-vertex labels (contiguous integers starting at 0 for unmapped, 1 for the first group, etc.).
new_names (dict of {int: str}) – Mapping from new integer label to group name.
- Return type:
Examples
Group Desikan parcels into lobes:
>>> labels, ctab, names = sb.io.load_freesurfer_annot("lh.aparc.annot") >>> lobe_labels, lobe_names = sb.io.remap_parcellation( ... labels, names, sb.io.DESIKAN_LOBE_MAP, ... ) >>> set(lobe_names.values()) {'frontal', 'parietal', 'temporal', 'occipital', 'insular', 'unmapped'}
Group Schaefer parcels into Yeo networks:
>>> labels, _, names = sb.io.load_freesurfer_annot( ... "lh.Schaefer2018_400Parcels_7Networks_order.annot" ... ) >>> net_labels, net_names = sb.io.remap_parcellation( ... labels, names, sb.io.SCHAEFER_NETWORK_MAP, match="contains", ... )
- spectralbrain.io.loaders.DESIKAN_LOBE_MAP: dict[str, str] = {'bankssts': 'temporal', 'caudalanteriorcingulate': 'frontal', 'caudalmiddlefrontal': 'frontal', 'cuneus': 'occipital', 'entorhinal': 'temporal', 'frontalpole': 'frontal', 'fusiform': 'temporal', 'inferiorparietal': 'parietal', 'inferiortemporal': 'temporal', 'insula': 'insular', 'isthmuscingulate': 'parietal', 'lateraloccipital': 'occipital', 'lateralorbitofrontal': 'frontal', 'lingual': 'occipital', 'medialorbitofrontal': 'frontal', 'middletemporal': 'temporal', 'paracentral': 'frontal', 'parahippocampal': 'temporal', 'parsopercularis': 'frontal', 'parsorbitalis': 'frontal', 'parstriangularis': 'frontal', 'pericalcarine': 'occipital', 'postcentral': 'parietal', 'posteriorcingulate': 'parietal', 'precentral': 'frontal', 'precuneus': 'parietal', 'rostralanteriorcingulate': 'frontal', 'rostralmiddlefrontal': 'frontal', 'superiorfrontal': 'frontal', 'superiorparietal': 'parietal', 'superiortemporal': 'temporal', 'supramarginal': 'parietal', 'temporalpole': 'temporal', 'transversetemporal': 'temporal'}#
Map from Desikan-Killiany (aparc) region names to lobe labels.
Works with both
aparc.annotandaparc.DKTatlas.annot(Desikan-Killiany-Tourville). The mapping follows standard neuroanatomical conventions.Examples
>>> labels, ctab, names = sb.io.load_freesurfer_annot("lh.aparc.annot") >>> lobe_labels, lobe_names = sb.io.remap_parcellation( ... labels, names, DESIKAN_LOBE_MAP, ... )
- spectralbrain.io.loaders.SCHAEFER_NETWORK_MAP: dict[str, str] = {'Cont': 'Control', 'Default': 'Default', 'DorsAttn': 'DorsalAttention', 'Limbic': 'Limbic', 'SalVentAttn': 'SalVentAttn', 'SomMot': 'Somatomotor', 'TempPar': 'TempPar', 'Vis': 'Visual'}#
Map from Schaefer parcel network prefixes to Yeo 7/17 network names.
Used with
remap_parcellation()whenmatch="contains"to group Schaefer-200/400/600/800/1000 parcels by their parent network.Examples
>>> labels, ctab, names = sb.io.load_freesurfer_annot( ... "lh.Schaefer2018_200Parcels_7Networks_order.annot" ... ) >>> net_labels, net_names = sb.io.remap_parcellation( ... labels, names, SCHAEFER_NETWORK_MAP, match="contains", ... )