跳到正文
百沐一下百沐一下
本节目录

空间转录组入门: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,它的标准输出目录里有两块东西,缺一不可:

  1. 表达矩阵filtered_feature_bc_matrix/(或打包好的 filtered_feature_bc_matrix.h5),结构和单细胞的 10x 输出一样,是 spot × 基因 的稀疏计数矩阵。
  2. 空间信息:一个 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 试一遍。

相关