空间转录组入门:10x Visium 全流程
跟完这篇,您能把一份 10x Visium 空间转录组数据,从 Space Ranger 的原始输出一路做到:读入建对象、按空间特点做质控、聚类并识别空间域、借单细胞参考做去卷积、再找出有空间格局的基因——并且清楚每一步为什么和单细胞不一样、每个中间结果该怎么看。
空间转录组和单细胞最大的区别只有一句话:它多了坐标。每个测到的点都知道自己在组织切片上的位置。于是分析的目标不再只是「有哪些细胞」,而是「什么细胞、什么基因,出现在组织的什么位置」。这条主线贯穿全篇。
流程总览
一个标准的 Visium 分析,就是下面这条流水线。前半段和单细胞很像,但从「空间域」开始,坐标信息才真正被用起来。
| 步骤 | 关键函数 / 工具 | 这一步在做什么 | 常见产出 |
|---|---|---|---|
| 1. 读入建对象 | Load10X_Spatial | 把表达矩阵、坐标、组织图三者读进一个对象 | 带空间信息的 Seurat 对象 |
| 2. 质控 | PercentageFeatureSet / subset | 去掉明显异常的 spot,但别当成单细胞乱滤 | 干净的 spot 集 |
| 3. 标准化 + 聚类 | SCTransform / RunPCA / FindClusters | 消除深度差异、把 spot 按表达分群 | 表达聚类 + SpatialDimPlot |
| 4. 空间域识别 | BayesSpace / SpaGCN | 让聚类「看得见」邻居,划出连续的组织区域 | 空间域标签 |
| 5. 去卷积 | RCTD(spacexr)/ SPOTlight | 用单细胞参考估计每个 spot 里各类细胞的比例 | spot × 细胞类型 权重表 |
| 6. 空间可变基因 | FindSpatiallyVariableFeatures | 找出表达随位置变化的基因 | SVG 列表 + 空间表达图 |
下面逐段展开。示例以人类数据、Seurat 较新版本为准;代码片段用来说明每步「做什么、调什么」,不追求可直接整段运行。
开始之前:您手上要有什么
Visium 的上游是 10x 官方的 Space Ranger,它的标准输出目录里有两块东西,缺一不可:
- 表达矩阵:
filtered_feature_bc_matrix/(或打包好的filtered_feature_bc_matrix.h5),结构和单细胞的 10x 输出一样,是 spot × 基因 的稀疏计数矩阵。 - 空间信息:一个
spatial/子目录,里面有tissue_positions.csv(每个 spot 的行列与像素坐标)、scalefactors_json.json(像素与真实尺度的换算)、以及tissue_hires_image.png等组织切片图。
一个关键前提要先说清楚:Visium 的一个 spot 不是一个细胞。每个 spot 直径约 55 微米,按惯例通常覆盖 1–10 个细胞(具体几个取决于组织的细胞密度)。所以一个 spot 的表达谱,是它底下若干个细胞的混合信号。这句话决定了后面质控、去卷积两步为什么要那样做。
本篇讲的是经典 Visium(spot 级)。更高分辨率的 Visium HD、或探针法的 Xenium 等平台,原理相通但细节不同,不在这篇范围内。
读入数据、建对象
Load10X_Spatial 会一次把表达矩阵、spot 坐标和组织图都读进来,包成一个带空间信息的 Seurat 对象。
library(Seurat)
# data.dir 指向 Space Ranger 的输出目录(内含 h5 与 spatial/ 子目录)
st <- Load10X_Spatial(
data.dir = "spaceranger_output/",
filename = "filtered_feature_bc_matrix.h5"
)
st
几点说明:
- 表达数据默认放在名为
Spatial的 assay 里(单细胞里是RNA)。后面很多函数要显式写assay = "Spatial",别沿用单细胞的默认。 - 对象里同时带了坐标和组织图,所以可以直接画空间图。
SpatialFeaturePlot把某个指标叠在切片上看它的空间分布:
# 把每个 spot 的总 UMI 叠到组织图上,先直观看一眼数据质量与结构
SpatialFeaturePlot(st, features = "nCount_Spatial")
- 建完对象后,
st@meta.data里已自动带上nCount_Spatial(每个 spot 的总 UMI)和nFeature_Spatial(检出基因数),质控就靠它们。
质控:别把 spot 当细胞滤
质控的指标和单细胞一样,还是那三个;但卡阈值的逻辑不同,这是初学最容易踩的坑。
# 人类线粒体基因以 MT- 开头;小鼠用 "^mt-"
st[["percent.mt"]] <- PercentageFeatureSet(st, pattern = "^MT-")
# 先看分布,尤其把 nCount 叠回空间图,判断低值是坏点还是真实结构
VlnPlot(st, features = c("nFeature_Spatial", "nCount_Spatial", "percent.mt"), ncol = 3)
SpatialFeaturePlot(st, features = "nCount_Spatial")
关键区别在于:
- 单细胞里,
nCount特别低往往意味着空液滴、该丢。但在 Visium 里,一个 spot 的总 UMI 高低本身就带生物学含义——细胞密集的区域(如肿瘤实质)计数天然高,疏松或无细胞的区域(如坏死、腔隙)计数天然低。低计数可能是真实的组织结构,不是坏点。所以先把nCount_Spatial叠回空间图看:如果低值连成一片、正好对上某个解剖区域,就别急着滤掉。 - 线粒体比例
percent.mt仍可用来提示细胞破损,但阈值要放宽、要看图。常见做法是把明显离群的高线粒体 spot 去掉即可,而不是照搬单细胞的< 10%。这些数字都是常用起点、非铁律,务必按您自己数据的分布和组织特点来定。
# 阈值按上一步看到的分布来定,下面的数字是示例,不是标准答案
st <- subset(st, subset = nFeature_Spatial > 200 & percent.mt < 25)
标准化与聚类
不同 spot 的测序深度差异很大,而且这种差异和解剖位置强相关,直接比计数会把「深度」误读成「生物学」。Seurat 空间流程惯用 SCTransform 来标准化,它对这类深度差异的处理更稳。之后的降维聚类和单细胞完全一样。
# SCTransform 一步完成标准化 + 找高变基因 + 方差稳定;注意指定 assay
st <- SCTransform(st, assay = "Spatial", verbose = FALSE)
st <- RunPCA(st, assay = "SCT")
st <- FindNeighbors(st, dims = 1:30) # 主成分个数按肘图定,30 是常用取值
st <- FindClusters(st, resolution = 0.5) # resolution 越大分群越细
st <- RunUMAP(st, dims = 1:30)
结果有两种看法,空间数据的价值在第二种:
# 看法一:UMAP,只反映表达相似度,不含位置信息
DimPlot(st, reduction = "umap", label = TRUE)
# 看法二:把同样的 cluster 标签叠回组织切片——这才是空间数据的重点
SpatialDimPlot(st, label = TRUE)
- 这一步的聚类只用了表达、没用坐标。它把表达相似的 spot 归为一群,但一群 spot 在切片上可能东一块西一块。要得到「连续成片的组织区域」,需要下一步专门的空间域方法。
resolution没有「正确值」,试几个值、对照SpatialDimPlot上分出的区块是否符合已知解剖结构再定。降维聚类的调参逻辑与单细胞一致,见 单细胞分析全流程。
空间域识别
上一步的普通聚类把每个 spot 当成孤立个体,看不见它的邻居。而组织是连续的——相邻的 spot 大概率属于同一个区域。空间域方法就是把这条先验用起来:在分群时同时考虑表达和坐标,划出连续、平滑的组织区域(即「空间域」)。
常用的一类工具是 BayesSpace,思路是让每个 spot 的归属受其空间邻居影响,从而得到更连续的区块。它在 SingleCellExperiment 上工作,典型步骤如下:
library(BayesSpace)
# sce 是转成 SingleCellExperiment 的空间数据
sce <- spatialPreprocess(sce, platform = "Visium",
n.PCs = 15, log.normalize = TRUE)
# qTune 帮您在候选的域数量 q 之间做选择
sce <- qTune(sce, qs = seq(3, 12))
qPlot(sce)
# 用选定的 q 做空间聚类(结果比普通聚类更连续成片)
sce <- spatialCluster(sce, q = 8, platform = "Visium", nrep = 10000)
clusterPlot(sce)
几点提醒:
- 域的数量
q需要您来定,没有自动的「正确答案」。qTune/qPlot给的是参考,最终仍要结合已知的组织学分区来判断——按数据和先验知识调,不是铁律。 - 同类思路的工具还有 SpaGCN(用图神经网络融合表达、坐标和组织图像)等。选哪个取决于您的数据和习惯,属于常见的多选一,没有绝对优劣。
- 判断空间域好不好,最直接的办法是把结果叠回切片,看它是否对得上病理或解剖上已知的分区。
与单细胞整合做去卷积
回到那句关键前提:一个 spot 是多个细胞的混合。所以「这个 spot 是什么细胞类型」这个问法本身就不成立,正确的问法是「这个 spot 里各类细胞各占多少比例」。回答它需要一份同组织的单细胞参考:拿参考里各细胞类型的表达特征,去拆解每个 spot 的混合信号,这一步叫去卷积(deconvolution)。
RCTD(在 spacexr 包里)是常用的一种,它需要两份输入——带细胞类型标签的单细胞参考、以及带坐标的空间数据:
library(spacexr)
# 参考:单细胞的 counts + 每个细胞的类型标签 + 每个细胞的总 UMI
reference <- Reference(sc_counts, cell_types, sc_nUMI)
# 空间:Visium 的 counts + 每个 spot 的坐标 + 每个 spot 的总 UMI
puck <- SpatialRNA(spot_coords, st_counts, st_nUMI)
myRCTD <- create.RCTD(puck, reference, max_cores = 4)
# Visium 每个 spot 细胞多,用 "full" 模式估计任意比例的混合
myRCTD <- run.RCTD(myRCTD, doublet_mode = "full")
# 结果:每个 spot 上各细胞类型的权重(比例)
weights <- myRCTD@results$weights
doublet_mode = "full"适合每个 spot 含多个细胞的 Visium;它允许一个 spot 由任意多种细胞类型按比例混合。得到的weights每一行是一个 spot、每一列是一种细胞类型的占比。- 拿到比例后,最常做的是把某个细胞类型的占比叠回切片,看它在组织里的分布,例如「免疫细胞主要富集在哪个区域」。
- 同类工具还有 SPOTlight、cell2location 等,思路一致、实现各异。去卷积结果的好坏,高度依赖单细胞参考是否与空间样本来自同类组织——参考里缺失的细胞类型,去卷积也变不出来。参考的细胞注释怎么做,见 细胞注释:手动 marker 与自动 SingleR。
更轻量的替代是 Seurat 的锚点标签传递(
FindTransferAnchors+TransferData)。它同样借单细胞参考给每个 spot 打各类型的预测分,装配简单;但对「一个 spot 是混合物」的建模不如专门的去卷积工具直接,作为快速探查够用,定量结论仍建议用去卷积方法。
找空间可变基因
聚类和去卷积回答了「哪里是什么」,还有一个只有空间数据才能问的问题:哪些基因的表达本身带有空间格局——即它不是随机散布,而是在切片上聚成区块、形成梯度或边界。这类基因叫空间可变基因(spatially variable genes, SVG)。
Seurat 用 FindSpatiallyVariableFeatures 找 SVG,常用的判据是 Moran's I(一个衡量「空间自相关」的标准统计量:值越接近 1,说明相邻 spot 的表达越相似、空间格局越强):
st <- FindSpatiallyVariableFeatures(
st,
assay = "SCT",
features = VariableFeatures(st)[1:1000], # 先在高变基因里找,省算力
selection.method = "moransi"
)
# 取排名靠前的 SVG,叠回切片看它们的空间分布
top <- head(SpatiallyVariableFeatures(st, selection.method = "moransi"), 6)
SpatialFeaturePlot(st, features = top)
- Moran's I 是空间自相关的经典指标,属于广泛接受的标准方法。除
moransi外,Seurat 也支持markvariogram等方法;专门的 SVG 工具还有 SpatialDE、SPARK-X 等,适合更大规模的数据。 - SVG 和普通高变基因不是一回事:高变基因只问「表达变化大不大」,SVG 还要问「变化是否有空间结构」。二者常有重叠,但一个在各处随机高低起伏的基因方差可以很大、却不是 SVG。
- 拿到 SVG 列表后,通常接着做富集分析,看这些有空间格局的基因落在哪些通路上,见 富集分析怎么做。
在平台上跑一遍
上面这条从读入到 SVG 的流程,在「百沐一下」不写代码也能走完:上传 Space Ranger 的输出目录(以及一份同组织的单细胞参考,用于去卷积),用一句话说清目的——例如「对这份 Visium 数据做质控、空间聚类和空间域识别,再用我传的单细胞参考做去卷积,最后找出空间可变基因」,组学智能体会自动完成建对象、SCTransform、聚类与空间域、去卷积到 SVG 的全流程,并把空间图、结果表和可复现的 R 代码一起交付。功能说明见 组学智能体使用指南,或直接到 app.baimuyixia.com 试一遍。
相关
- 单细胞分析全流程:Seurat 标准 pipeline —— 空间分析的前半段与它同源,聚类调参可对照
- 细胞注释:手动 marker 与自动 SingleR —— 去卷积所需的单细胞参考,细胞类型怎么标
- 富集分析怎么做 —— 拿到空间可变基因后看它们落在哪些通路
- 组学智能体使用指南 —— 在平台上零代码跑通空间全流程