Topological analysis of single-cell data: per-cluster persistent homology and periodicity-based topogene discovery.
Project description
sctopo
Topological analysis of single-cell data. sctopo extracts statistically
significant 1-dimensional homological features (loops) in single-cell
embeddings, scores genes by how strongly their expression is locked to each
loop, and visualizes both geometry and gene-expression structure in three
complementary 3-D views per cycle.
What it does
Given a single-cell embedding (typically PCA or Concord) and Leiden cluster
labels, sctopo runs the following pipeline per cluster:
-
Per-cluster persistent homology. Compute Vietoris–Rips persistent homology on the cluster's embedding (Ripser).
-
Significance filtering. Keep only H1 classes whose persistence exceeds the (1 − α) quantile of a column-permutation null distribution, and whose birth radius is below a quantile of nearest-neighbor distances.
-
Critical-edge cycle recovery. For each surviving class, extract a representative cycle via shortest-path on the 1-skeleton.
-
Circular coordinates. Assign a continuous angle θ ∈ [0, 2π) to every topocell (cells in a neighborhood of the cycle) using DREiMac.
-
Topogene discovery. Rank genes by the amplitude of their circular correlation with θ:
$$r_{\text{circ}}(g) = \sqrt{\,\operatorname{corr}(x_g, \cos\theta)^2 + \operatorname{corr}(x_g, \sin\theta)^2\,}$$
This is the first Fourier-mode amplitude along the cycle. A permutation test gives per-gene p-values and a family-wise significance threshold.
-
Visualization. Three 3-D views per loop (cluster PCA / global UMAP / topogene PCA), plus per-loop matplotlib panels for PDF export.
Installation
git clone https://github.com/binglunshao/sctopo.git
cd sctopo
pip install -e .
Development install:
pip install -e ".[dev]"
Core dependencies: numpy, scipy, scikit-learn, networkx, pandas,
matplotlib, plotly, anndata, scanpy, ripser, persim, dreimac,
torch (legacy gradient scoring only). torch is only required if you
call sctopo.genes.topo_scores_rep_sampling; the default periodicity
scoring is pure NumPy.
Quick start
import anndata as ad
import sctopo.cells as tpc
import sctopo.genes as tpg
import sctopo.viz as tpv
# Load and subset to one cluster
adata = ad.read_h5ad("brain_dev_concord.h5ad")
adata_cluster = adata[adata.obs["leiden"] == "2"].copy()
# 1. Per-cluster PH with significance filtering
X = adata_cluster.obsm["X_pca"]
topological_loops = tpc.critical_edge_method_significant(
X,
n_subsamples=50,
alpha=0.05,
birth_dist_nn_quantile=0.75,
verbose=True,
)
tpv.quick_loop_summary(topological_loops)
# 2. Circular coords + topogenes for each loop
results = []
for i in range(len(topological_loops)):
cc = tpg.get_circular_coords(topological_loops, loop_index=i)
res = tpg.compute_topogenes(
adata_cluster, topological_loops, cc,
loop_index=i, n_genes=100,
)
results.append({"cc": cc, **res})
print(f"Loop {i+1}: top genes = {res['topogenes'][:5]}")
# 3. Per-gene permutation significance
sig = tpg.topogenes_significance(
adata_cluster, topological_loops, results[0]["cc"],
loop_index=0, n_perms=100,
)
print(f"Family-wise α=0.05 threshold: {sig['max_threshold_0p05']:.3f}")
# 4. Visualize
import scanpy as sc
topocell_ixs = topological_loops[0]["topocell_ixs"]
adata_cc = adata_cluster[topocell_ixs, results[0]["topogenes"]].copy()
sc.tl.pca(adata_cc, n_comps=3)
fig = tpv.plot_topocells_subplots(
adata_cluster, adata_cc, topological_loops,
loop_index=0, color_col="phase",
)
fig.show()
A complete walk-through is in notebooks/example_pipeline.ipynb.
Topogene scoring: two methods
sctopo ships two topogene-scoring algorithms. The periodicity method is the
default and recommended choice; the gradient method is preserved for
reproducibility with earlier analyses.
| Periodicity (default) | Gradient (legacy) | |
|---|---|---|
| Function | topo_scores_periodicity |
topo_scores_rep_sampling |
| Definition | √(corr(x, cos θ)² + corr(x, sin θ)²) | ‖∇₍x₎ Σ subsample-cycle-perimeter‖₂ |
| Determinism | Deterministic | Monte-Carlo over n_reps |
| Interpretation | First Fourier amplitude along cycle | Sensitivity of cycle length to expression |
| Dependencies | NumPy + SciPy | PyTorch |
| Per-gene p-value | Yes (cheap permutation) | Yes (more expensive) |
Both methods accept the same arguments and return the same shape of output, so
you can swap via compute_topogenes(..., method="periodicity"|"rep_sampling").
Package layout
sctopo/
├── pp/ preprocessing utilities
│ ├── pca.py gap-based PCA cutoff (sparse-aware)
│ └── outliers.py Isolation Forest on PCA coords
├── cells/ per-cluster PH, significance, loop extraction
│ ├── graph.py VR 1-skeleton construction
│ ├── significance.py permutation null
│ ├── loops.py critical_edge_method[_significant]
│ └── cycle_assign.py project all cells onto a cycle
├── genes/ circular coords + topogene scoring
│ ├── circular_coords.py DREiMac wrapper, circular variance
│ ├── periodicity.py default scoring (Fourier amplitude)
│ ├── rep_sampling.py legacy gradient scoring
│ └── topogenes.py compute_topogenes, topogenes_significance
└── viz/ plotly + matplotlib visualizations
├── cloud.py 3-D topocell views
├── diagrams.py persistence diagrams
└── summary.py text summaries
Citing
If you use sctopo in published work, please cite:
@software{sctopo2026,
author = {Shao, Binglun},
title = {sctopo: topological analysis of single-cell data},
year = {2026},
url = {https://github.com/binglunshao/sctopo},
version = {0.1.0},
}
A paper describing the method is in preparation; please also cite the
underlying tools ripser (Tralie et al. 2018)
and dreimac (Perea et al.).
Acknowledgements
sctopo builds on ideas from an earlier prototype
totopos, developed in
collaboration with Emanuel Flores Bautista. Per-cluster persistent
homology, periodicity-based topogene scoring, permutation-null
significance testing, and the unified visualization API are new in this
package.
License
BSD 3-Clause License. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sctopo-0.1.0.tar.gz.
File metadata
- Download URL: sctopo-0.1.0.tar.gz
- Upload date:
- Size: 43.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bde4fb8095437e0d85a8d424fbc789aaa0aa399b21570babd22025c48091c6d0
|
|
| MD5 |
89a786b9575a63a9f1890a8dc7b43276
|
|
| BLAKE2b-256 |
2defa581c0568d230ffa30e1559f20d9e06ff74cb6d4c50f23382db10a667cfa
|
File details
Details for the file sctopo-0.1.0-py3-none-any.whl.
File metadata
- Download URL: sctopo-0.1.0-py3-none-any.whl
- Upload date:
- Size: 43.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
63b95f5b019922c98928ac5d8c6d96b253ecc00ff84f50433fec9f095be23ec4
|
|
| MD5 |
5d73d3a9cfa54825f76e3560f11c503f
|
|
| BLAKE2b-256 |
a6d786128cccaa7a9726c6557b22bb597acb9b7ea5c642081c87dd4c45ef28f6
|