SpectralBrain
Spectral Shape Analysis for Brain Structures
SpectralBrain computes, analyzes, and visualizes spectral shape descriptors of brain structures — cortical surfaces, subcortical meshes, hippocampal subfields, white-matter tracts, and point clouds from volumetric segmentations. It connects spectral geometry (the Laplace–Beltrami operator) to clinical neuroimaging, with one pipeline from FreeSurfer / HippUnfold output through statistically rigorous analysis to publication-ready figures.
The core idea: any input geometry — cortical surface, subcortical/hippocampal mesh, tract, or point cloud — is passed through the Laplace–Beltrami operator to obtain its eigenpairs {λ, φ}, from which pose- and mesh-free spectral descriptors (ShapeDNA, HKS, SI-HKS, WKS, GPS, BKS, functional maps, wavelets) are read out.
Statement of need
Volumetric and thickness measures collapse a structure's shape to a few scalars and are sensitive to registration and voxel size. Intrinsic spectral descriptors derived from the Laplace–Beltrami operator (LBO) — ShapeDNA, the Heat/Wave Kernel Signatures, and relatives — characterize shape independently of pose and parameterization, capturing geometry that volume alone misses. They are well established in geometry processing but scattered across research code, rarely packaged with the I/O, multi-site harmonization, correct multiple-comparison statistics, and rendering that a neuroimaging study needs end to end. SpectralBrain fills that gap as a single, tested library, with a primary focus on the hippocampus in mesial temporal lobe epilepsy, while remaining general to any brain surface or point cloud.
Key capabilities
- Spectral descriptors — ShapeDNA, Heat Kernel Signature (HKS), Scale-Invariant HKS, Wave Kernel Signature (WKS), Global Point Signature (GPS), Bates–Kornfeld Signature (BKS) and its inverse, functional maps, and more — all from the LBO eigenpairs of a mesh or point cloud.
- Input-agnostic I/O — FreeSurfer surfaces and morphometry, GIfTI
(
.surf.gii/.func.gii/.shape.gii), NIfTI / MGZ volumes and labels, HippUnfold v1 & v2 outputs,.ply / .obj / .stl / .vtk, HDF5, and point clouds, with automatic format detection. - Cohort loading — BIDS / derivatives, FreeSurfer
SUBJECTS_DIR, or an explicit list, loaded in parallel and stacked for group analysis; FreeSurfer measures can be resampled onto a common template; TractSeg bundle masks import directly as point clouds or isosurface meshes. - Statistics done right — vertex-wise tests with genuine family-wise error control (max-statistic permutation), FDR, partial correlations with correct degrees of freedom, TFCE, the analytic DeLong AUC test, BCa bootstrap, ComBat / ComBat-GAM harmonization, and six PyMC Bayesian models.
- Contiguous clustering & atlas comparison — a distance-dependent Chinese Restaurant Process (ddCRP) with a Normal-Inverse-Wishart collapsed marginal likelihood (spatial and fPCA-functional variants), consensus clustering, data-driven hyperparameter autotuning, and a cluster-vs-atlas suite (ARI/AMI/ NMI/VI, Dice/Jaccard, within-parcel homogeneity) reported against size-matched random parcellations, plus spatially-aware ARI (spARI) and eigenstrapping/ BrainSMASH spatial nulls for bounded surfaces.
- Publication figures — a template-free six-view 3D renderer (vedo), unfolded flat-maps, Bayesian-posterior plots, advanced 3D tractography (direction- encoded/scalar streamlines, bundle surfaces with HKS/WKS overlays, multi-POV montages), and parcellation-vs-clustering grids (views × labelings) for hippocampi, brains, and bundles.
Installation
pip install spectralbrain
Optional feature sets (extras):
pip install "spectralbrain[bayesian]" # PyMC, nutpie, NumPyro, BlackJAX, ArviZ
pip install "spectralbrain[viz]" # vedo, fury, trimesh, cmcrameri, …
pip install "spectralbrain[gpu]" # torch, CuPy, JAX (CUDA)
pip install "spectralbrain[neuro]" # nilearn, dipy, pybids, templateflow, …
pip install "spectralbrain[tuning]" # optuna (ddCRP autotuning; random fallback)
pip install "spectralbrain[full]" # everything above
Requires Python 3.11–3.12.
API at a glance
The core API is on the top-level package; heavier statistics and visualization
live in submodules you import explicitly (mirroring scipy.stats):
import spectralbrain as sb # meshes, descriptors, I/O
import spectralbrain.statistics as sbstats # frequentist + Bayesian
import spectralbrain.viz as sbviz # 3D / 2D figures
Quick start
1 — Mesh → eigenpairs → descriptors
import spectralbrain as sb
# A BrainMesh from vertices (N, 3) and faces (M, 3).
vertices, faces = sb.io.load_gifti_surface("path/to/surf/gii")
mesh = sb.BrainMesh(vertices, faces)
decomp = mesh.decompose(k=100) # 100 LBO eigenpairs
hks = sb.compute_hks(decomp, t_values=[1.0, 10.0, 100.0]) # (N, 3)
wks = sb.compute_wks(decomp, n_energies=50) # (N, 50)
dna = sb.compute_shapedna(decomp) # (k-1,) global
Point clouds work identically — sb.BrainPointCloud(points).decompose(k=...).
2 — Compare two shapes
d = sb.shapedna_distance(dna_a, dna_b) # pose-invariant spectral distance
3 — Vertex-wise group statistics with FWER control
import spectralbrain.statistics as sbstats
# controls, patients : (n_subjects, n_vertices) descriptor fields
res = sbstats.vertexwise_permutation(
controls, patients,
n_permutations=5000,
correction="max", # family-wise error via the max-statistic null
seed=0,
)
significant = res.significant # boolean mask, FWER-controlled
correction="fdr" and "none" are also available; vertexwise_ttest
defaults to Welch's t-test.
4 — Compare two classifiers (analytic DeLong)
auc_new, auc_ref, p = sbstats.auc_comparison_delong(y_true, scores_new, scores_ref)
5 — Six-view 3D render (template-free)
import spectralbrain.viz as sbviz
fig = sbviz.plot_hippocampus_sixview(
mesh, scalars=hks[:, 1],
cmap="plasma", scalar_bar_title="HKS(t=10)",
save="hipp_sixview.png",
)
# Pick any subset/order of the six canonical views:
fig = sbviz.plot_hippocampus_sixview(mesh, scalars=hks[:, 1],
views=("superior", "left_lateral"))
Views: anterior, posterior, inferior, superior, left_lateral, right_lateral.
It renders any surface — HippUnfold v2 den-8k, an aseg ROI mesh, or a whole
cortical hemisphere — with no bundled template, so scalar↔vertex correspondence
is guaranteed.
6 — Bayesian sparse regression (extra: [bayesian])
from spectralbrain.statistics import HorseshoeRegression
model = HorseshoeRegression(tau_prior=0.5).fit(X, y, sampler="nuts")
importance = model.feature_importance() # sparse posterior shrinkage
7 — Contiguous ddCRP clustering + atlas comparison
The sampler maintains incremental per-component sufficient statistics (the cluster scatter is never recomputed inside the candidate loop) and caches the NIW marginal per cluster, so it scales to dense surfaces (~1-3 s/draw at ~7k vertices). Pass n_components to PCA-whiten the descriptors for a further speedup and better conditioning.
import spectralbrain.statistics as sbstats
# H : (V, d) per-vertex descriptors (e.g. fused HKS/WKS); vertices/faces from the mesh.
res = sbstats.cluster_ddcrp(H, faces=faces, vertices=vertices,
decay_kind="exponential") # decay uses real edge distances
print(res) # ClusterResult(method='ddcrp', n_clusters=…)
# Tune hyperparameters from the data (optuna if installed, else random search):
tuned = sbstats.autotune_ddcrp(H, faces=faces, vertices=vertices, n_trials=40)
final = tuned.cluster_result # refit ClusterResult
# Is the partition more atlas-like than a size-matched random parcellation?
report = sbstats.cluster_atlas_concordance(final.labels, atlas_labels,
faces=faces, coords=vertices, n_null=1000)
print(report["metrics"]["ari"], report["ari_null"]["z"], report["spARI"]["spARI"])
8 — Tracts in 3D and parcellation-vs-clustering grids (extra: [viz])
import spectralbrain.viz as sbviz
# (a) advanced 3D tractography from several POVs (FURY; DEC orientation colours)
sl, _ = sbviz.load_streamlines("CST_left.trk", to_space="world") # needs dipy
fig, _ = sbviz.streamlines_multiview(sl, views=("left", "anterior", "superior", "oblique"),
out_path="cst_multiview.pdf")
# bundle surface from a TractSeg mask, with an HKS overlay
V, F = sbviz.mask_to_mesh(mask, affine=affine)
hks = sbviz.spectral_overlay(V, F, kind="hks")
sbviz.render_bundle_surface(V, F, scalars=hks, view="oblique", out_path="cst_hks.png")
# (b) 3D grid: columns = views, rows = a reference parcellation then each clustering
fig, meta = sbviz.plot_parcellation_vs_clusters(
vertices, faces, parcellation=atlas_labels,
clusterings={"ddCRP": res, "Leiden": leiden_res}, # ClusterResult or label arrays
views=["left_lateral", "anterior", "superior"],
save="parcellation_vs_clusters.png",
)
The grid works identically for hippocampi, whole brains, and bundle surfaces —
it operates on any (vertices, faces) mesh plus a dict of per-vertex labelings.
Loading a cohort
import spectralbrain as sb
# BIDS / derivatives (one file per subject):
files = sb.discover_bids("/data/derivatives/hippunfold",
"sub-{sub}/surf/sub-{sub}_hemi-L_*thickness.shape.gii")
group = sb.load_group(files, mode="maps", n_jobs=8)
res = sb.group_comparison(group, group.covariate("group"), test="ttest")
# FreeSurfer SUBJECTS_DIR, resampled to a common template:
group = sb.load_group_freesurfer("/data/fs", measure="thickness",
template="fsaverage", n_jobs=8)
# TractSeg bundle masks → meshes ready for .decompose():
bundles = sb.load_tractseg("/data/sub-01/tractseg_output", output="mesh")
decomp = bundles["CST_left"].decompose(k=80)
mode="pipeline" runs load → decompose → descriptor per subject (with an
optional GPU backend=); mode="maps" stacks vertex-corresponded fields.
Compute backends
Eigen-decomposition and Bayesian sampling run on pluggable backends:
from spectralbrain.backends import TorchBackend # or CupyBackend, JaxBackend
decomp = mesh.decompose(k=200, backend=TorchBackend()) # GPU eigsolve
Bayesian models accept sampler="auto" | "nuts" | "nutpie" | "numpyro" | "blackjax".
Structure & workflow
From inputs to inference, SpectralBrain is one coherent pipeline — load geometry → build the LBO & decompose → compute descriptors → group statistics → assess & visualize — assembled from a small set of focused, independently usable subpackages.
(a) inputs — geometry, operator, cohort, atlas, spectral descriptors, and
inference; (b) the five-step main workflow, ending in a lateralization
effect-size read-out; (c) the modular structure —
core · spectral · io · statistics · viz · backends.
The pipeline in practice
The five stages above are not just a diagram — they run end to end on real study designs. The figure below carries two analyses through the whole pipeline side by side and adds a parallel Bayesian lane, so the same data are assessed with both frequentist tools (max-statistic permutation, TFCE, DeLong AUC) and Bayesian ones (hierarchical models, horseshoe priors, HDI + ROPE, LOO).
An end-to-end walkthrough. Columns are worked analyses —
hippocampal lateralization in MTLE-HS (HippUnfold den-8k surfaces,
L vs R), cortical morphometry (MTLE-HS vs. controls, FreeSurfer / Schaefer-200),
and a Bayesian lane (hierarchical model → horseshoe priors → variable selection
→ posterior effect size with HDI + ROPE → posterior-predictive check and LOO
model comparison). Rows are the five pipeline stages — load
geometry → decompose → descriptors → group statistics → assess — tied on the
left to the subpackages that implement them
(io · core · spectral · statistics · viz). Panels are illustrative,
generated from synthetic example data to show the shape and flow of an analysis,
not empirical results.
Documentation map
| Subpackage | What it provides |
|---|---|
spectralbrain (top level) |
BrainMesh, BrainPointCloud, decompose, all compute_* descriptors, distances, I/O, cohort loading |
spectralbrain.io |
loaders/savers, BIDS & FreeSurfer discovery, load_group, template resampling, TractSeg import, parcellation |
spectralbrain.statistics |
vertex-wise tests, TFCE, effect sizes, RSA, classification, ComBat(-GAM), normative models, bootstrap & null models, six Bayesian models |
spectralbrain.backends |
CPU / Torch / CuPy / JAX eigensolvers; PyMC / nutpie / NumPyro / BlackJAX samplers |
spectralbrain.viz |
six-view 3D renderer, unfolded flat-maps, cluster overlays, Bayesian-posterior and general scientific plots |
Validation
examples/example_clustering_tracts.py is a runnable end-to-end pipeline (HippUnfold hippocampus -> HKS/WKS -> ddCRP -> atlas stats -> 3D figures; synthetic fallback if no data). validation/validate_spari.py checks the spatially-aware Rand index: analytical properties (identity, label invariance, symmetry, reduction to the exact ARI as the spatial scale vanishes, chance level, locality monotonicity) run anywhere, plus an R cell-for-cell bridge (--with-r) against the published spARI package that justifies flipping validated_against_R=True.
Development
git clone https://github.com/rdneuro/spectralbrain
cd spectralbrain
uv sync --group dev # or: pip install -e ".[full]" + dev tools
uv run pytest # run the test suite
uv run ruff check src/ tests/
Citing
If SpectralBrain contributes to your work, please cite it. Someday, maybe, if we feel lucky, a JOSS paper will be submited; until then, cite the archived release on Zenodo:
Debona, R. SpectralBrain: Spectral Shape Analysis for Brain Structures. Zenodo. https://doi.org/10.5281/zenodo.21090748
The DOI 10.5281/zenodo.21090748
always resolves to the latest release. See CITATION.cff for a
machine-readable citation — GitHub's "Cite this repository" button reads it.
License
MIT — see LICENSE.
Metadata
Release files for spectralbrain 0.0.7
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| spectralbrain-0.0.7.tar.gz | 5.1 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| spectralbrain-0.0.7-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 5.6 MB
Release files / spectralbrain-0.0.7.tar.gz
| Download URL | spectralbrain-0.0.7.tar.gz |
|---|---|
| Size | 5.1 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
fd09499d3f6c2e86b0910d73951110df81a558f1cbf499080d58c553d93860c5
|
|
BLAKE2b-256 checksum How to use checksums |
ae0a7c360af838382161c12c92c69700a66d717ca0657699387b8b083dc7cc08
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.
Transparency logRelease files / spectralbrain-0.0.7-py3-none-any.whl
| Download URL | spectralbrain-0.0.7-py3-none-any.whl |
|---|---|
| Size | 489.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
added31929aab22f7d5f9e10eb25060e1540d5ef7a801e2a9bdd69a934e0aa5d
|
|
BLAKE2b-256 checksum How to use checksums |
0c4c6fe1c614a091f609628d349164363dedf0f2520c0f0e1fd846fb61aee995
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.
Transparency log