spanormpy
A faithful Python / scverse port of the R package
SpaNorm (spatially-aware normalisation for spatial
transcriptomics data). It operates on AnnData (and optionally SpatialData) with a PyTorch
backend that runs on CPU and CUDA (Apple Metal in float32).
Documentation: https://bhuvalab.github.io/SpaNorm/ (one site covering both the R package and spanormpy, with side-by-side R and Python tutorials and the API reference for each).
Version 0.1.0 (beta). Ports SpaNorm 1.7.16 (R commit f233b7b, Bioconductor devel); see CHANGELOG.md.
Install
pip install spanormpy
pip install git+https://github.com/BhuvaLab/spanormpy # development version
Optional extras: pip install "spanormpy[spatial]" for SpatialData input and
pip install "spanormpy[dev]" for the test and tutorial tools. For a GPU, install the CUDA build of
PyTorch first (see https://pytorch.org), then use backend="gpu" or the default backend="auto".
See docs/benchmark.md (about 2.7x faster spanorm on an H100 MIG slice).
Quickstart
import anndata as ad
import spanormpy as sn
adata = ad.read_h5ad("visium.h5ad") # raw counts in X, coordinates in obsm["spatial"]
sn.filter_genes(adata, prop=0.2) # keep genes expressed in >= 20% of spots (in place)
sn.spanorm(adata) # normalised data -> adata.layers["logcounts"]
sn.pl.plot_spatial(adata, what="expression", color="MOBP", layer="logcounts")
sn.spanorm_svg(adata) # spatially variable genes -> adata.var["svg_*"]
sn.top_svgs(adata, n=10)
sn.spanorm_pca(adata) # GLM-PCA approximation -> adata.obsm["X_spanorm_pca"]
sn.polish_spanorm(adata) # optional: converge every gene separately
The fit is stored in the object (var, varm, obsm, and scalars in uns["spanorm"]), so
re-running with another adj_method only redoes the adjustment. A full walk-through is in
docs/tutorial.ipynb (a squidpy mouse-brain Visium walk-through of the R vignette; the HumanDLPFC version identical to the R vignette is on the website). Every R export and its Python
name are listed in docs/r-to-python.md.
Differences from R
The full list, with reasons, is in docs/r-discrepancies.md. The intentional ones:
- Gene subsets reuse the stored fit (a deviation). R refits when the object is subset by genes
(
fit$ngenes != nrow). Afteradata[:, genes],spanorminstead reuses the matching slice of the stored fit (as R'ssubsetFitGeneswould), which equals R's adjustment of the full fit on those genes;overwrite=Truereproduces R's refit. A spot subset refits, as in R.polish_spanormandspanorm_svghave their own subset rules (see the discrepancies page). Views are converted to real objects without a warning. - Explicit
size_factorsargument. Pass size factors directly;obs["size_factors"]is never read implicitly. - Default pipeline matches R only approximately. Default size factors come from a built-in scran-like
method (own
quick_cluster) written toobs["spanorm_size_factors"], and spot sampling uses a numpy RNG (random_statereplacesset.seed). Results agree with R to numerical closeness; exact parity is obtained when R's size factors and sampling are supplied. - Adjustment honours
backend. R's adjustment step uses any available accelerator regardless of the requested backend; herebackend="cpu"keeps everything on the CPU. logcountsfollows the input.layers["logcounts"]is dense for dense counts and sparse for sparse counts (R always stores sparse).n_jobsreplacesBPPARAM.
Download statistics
The badges above show download counts from PyPI (via pepy.tech) and conda-forge. They appear once the package is published there. spanormpy contains no telemetry and makes no network calls.
Citation
Salim A, Bhuva DD, Chen C, Tan CW, Yang P, Davis MJ, Yang JYH. SpaNorm: spatially-aware normalization for spatial transcriptomics data. Genome Biology 2025, 26(1):109. doi:10.1186/s13059-025-03565-y
Licence
GPL-3.0-or-later, as for SpaNorm.
Metadata
Release files for spanormpy 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| spanormpy-0.1.0.tar.gz | 1.3 MB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| spanormpy-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.4 MB
Release files / spanormpy-0.1.0.tar.gz
| Download URL | spanormpy-0.1.0.tar.gz |
|---|---|
| Size | 1.3 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d0664777ff9557a1f23ac23493876bebc3db21449a3d697709addff8084dada4
|
|
BLAKE2b-256 checksum How to use checksums |
822ead38b54a4816efe091d2a32799ff62d775c00152474c71112e58b5c020f3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 22, 2026.
Transparency logRelease files / spanormpy-0.1.0-py3-none-any.whl
| Download URL | spanormpy-0.1.0-py3-none-any.whl |
|---|---|
| Size | 146.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f4a4324e4524e399fb40c173ff9427c3f641ae89c5f77e3bd918a1b0019a80e7
|
|
BLAKE2b-256 checksum How to use checksums |
7782f2518608cdbb4d8561d3fb88222324c04a82796a3d64dca1faf7f67611f6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 22, 2026.
Transparency logSecurity for spanormpy 0.1.0
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.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for spanormpy-0.1.0.tar.gz
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 22, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.