Skip to main content

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.

License: BSD-3-Clause Python: 3.9+


What it does

Given a single-cell embedding (typically PCA or Concord) and Leiden cluster labels, sctopo runs the following pipeline per cluster:

  1. Per-cluster persistent homology. Compute Vietoris–Rips persistent homology on the cluster's embedding (Ripser).

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

  3. Critical-edge cycle recovery. For each surviving class, extract a representative cycle via shortest-path on the 1-skeleton.

  4. Circular coordinates. Assign a continuous angle θ ∈ [0, 2π) to every topocell (cells in a neighborhood of the cycle) using DREiMac.

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

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

Metadata

Release files for sctopo 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sctopo 0.1.0
File Size Uploaded
sctopo-0.1.0.tar.gz 43.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sctopo 0.1.0
File Interpreter ABI Platform
sctopo-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 86.2 kB

Release files / sctopo-0.1.0.tar.gz

Download URL sctopo-0.1.0.tar.gz
Size 43.2 kB
Tags Source
SHA-256 checksum
How to use checksums
bde4fb8095437e0d85a8d424fbc789aaa0aa399b21570babd22025c48091c6d0
BLAKE2b-256 checksum
How to use checksums
2defa581c0568d230ffa30e1559f20d9e06ff74cb6d4c50f23382db10a667cfa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.4

Release files / sctopo-0.1.0-py3-none-any.whl

Download URL sctopo-0.1.0-py3-none-any.whl
Size 43.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
63b95f5b019922c98928ac5d8c6d96b253ecc00ff84f50433fec9f095be23ec4
BLAKE2b-256 checksum
How to use checksums
a6d786128cccaa7a9726c6557b22bb597acb9b7ea5c642081c87dd4c45ef28f6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.4

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page