By Lociven · SpatiaBio · August 2026
Finding genes that vary spatially — not just between clusters, but continuously across tissue — is one of the core tasks in spatial transcriptomics. SpatialDE2 is the current standard for this. It's faster than its predecessor, handles Visium HD and single-cell resolution data, and gives you interpretable spatial patterns. This post covers how it works and how to run it.
What is a spatially variable gene?
A spatially variable gene (SVG) is a gene whose expression level is not randomly distributed across tissue — it shows spatial structure. That structure might be a sharp boundary (tumor vs stroma), a gradient (hypoxia from center to edge), or a periodic pattern (cortical layers in brain).
Standard differential expression tests (comparing cluster A vs cluster B) can find SVGs indirectly, but they depend on your clustering choices. SpatialDE2 tests for spatial variation directly, without needing predefined clusters, using a Gaussian process model.
SpatialDE2 vs Moran's I: Moran's I (available in Squidpy via sq.gr.spatial_autocorr) is faster and good for a quick screen. SpatialDE2 is slower but models the spatial covariance structure more accurately and provides pattern classification (linear gradient, periodic, etc.).
Installation
pip install SpatialDE # SpatialDE2 requires Python 3.9+ and JAX pip install jax jaxlib pip install git+https://github.com/PMBio/SpatialDE.git
Running SpatialDE2
import squidpy as sq
import scanpy as sc
import SpatialDE
import numpy as np
import pandas as pd
# Load and prepare Visium data
adata = sq.read.visium("path/to/visium/")
sc.pp.filter_genes(adata, min_cells=3)
sc.pp.normalize_total(adata, target_sum=1e4)
sc.pp.log1p(adata)
# Use highly variable genes to limit runtime
sc.pp.highly_variable_genes(adata, n_top_genes=2000)
adata_hvg = adata[:, adata.var["highly_variable"]].copy()
# Get spatial coordinates
coords = pd.DataFrame(
adata_hvg.obsm["spatial"],
columns=["x", "y"],
index=adata_hvg.obs_names
)
# Expression matrix (spots x genes)
expr = pd.DataFrame(
adata_hvg.X.toarray() if hasattr(adata_hvg.X, "toarray") else adata_hvg.X,
index=adata_hvg.obs_names,
columns=adata_hvg.var_names
)
# Run SpatialDE2
results = SpatialDE.run(coords, expr)
results = results.sort_values("qvalue")
print(results.head(10)[["g", "l", "qvalue", "FSV"]])
Key output columns:
g— gene namel— estimated spatial length scale (how broad the pattern is)qvalue— FDR-adjusted p-value for spatial variationFSV— fraction of variance explained by spatial structure (0–1; higher = more spatially structured)
The difference in one view. Left: Moran's I returns a ranking — these are the real top genes from the mouse-brain dataset (top 500 HVGs, n_perms=200). Right: a single score cannot distinguish a compact hotspot from a smooth gradient; all three shapes can score high. Classifying the pattern is what SpatialDE2's Gaussian-process test adds, and what the extra runtime pays for.
Pattern classification with SPARK-X
SpatialDE2 classifies SVGs into spatial patterns: linear gradients, radial patterns, and periodic patterns. For most tissue sections, linear and radial patterns dominate. Periodic patterns are most relevant in brain (cortical layers) and intestine (crypt-villus axis).
# Get top SVGs
sig_results = results[results["qvalue"] < 0.05].sort_values("FSV", ascending=False)
top_svgs = sig_results["g"].head(20).tolist()
print(f"Significant SVGs: {len(sig_results)}")
print(f"Top 5 by FSV:\n{sig_results[['g','FSV','l']].head()}")
# Visualize top SVGs on tissue
sq.pl.spatial_scatter(
adata,
color=top_svgs[:4],
ncols=2,
cmap="magma",
size=1.5
)
Quick alternative: Moran's I in Squidpy
If you need a fast screen before committing to SpatialDE2, Squidpy's sq.gr.spatial_autocorr with Moran's I runs in minutes on a full Visium dataset:
sq.gr.spatial_neighbors(adata, coord_type="grid", n_rings=2)
sq.gr.spatial_autocorr(adata, mode="moran", genes=adata.var_names[adata.var.highly_variable])
# Top spatially autocorrelated genes
top_morans = (
adata.uns["moranI"]
.sort_values("I", ascending=False)
.head(20)
)
print(top_morans[["I", "pval_norm_fdr_bh"]])
Use Moran's I to screen, then run SpatialDE2 on the top candidates for pattern classification and accurate FSV estimates.
Get the complete pack
SpatiaBio Pack 2 — Deconvolution & Spatial Pattern Detection
The full SpatialDE2 spatial pattern classification notebook — Moran's I screening, hotspot/gradient pattern detection, and spatial co-expression modules. Plus a cell2location deconvolution notebook.
Get it for $19 →From the NeoantigenLab sister blog
Using spatial data for cancer immunology research?
NeoantigenLab covers neoantigen biology, pVACseq, HLA typing, and checkpoint inhibitors — the biology behind your spatial findings.
Visit NeoantigenLab →Tags: SpatialDE2, spatially variable genes, SVG, Moran's I, spatial autocorrelation, Visium, Squidpy, Gaussian process, spatial transcriptomics
No comments:
Post a Comment