Tuesday, June 30, 2026

Squidpy vs Seurat for Spatial Transcriptomics: Which Tool Should You Use in 2026?

Introduction

If you're starting a spatial transcriptomics project in 2026, you've probably run into the same fork in the road every single-cell person eventually hits: Seurat or Squidpy? Both are mature, well-maintained, and backed by active communities — but they come from different ecosystems (R vs Python) and take different philosophical approaches to spatial data.

This isn't a "which one is objectively better" post. It's a practical breakdown of where each tool actually shines, based on what each is built for — so you can pick the right one for your pipeline instead of just going with whatever your lab used last.

To make this concrete instead of just theoretical, I actually ran Squidpy's core spatial workflow end-to-end on a real public dataset (squidpy's mouse brain Visium demo) and reported the real numbers below — not just textbook claims.

Quick Comparison

Seurat Squidpy
Language R Python
Core strength scRNA-seq + spatial integration Spatial-first, neighborhood/graph analysis
Best for Labs already in R/Bioconductor ecosystem Pipelines needing scanpy/AnnData compatibility
Spatial stats Basic (SpatialFeaturePlot, cluster overlay) Advanced (Moran's I, neighborhood enrichment, ligand-receptor via squidpy.gr)
Learning curve Lower if you know R Lower if you know scanpy
GitHub stars (as of 2026) ~2.8k ~580
Integration Seurat objects, SeuratDisk AnnData, works natively with scvi-tools

When Seurat Makes Sense

  • Your lab's existing scRNA-seq pipeline is already in Seurat — switching ecosystems mid-project has a real cost
  • You need quick, publication-ready spatial overlay plots without much custom code
  • You're working with 10x Visium data and want the well-documented Load10X_Spatial() workflow
library(Seurat)
library(SeuratData)

brain <- LoadData("stxBrain", type = "anterior1")
brain <- SCTransform(brain, assay = "Spatial", verbose = FALSE)
brain <- RunPCA(brain, assay = "SCT", verbose = FALSE)
brain <- FindNeighbors(brain, reduction = "pca", dims = 1:30, verbose = FALSE)
brain <- FindClusters(brain, verbose = FALSE)
SpatialDimPlot(brain, label = TRUE)

Real output from this run (Seurat 5.5.1, R 4.6.1, SeuratData's stxBrain mouse brain Visium dataset — the official Seurat demo, conceptually the same tissue type as the squidpy demo below):

  • Dataset loaded: 31,053 genes × 2,696 spots
  • SCTransform took ~273 seconds (4.5 minutes) on this machine
  • Clustering (FindNeighbors + FindClusters) took only ~3.4 seconds after that — the bottleneck is entirely in SCTransform, not clustering
  • 15 clusters were identified, matching well with visually distinct anatomical regions in the tissue image
  • One real gotcha we hit: SCTransform printed a warning that it couldn't find the glmGamPoi package and fell back to a slower native implementation. Installing glmGamPoi via Bioconductor first is a meaningful speedup for anyone running this regularly — we didn't have it installed for this run, which is reflected in the ~273s figure above.
Seurat SpatialDimPlot showing 15 clusters identified in mouse brain Visium tissue

Seurat's spatial cluster plot on the official stxBrain demo dataset — real output from the code above, not a mockup.

(This workflow follows Seurat's official Visium tutorial structure — Seurat workflows for Visium data are extensively documented and battle-tested across thousands of published studies, which is itself part of Seurat's value: you're rarely the first person debugging a given step.)

When Squidpy Makes Sense

  • You need actual spatial statistics — neighborhood enrichment, co-occurrence, Moran's I autocorrelation — not just visualization
  • Your downstream pipeline is Python-based (e.g., feeding into scvi-tools or a custom ML model)
  • You're working with multiple spatial modalities (Visium, MERFISH, Xenium) and want one consistent API via AnnData
import squidpy as sq
import scanpy as sc

# Built-in public demo dataset (mouse brain, Visium)
adata = sq.datasets.visium_hne_adata()

sq.gr.spatial_neighbors(adata)
sq.gr.nhood_enrichment(adata, cluster_key="cluster")
sq.gr.co_occurrence(adata, cluster_key="cluster")
Spatial cluster distribution in mouse brain Visium dataset, generated with sq.pl.spatial_scatter

Spatial distribution of the 15 annotated brain regions, plotted directly from the squidpy run above.

Real output from this run (squidpy 1.x, mouse brain Visium demo dataset, 2,688 spots × 18,078 genes, 15 annotated regions including Cortex_1–5, Hippocampus, Thalamus_1–2, Striatum, etc.):

  • spatial_neighbors + nhood_enrichment completed in ~9.5 seconds on the full 2,688-spot dataset
  • co_occurrence completed in ~6.7 seconds
  • Neighborhood enrichment z-scores ranged up to ~78, meaning some region pairs (e.g. cortical layers next to each other) show very strong spatial co-localization — exactly the kind of signal Seurat's basic spatial plots won't quantify for you directly
  • One practical gotcha I hit: sq.gr.spatial_neighbors throws a FutureWarning as of squidpy 1.x — it's being split into spatial_neighbors_knn / _radius / _delaunay / _grid in v1.9. If you're starting a new project now, it's worth using the specific function instead of the generic one to avoid a breaking change later.
Neighborhood enrichment z-score heatmap between brain regions, generated with sq.pl.nhood_enrichment

Neighborhood enrichment z-scores between region pairs — darker/brighter cells indicate stronger spatial co-localization.

(Tested on squidpy's public demo dataset, not proprietary research data — same workflow applies to your own Visium/MERFISH/Xenium data via sq.read.visium() or the equivalent reader.)

The Honest Answer

If you're already deep in the R/Bioconductor world and just need solid visualization + basic spatial clustering, Seurat won't slow you down. If your work leans toward quantitative spatial statistics or you're building anything that touches a Python ML stack, Squidpy's purpose-built spatial functions save you from reinventing the wheel.

Based on actually running the Squidpy workflow above, the value isn't in the plots — it's in the quantified output (z-scores, co-occurrence stats) you can directly use in a paper or downstream model. That's the gap Seurat's spatial functions don't close on their own.

FAQ

Can I use both in the same project? Yes — many labs preprocess in Seurat, export via SeuratDisk to AnnData, then run Squidpy's spatial stats.

Does Squidpy work with non-10x platforms like MERFISH or Xenium? Yes, Squidpy has built-in readers for multiple spatial platforms, which is one of its main advantages over Seurat's more Visium-centric workflow.

Is one faster than the other for large datasets? We ran both on a similar-sized dataset (~2,700 spots) on the same machine. Squidpy's spatial graph + neighborhood enrichment finished in under 10 seconds. Seurat's SCTransform alone took ~273 seconds, though clustering after that was fast (~3.4s). Important caveat: these aren't doing identical work — SCTransform is a normalization step with no direct Squidpy equivalent in our comparison, so this isn't a clean apples-to-apples benchmark, just real numbers from real runs of each tool's typical workflow. Installing glmGamPoi would likely cut Seurat's SCTransform time significantly; we ran without it.


Last updated: June 2026. Tool versions referenced: Seurat 5.x, Squidpy 1.x — always check current documentation as APIs evolve.

Get the complete pack

Squidpy Complete Analysis Pack — 10 Notebooks

All 10 notebooks from this series in one download — SVGs, neighborhood enrichment, co-occurrence, ligand-receptor, and the complete pipeline. Verified and ready to run on your own data.

Get it for $19 →

No comments:

Post a Comment

I Gave Claude Science One Prompt. It Ran a Full Spatial Analysis.

By Lociven · SpatiaBio · July 2, 2026 I gave Claude Science AI Workbench — Anthropic's new scientific analysis platform — a single...