Squidpy: Spatial Transcriptomics
SkillDev toolsAnalyzes spatial transcriptomics with squidpy (1.8.x) on AnnData and SpatialData objects, routing platforms correctly: Visium spots use spatial_neighbors(coord_type='grid') and pair with deconvolution, while Xenium/MERFISH single-cell data use coord_type='generic'/Delaunay neighbors and spatialdata-io readers (xenium, visium_hd, merscope). Runs sq.gr.spatial_neighbors, nhood_enrichment, co_occurrence, spatial_autocorr (Moran's I for spatially variable genes), ripley, and ligrec. Use when the user wants spatial transcriptomics, squidpy, Visium/Xenium/MERFISH analysis, neighborhood enrichment, co-occurrence, or spatially variable genes; QC/clustering uses alterlab-scanpy and spot deconvolution (destVI/Tangram) uses alterlab-scvi-tools. Part of the AlterLab Academic Skills suite.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Squidpy: Spatial Transcriptomics skill
What this skill tells your AI
The instructions your AI receives, as published by alterlab-ieu/alterlab-academic-skills in skills/bioinformatics/alterlab-squidpy-spatial/SKILL.md and read by ahel’s review.
Squidpy is the scverse toolkit for spatially-resolved omics, built on AnnData and
SpatialData. It answers questions a non-spatial scRNA-seq pipeline cannot: which
cell types sit next to which (neighborhood enrichment), how cell-type pairs
co-occur across distance (co-occurrence), which genes vary across tissue space
(Moran's I / spatially variable genes), and what ligand-receptor signalling is
plausible (ligrec). This skill does the spatial analysis; it hands non-spatial
QC/clustering to alterlab-scanpy and spot deconvolution to alterlab-scvi-tools.
When to Use This Skill
Use when the request involves:
- Spatial transcriptomics / spatially-resolved omics on Visium, Visium HD, Xenium, MERFISH/MERSCOPE, or CosMx data.
- Building a spatial neighbor graph and running neighborhood enrichment, co-occurrence, interaction matrix, Ripley's statistics, or centrality scores.
- Finding spatially variable genes via Moran's I (
spatial_autocorr) or Sepal. - Ligand-receptor analysis in a spatial context (
ligrec). - Reading platform output into AnnData/SpatialData and choosing the right
coord_typefor the platform.
Does NOT Trigger
| Request | Route to |
|---|---|
| Non-spatial scRNA-seq QC, normalization, PCA/UMAP, Leiden clustering, marker genes | alterlab-scanpy |
| Spot deconvolution / mapping cell types to Visium spots (destVI, Tangram), probabilistic batch correction/integration | alterlab-scvi-tools (see its references/models-spatial.md) |
Building/slicing/concatenating .h5ad AnnData objects, layer & obsm wrangling (no spatial analysis) | alterlab-anndata |
| RNA-velocity / trajectory dynamics | alterlab-scvelo |
| Bulk RNA-seq differential expression from a count matrix | alterlab-pydeseq2 |
| Raw FASTQ → expression matrix (read alignment/quantification) | alterlab-rnaseq-quant |
| Diversity / ecology statistics on a feature table | alterlab-scikit-bio |
If the user wants the whole pipeline ("cluster my Xenium data, then find which
cell types are neighbors"), run the scanpy clustering step under alterlab-scanpy
first, then return here for the spatial graph and enrichment.
The One Decision That Matters: Platform → coord_type
Squidpy's spatial graph depends on the measurement geometry. Getting coord_type
wrong silently produces a meaningless graph. (All parameter behavior below is from
the squidpy 1.8 sq.gr.spatial_neighbors API.)
| Platform | Resolution | Builder | Pair with |
|---|---|---|---|
| Visium | spot (multi-cell, hex grid) | coord_type="grid", n_neighs=6, n_rings=1..2 | deconvolution → alterlab-scvi-tools |
| Visium HD | 2/8/16 µm bins (square grid) | coord_type="grid" (square lattice) | binning choice up front |
| Xenium / MERFISH / CosMx | single cell | coord_type="generic", delaunay=True (or n_neighs=k) | direct cell-type analysis |
coord_type=Noneauto-picks"grid"only whenspatialis inadata.unswithn_neighs=6(the Visium signature); otherwise it falls back to"generic". Setcoord_typeexplicitly rather than relying on auto-detection.delaunay=Trueis only used whencoord_type="generic"; it builds the graph from a Delaunay triangulation instead of k-nearest spots.n_ringsis only used forcoord_type="grid".
Loading Data (pick the reader for the platform)
import squidpy as sq
import scanpy as sc
# Visium (legacy spot data) — squidpy's own reader, returns AnnData
adata = sq.read.visium("path/to/visium_outs/")
# Vizgen MERSCOPE / Nanostring CosMx via squidpy readers
adata = sq.read.vizgen("path/to/merscope/", counts_file="cell_by_gene.csv",
meta_file="cell_metadata.csv")
adata = sq.read.nanostring("path/to/cosmx/", counts_file="exprMat_file.csv",
meta_file="metadata_file.csv", fov_file="fov_positions.csv")
For Xenium and Visium HD, use the spatialdata-io readers (squidpy has no
sq.read.xenium) and operate on a SpatialData object:
from spatialdata_io import xenium, visium_hd, merscope
sdata = xenium("path/to/xenium_outs/") # 10x Xenium
sdata = visium_hd("path/to/visium_hd_outs/") # 10x Visium HD
sdata = merscope("path/to/merscope/") # Vizgen MERSCOPE
spatialdata-io reader names are verified against the spatialdata-io stable API.
Squidpy 1.8 accepts SpatialData objects directly; see
references/spatialdata_io.md for the SpatialData ↔ AnnData (table) flow.
Standard Spatial Workflow
QC, normalization, HVGs, PCA, neighbors, Leiden, and sc.tl.umap are scanpy
steps — run them via alterlab-scanpy. Once you have clusters / cell-type labels,
do the spatial part here.
import squidpy as sq
# 1. Build the spatial neighbor graph (choose coord_type per the table above)
sq.gr.spatial_neighbors(adata, coord_type="generic", delaunay=True) # Xenium/MERFISH
# sq.gr.spatial_neighbors(adata, coord_type="grid", n_neighs=6) # Visium
# 2. Neighborhood enrichment: which cluster pairs are spatially adjacent?
sq.gr.nhood_enrichment(adata, cluster_key="leiden")
sq.pl.nhood_enrichment(adata, cluster_key="leiden")
# 3. Co-occurrence across distance
sq.gr.co_occurrence(adata, cluster_key="leiden")
sq.pl.co_occurrence(adata, cluster_key="leiden", clusters="0")
# 4. Spatially variable genes via Moran's I
sq.gr.spatial_autocorr(adata, mode="moran")
svgs = adata.uns["moranI"].head(20) # ranked by Moran's I
# 5. Ligand-receptor interaction (Omnipath-backed)
sq.gr.ligrec(adata, cluster_key="leiden")
Other graph statistics: sq.gr.interaction_matrix, sq.gr.centrality_scores,
sq.gr.ripley (clustering/dispersion vs. CSR), and sq.gr.sepal (an alternative
spatially-variable-gene test). Visualize tissue with sq.pl.spatial_scatter
(spot/point) or sq.pl.spatial_segment (segmented cells). For image features on
H&E/IF, the sq.im module (process, segment, calculate_image_features)
operates on an ImageContainer.
Helper script — build the graph and run the core statistics in one call:
uv run python skills/bioinformatics/alterlab-squidpy-spatial/scripts/spatial_neighborhood.py \
clustered.h5ad --platform xenium --cluster-key leiden --out spatial_report.json
See scripts/spatial_neighborhood.py --help. It chooses coord_type from
--platform, runs spatial_neighbors, nhood_enrichment, co_occurrence, and
spatial_autocorr, and writes a JSON summary (top spatially variable genes + the
enrichment z-score matrix) plus the updated .h5ad.
Deeper References
references/platform_routing.md— full platform→coord_typedecision table, then_neighs/n_rings/delaunayparameter semantics, and per-platform gotchas.references/analysis_recipes.md— copy-paste recipes for eachsq.gr/sq.plfunction with the parameters that matter and how to read the outputs.references/spatialdata_io.md— reading Xenium / Visium HD / MERSCOPE into SpatialData and getting the AnnDatatablesquidpy operates on.
Self-Check Before Reporting
- Did you set
coord_typeto match the platform (grid for Visium, generic for single-cell)? A wrong graph invalidates every downstream statistic. - Did clustering/QC run under
alterlab-scanpy(this skill assumes labels exist)? - For Visium spot data, did you flag that deconvolution (
alterlab-scvi-tools) is needed before cell-type-level claims — spots are multi-cell? - Are
nhood_enrichmentz-scores reported with the permutation context, not as raw counts?
Part of the AlterLab Academic Skills suite.
Signals
- GitHub stars
- 66
- Forks
- 13
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
alterlab-squidpy-spatial- Source
- github.com/alterlab-ieu/alterlab-academic-skills