omics.co.in

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.

The Two Fundamental Spatial Methodologies
  • 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")
← Return to Home Hub Scroll to Top ↑