Chapter 13: Spatial Transcriptomics: 10x Visium, Xenium, MERFISH & Stereo-seq
Chapter 13: Spatial Transcriptomics: 10x Visium, Xenium, MERFISH & Stereo-seq
While scRNA-seq reveals what cell types exist within a tissue, it destroys the physical spatial architecture during tissue dissociation. Spatial transcriptomics preserves the intact tissue context, resolving gene expression alongside histological H&E or immunofluorescence images to map cellular microenvironments, tumor-stroma borders, and spatial cell-cell niches.
- Sequencing-Based Spatial Capture (10x Visium, Slide-seq, Stereo-seq): Tissue sections are placed on slides patterned with spatially barcoded capture spots (e.g. 55 \(\mu\)m diameter spots in 10x Visium, or submicron spots in Stereo-seq). Captures the entire unbiased transcriptome across multi-cell spots.
- Imaging-Based In Situ Profiling (10x Xenium, CosMx, MERFISH): Cyclic fluorescent hybridization or sequencing directly on tissue slices. Delivers subcellular single-molecule resolution (hundreds to thousands of pre-selected genes) without cell deconvolution needed.
1. Analyzing 10x Visium Data in Seurat
library(Seurat)
library(ggplot2)
# Load 10x Visium spatial directory containing H&E image and matrix
visium_brain <- Load10X_Spatial(
data.dir = "visium_mouse_brain/",
filename = "filtered_feature_bc_matrix.h5"
)
# Normalize spatial data using SCTransform
visium_brain <- SCTransform(visium_brain, assay = "Spatial", verbose = FALSE)
# Run PCA, UMAP, and spatial clustering
visium_brain <- RunPCA(visium_brain, assay = "SCT", verbose = FALSE)
visium_brain <- FindNeighbors(visium_brain, reduction = "pca", dims = 1:30)
visium_brain <- FindClusters(visium_brain, resolution = 0.8)
# Visualize clusters overlaid directly on histological tissue slice
SpatialDimPlot(visium_brain, label = TRUE, label.size = 3)
# Visualize specific spatial marker gene expression
SpatialFeaturePlot(visium_brain, features = c("Snap25", "Mbp", "Gfap"))2. Spot Deconvolution with RCTD & cell2location
In 10x Visium, each 55 \(\mu\)m spot captures 5–15 cells. To resolve which cell types constitute each spot, Robust Cell Type Decomposition (RCTD) or cell2location uses a matched single-cell reference atlas to deconvolve mixed spot transcriptomes into estimated cell-type proportions.
library(spacexr)
# Format single-cell reference and spatial Visium query
sc_ref <- Reference(counts = sc_counts, cell_types = sc_annotations, n_max_cells_per_type = 500)
spatial_puck <- SpatialRNA(coords = coordinates, counts = visium_counts)
# Run RCTD in full multi-cell mode
myRCTD <- create.RCTD(spatial_puck, sc_ref, max_cores = 8)
myRCTD <- run.RCTD(myRCTD, doublet_mode = 'full')
# Extract cell type weights for each spatial spot
cell_proportions <- myRCTD@results$weights
head(cell_proportions)3. Spatial Variable Genes & Microenvironment Niches
To identify genes with spatially patterned expression (e.g. genes restricted to tumor-invasive fronts or lymphoid aggregates), spatial autocorrelation statistics like Moran's I measure whether expression correlates with physical coordinates.
# Identify spatially variable features using Moran's I in Seurat
visium_brain <- FindSpatiallyVariableFeatures(
visium_brain,
assay = "SCT",
features = VariableFeatures(visium_brain)[1:1000],
selection.method = "moransi"
)
# Top spatially structured genes
top_spatial_genes <- head(SpatiallyVariableFeatures(visium_brain, selection.method = "moransi"), 6)
SpatialFeaturePlot(visium_brain, features = top_spatial_genes, ncol = 3)# Spatial microenvironment neighborhood analysis in Python (Squidpy)
import squidpy as sq
# Build spatial neighborhood graph from coordinates
sq.gr.spatial_neighbors(adata, radius=100, coord_type="generic")
# Co-occurrence analysis of cell types
sq.gr.co_occurrence(adata, cluster_key="cell_type")
sq.pl.co_occurrence(adata, cluster_key="cell_type", clusters="Tumor_Epithelial")
# Compute neighborhood enrichment test
sq.gr.nhood_enrichment(adata, cluster_key="cell_type")
sq.pl.nhood_enrichment(adata, cluster_key="cell_type")