09 空间转录组学
09 空间转录组学
空间转录组在 scRNA-seq 的基础上保留了一个关键维度:每条表达信号来自切片的哪个位置。不同技术的空间分辨率差别很大:10x Visium 把组织打在微珠芯片上,每个 spot 约 55 μm 包含数个细胞;Slide-seq、MERFISH、seqFISH+ 能做到单细胞或亚细胞分辨率,代价是数据量更大、分析工具更专。
本节用 10x Visium 小鼠脑数据演示最常用的一条流程:读入 → 质控 → 空间感知标准化(SCT)→ 聚类 → 空间变异基因 → 与参考 scRNA-seq 数据做 cell type 反卷积。
主流空间技术对比
| 技术 | 分辨率 | 数据量 | 常用工具 |
|---|---|---|---|
| 10x Visium | spot(~55 μm) | 中等 | Seurat、Scanpy + Squidpy |
| Slide-seq V2 | ~10 μm | 中等 | Seurat、RCTD |
| Stereo-seq | 亚微米 | 大 | StereoPy |
| MERFISH / seqFISH+ | 单细胞 | 大 | Squidpy、Giotto |
| Xenium | 亚细胞 | 大 | 10x pipeline、Seurat |
Visium 仍然是门槛最低的选择:一张切片产出的 spot 数在几千级,普通笔记本能直接分析,教材、社区工具链也最完整。
用 Seurat 分析 Visium 小鼠脑
从 10x Genomics 下载 Visium 小鼠脑切片数据后(或用 SeuratData 里的 stxBrain),基本流程和 scRNA-seq 很像,只是多了 spatial 这一层坐标和组织图片:
library(Seurat)
# 若要一键获取示例数据:
# InstallData("stxBrain")
# brain <- LoadData("stxBrain", type = "anterior1")
# 或者从本地目录读取
brain <- Load10X_Spatial(
data.dir = "~/biof3-data/visium-mouse-brain/outs",
filename = "filtered_feature_bc_matrix.h5",
assay = "Spatial",
slice = "slice1"
)
# 质控:在组织图上看每个 spot 的总表达量
VlnPlot(brain, features = "nCount_Spatial", pt.size = 0.1) + NoLegend()
SpatialFeaturePlot(brain, features = "nCount_Spatial")
两张 QC 图放一起看:有没有"测序偏低的区域"集中在切片边缘(组织脱落),或者局部异常高(气泡、污染)。
标准化这一步建议用 SCTransform,它对 spot 间差异较大的空间数据表现稳定:
brain <- SCTransform(brain, assay = "Spatial", verbose = FALSE)
brain <- RunPCA(brain, assay = "SCT")
brain <- FindNeighbors(brain, reduction = "pca", dims = 1:30)
brain <- FindClusters(brain, verbose = FALSE)
brain <- RunUMAP(brain, reduction = "pca", dims = 1:30)
# 聚类结果同时画在 UMAP 和组织切片上
DimPlot(brain, label = TRUE)
SpatialDimPlot(brain, label = TRUE, label.size = 3)
小鼠脑 Visium 在 SpatialDimPlot 里会呈现皮层、海马、胼胝体等解剖结构对应的聚类,不做任何 cell type 注释也能看出大致分区。
空间变异基因
常规的 FindVariableFeatures 只考虑表达变异,不考虑位置。空间变异基因是"表达分布不是随机的",通常也是真正有解剖学意义的基因:
brain <- FindSpatiallyVariableFeatures(
brain,
assay = "SCT",
features = VariableFeatures(brain)[1:1000],
selection.method = "moransi"
)
top_features <- head(
SpatiallyVariableFeatures(brain, selection.method = "moransi"),
6
)
SpatialFeaturePlot(brain, features = top_features, ncol = 3, alpha = c(0.1, 1))
"moransi"(Moran's I)衡量的是邻近 spot 的表达相似度,值越高说明越空间聚集。alpha 是作图参数,用来突出高表达区域、弱化背景。
把 scRNA-seq 当作参考做反卷积
Visium 的每个 spot 通常包含多个细胞,直接做 cell type 注释会模糊。常用做法是把已经注释好的 scRNA-seq 数据当参考,把 spot 内的细胞组成估出来。常用工具有 RCTD、SPOTlight、CARD:
# SPOTlight 示例(输入:scRNA 参考 + Visium 对象)
library(SPOTlight)
sc_ref <- readRDS("pbmc_reference.rds") # 假设已分析并注释
markers <- Seurat::FindAllMarkers(sc_ref)
spotlight_res <- SPOTlight(
x = sc_ref,
y = brain,
groups = sc_ref$cell_type,
mgs = markers
)
plotSpatialScatterpie(
x = brain,
y = spotlight_res,
cell_types = unique(sc_ref$cell_type),
img = FALSE
)
得到的 scatterpie 在每个 spot 位置画一个小饼图,显示各 cell type 的估计比例。常见验证方式:查看某种 cell type 的比例在组织切片上是否和已知解剖学位置一致。
用 Scanpy + Squidpy 做 Python 版
Python 生态下 scanpy 配合 squidpy 可以覆盖类似流程,并提供更丰富的空间统计(nhood enrichment、co-occurrence 等):
import scanpy as sc
import squidpy as sq
adata = sc.read_visium("~/biof3-data/visium-mouse-brain/outs")
adata.var_names_make_unique()
sc.pp.calculate_qc_metrics(adata, inplace=True)
sc.pl.spatial(adata, color="total_counts")
sc.pp.normalize_total(adata, inplace=True)
sc.pp.log1p(adata)
sc.pp.highly_variable_genes(adata, flavor="seurat", n_top_genes=2000)
sc.pp.pca(adata)
sc.pp.neighbors(adata)
sc.tl.umap(adata)
sc.tl.leiden(adata)
sc.pl.spatial(adata, color="leiden")
# 空间邻域富集:看哪些 cluster 在空间上彼此相邻
sq.gr.spatial_neighbors(adata)
sq.gr.nhood_enrichment(adata, cluster_key="leiden")
sq.pl.nhood_enrichment(adata, cluster_key="leiden")
Scanpy/Squidpy 侧最适合的场景是高分辨率空间数据(Stereo-seq、MERFISH),它们对大矩阵更友好。Visium 级别数据两套都能跑,选择看个人生态。