Metadata-Version: 2.4
Name: spectralbrain
Version: 0.0.5
Summary: Spectral shape analysis for brain structures via the Laplace-Beltrami operator.
Project-URL: Homepage, https://github.com/rdneuro/spectralbrain
Project-URL: Documentation, https://spectralbrain.readthedocs.io
Project-URL: Repository, https://github.com/rdneuro/spectralbrain
Project-URL: Issues, https://github.com/rdneuro/spectralbrain/issues
Project-URL: Changelog, https://github.com/rdneuro/spectralbrain/blob/main/CHANGELOG.md
Author-email: Rodrigo Debona <r.debona@posgrad.ufsc.br>
Maintainer-email: Rodrigo Debona <r.debona@posgrad.ufsc.br>
License-Expression: MIT
License-File: LICENSE
Keywords: HKS,ShapeDNA,WKS,brain,laplace-beltrami,morphometry,neuroimaging,neuroscience,shape-analysis,spectral-analysis
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
Classifier: Topic :: Scientific/Engineering :: Visualization
Classifier: Typing :: Typed
Requires-Python: <3.13,>=3.11
Requires-Dist: h5py>=3.10
Requires-Dist: joblib>=1.3
Requires-Dist: lapy>=1.0
Requires-Dist: matplotlib>=3.8
Requires-Dist: nibabel>=5.2
Requires-Dist: numpy>=1.26
Requires-Dist: pandas>=2.2
Requires-Dist: pyvista>=0.44
Requires-Dist: rich>=13.7
Requires-Dist: scikit-image>=0.22
Requires-Dist: scikit-learn>=1.4
Requires-Dist: scipy>=1.13
Requires-Dist: seaborn>=0.13
Requires-Dist: tqdm>=4.66
Requires-Dist: vtk>=9.3
Provides-Extra: bayesian
Requires-Dist: arviz>=0.18; extra == 'bayesian'
Requires-Dist: bambi>=0.14; extra == 'bayesian'
Requires-Dist: blackjax>=1.2; extra == 'bayesian'
Requires-Dist: numpyro>=0.15; extra == 'bayesian'
Requires-Dist: nutpie>=0.13; extra == 'bayesian'
Requires-Dist: pymc>=5.16; extra == 'bayesian'
Provides-Extra: full
Requires-Dist: antspyx>=0.4; (platform_system != 'Windows') and extra == 'full'
Requires-Dist: arviz>=0.18; extra == 'full'
Requires-Dist: bambi>=0.14; extra == 'full'
Requires-Dist: blackjax>=1.2; extra == 'full'
Requires-Dist: brainspace; extra == 'full'
Requires-Dist: cupy-cuda13x; (platform_system != 'Darwin') and extra == 'full'
Requires-Dist: dipy>=1.9; extra == 'full'
Requires-Dist: hippomaps; extra == 'full'
Requires-Dist: hippunfold-plot; extra == 'full'
Requires-Dist: ipywidgets>=8.1; extra == 'full'
Requires-Dist: jax[cuda13]; extra == 'full'
Requires-Dist: jaxlib; extra == 'full'
Requires-Dist: jupyterlab>=4.2; extra == 'full'
Requires-Dist: mne-connectivity>=0.7; extra == 'full'
Requires-Dist: mne>=1.7; extra == 'full'
Requires-Dist: nilearn; extra == 'full'
Requires-Dist: numpyro>=0.15; extra == 'full'
Requires-Dist: nutpie>=0.13; extra == 'full'
Requires-Dist: open3d>=0.19; (python_version < '3.13') and extra == 'full'
Requires-Dist: pybids>=0.16; extra == 'full'
Requires-Dist: pymc>=5.16; extra == 'full'
Requires-Dist: scienceplots>=2.1; extra == 'full'
Requires-Dist: templateflow>=24.0; extra == 'full'
Requires-Dist: torch>=2.4; extra == 'full'
Requires-Dist: torchvision; extra == 'full'
Requires-Dist: trame-vtk; extra == 'full'
Requires-Dist: trame-vuetify; extra == 'full'
Requires-Dist: trame>=3.6; extra == 'full'
Requires-Dist: vedo>=2024.5; extra == 'full'
Requires-Dist: yabplot; (python_version == '3.11.*') and extra == 'full'
Provides-Extra: gpu
Requires-Dist: cupy-cuda13x; (platform_system != 'Darwin') and extra == 'gpu'
Requires-Dist: jax[cuda13]; extra == 'gpu'
Requires-Dist: jaxlib; extra == 'gpu'
Requires-Dist: torch>=2.4; extra == 'gpu'
Requires-Dist: torchvision; extra == 'gpu'
Provides-Extra: neuro
Requires-Dist: antspyx>=0.4; (platform_system != 'Windows') and extra == 'neuro'
Requires-Dist: brainspace; extra == 'neuro'
Requires-Dist: dipy>=1.9; extra == 'neuro'
Requires-Dist: mne-connectivity>=0.7; extra == 'neuro'
Requires-Dist: mne>=1.7; extra == 'neuro'
Requires-Dist: nilearn; extra == 'neuro'
Requires-Dist: pybids>=0.16; extra == 'neuro'
Requires-Dist: templateflow>=24.0; extra == 'neuro'
Provides-Extra: notebooks
Requires-Dist: ipywidgets>=8.1; extra == 'notebooks'
Requires-Dist: jupyterlab>=4.2; extra == 'notebooks'
Requires-Dist: trame-vtk; extra == 'notebooks'
Requires-Dist: trame-vuetify; extra == 'notebooks'
Requires-Dist: trame>=3.6; extra == 'notebooks'
Provides-Extra: viz
Requires-Dist: brainspace; extra == 'viz'
Requires-Dist: hippomaps; extra == 'viz'
Requires-Dist: hippunfold-plot; extra == 'viz'
Requires-Dist: open3d>=0.19; (python_version < '3.13') and extra == 'viz'
Requires-Dist: scienceplots>=2.1; extra == 'viz'
Requires-Dist: vedo>=2024.5; extra == 'viz'
Requires-Dist: yabplot; (python_version == '3.11.*') and extra == 'viz'
Description-Content-Type: text/markdown

<p align="center">
  <strong>SpectralBrain</strong><br>
  <em>Spectral Shape Analysis for Brain Structures</em>
</p>

<p align="center">
  <a href="https://pypi.org/project/spectralbrain/"><img src="https://img.shields.io/pypi/v/spectralbrain.svg" alt="PyPI"></a>
  <a href="https://pypi.org/project/spectralbrain/"><img src="https://img.shields.io/pypi/pyversions/spectralbrain.svg" alt="Python"></a>
  <a href="https://github.com/rdneuro/spectralbrain/actions"><img src="https://github.com/rdneuro/spectralbrain/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
  <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License"></a>
</p>

---

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

## 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.
- **Publication figures** — a template-free six-view 3D renderer (vedo), plus
  unfolded flat-maps, cluster overlays, and Bayesian-posterior plots.

## Installation

```bash
pip install spectralbrain
```

Optional feature sets (extras):

```bash
pip install "spectralbrain[bayesian]"   # PyMC, nutpie, NumPyro, BlackJAX, ArviZ
pip install "spectralbrain[viz]"        # vedo, scienceplots, hippunfold_plot, …
pip install "spectralbrain[gpu]"        # torch, CuPy, JAX (CUDA)
pip install "spectralbrain[neuro]"      # nilearn, dipy, pybids, templateflow, …
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`):

```python
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

```python
import spectralbrain as sb

# A BrainMesh from vertices (N, 3) and faces (M, 3); or sb.io.load(...) a file.
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

```python
d = sb.shapedna_distance(dna_a, dna_b)   # pose-invariant spectral distance
```

### 3 — Vertex-wise group statistics with FWER control

```python
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)

```python
auc_new, auc_ref, p = sbstats.auc_comparison_delong(y_true, scores_new, scores_ref)
```

### 5 — Six-view 3D render (template-free)

```python
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]`)

```python
from spectralbrain.statistics import HorseshoeRegression

model = HorseshoeRegression(tau_prior=0.5).fit(X, y, sampler="nuts")
importance = model.feature_importance()   # sparse posterior shrinkage
```

## Loading a cohort

```python
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:

```python
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"`.

## 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 |

## Development

```bash
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 (a JOSS paper is in
preparation; until then cite the repository and release DOI). See
[`CITATION.cff`](CITATION.cff).

## License

MIT — see [`LICENSE`](LICENSE).
