简介
📖 这是空间转录组分析系列的第二期。上期空间转录组分析一,我们完成了数据导入、质控、降维和聚类,得到了 不同分辨率下的聚类情况。本期我们将聚焦细胞类型注释——回答"每个 cluster 到底是什么细胞"这个核心问题。
注释策略:两步走
空间转录组注释通常采用 “自动注释 + 手动校正” 两步策略:
| 第一步 | SingleR 自动注释 | 快速、可复现、覆盖广 | 参考数据库未必包含你的组织类型 |
| 第二步 | 文献 marker 手动校正 | 组织特异性强、生物学合理 | 依赖领域知识、主观性 |
💡 本文演示的胎盘组织就是一个典型案例——SingleR 的通用参考数据库没有非常细致的胎盘特异性细胞类型,注释结果非常粗糙,所以我们结合原文的 marker 进行了手动注释。
✉️ 后台发送关键词"空间转录组分析二"获取本期完整代码。
📦 一、加载包与读入数据
从上期保存的聚类结果出发:
library
(Seurat)
library
(SingleR)
library
(celldex)
library
(dplyr)
library
(ggplot2)
library
(scrapper)
# 辅助函数
sp <– readRDS(
"spatial_obj_clustered.rds"
)
在空间转录组分析中,聚类分辨率(resolution)通常不宜设置过高。本教程使用的是 10x Genomics Visium 数据,每个 spot 往往包含多个细胞,其表达谱属于混合信号,因此空间聚类更多用于识别组织区域和整体空间结构,而非像单细胞测序那样精细划分细胞亚群。若分辨率设置过高,容易将细胞组成比例差异或技术噪声识别为新的 cluster,导致结果过于零散且难以进行生物学解释。因此,本教程选择较为适中的分辨率(如 0.4)来观察样本的大体组织结构。当然,聚类分辨率并没有统一的最佳参数,不同样本的组织异质性、数据质量和 spot 数量均会影响结果。实际分析中建议结合空间分布、标记基因表达及组织学特征不断调整和比较不同分辨率的结果,最终选择一个既能反映真实组织结构、又具有良好生物学可解释性的聚类方案。
Idents(sp) <–
"SCT_snn_res.0.4"
🤖 二、SingleR 自动注释
SingleR 的原理是:将每个 cluster 的平均表达谱与参考数据库中的纯化细胞类型逐一比对,计算 Spearman 相关系数,取最相似的作为注释标签。
2.1 下载参考数据库
celldex 包提供了多种预处理的参考数据集,首次运行会自动联网下载:
# HumanPrimaryCellAtlas:~700 种细胞类型,覆盖面最广
ref <– HumanPrimaryCellAtlasData()
# 备选参考(按需选择):
# ref <- BlueprintEncodeData() # 免疫细胞为主
# ref <- DatabaseImmuneCellExpressionData() # 免疫细胞更细
2.2 运行注释
pred <– SingleR(
test = GetAssayData(sp, assay =
"SCT"
),
# 用 SCT 标准化后的表达矩阵
ref = ref,
labels = ref$label.main,
# label.main = 粗分; label.fine = 细分
clusters = Idents(sp)
# 按 cluster 注释(而非每个 spot)
)
👉 clusters = Idents(sp) 意味着是按 cluster 整体进行注释,而不是逐个 spot。这样速度快且结果更稳定。
2.3 查看结果
pred
输出(简化后):
> pred
DataFrame with 7 rows and 4 columns
scores labels delta.next pruned.labels
<matrix> <character> <numeric> <character>
0 0.389760:0.303218:0.265497:... Fibroblasts 0.0466681 Fibroblasts
1 0.374063:0.338815:0.306596:... Fibroblasts 0.0248072 Fibroblasts
2 0.413441:0.314701:0.269536:... Fibroblasts 0.0141207 Fibroblasts
3 0.391411:0.321139:0.281956:... Fibroblasts 0.0365852 Fibroblasts
4 0.386156:0.299599:0.261445:... Fibroblasts 0.1062931 Fibroblasts
5 0.395926:0.321951:0.275652:... Fibroblasts 0.0968614 Fibroblasts
6 0.371507:0.309391:0.277228:... Tissue_stem_cells 0.1059918 Tissue_stem_cells
⚠️ 问题来了:我们看labels这一列,7 个 cluster 中有 6 个被注释为 Fibroblasts,1 个注释为 Tissue_stem_cells。这显然不合理——胎盘组织包含多种滋养层细胞、蜕膜基质细胞、血管周细胞等,不可能全是成纤维细胞。
为什么会这样? 因为 HumanPrimaryCellAtlasData 主要涵盖血液、免疫、神经等系统,缺少胎盘特异性细胞类型。SingleR 只能在已有的标签里"硬选一个最像的",所以会大部分的 cluster 都归为 Fibroblasts。
虽然结果不好,但也可以先可视化一波:
p1 <- DimPlot(sp, group.by = "cell_type_main", label = TRUE, repel = TRUE) +
ggtitle("SingleR Auto Annotation") + NoAxes()
p2 <- SpatialDimPlot(sp, group.by = "cell_type_main", label = TRUE, label.size = 3)
p1 + p2
ggsave("auto_annotation.png", width = 16, height = 6, dpi = 300)

🔬 三、文献 Marker 手动校正
既然自动注释不靠谱,我们需要借助组织特异性 marker 基因进行手动注释。
3.1 加载文献 marker 表
本文使用的 marker 表整理自 Arutyunyan et al. (2023) Nature——就是数据来源的同一篇文献:
placenta_tab <– read.csv(
'nature2023_placenta_markers.csv'
, header =
TRUE
)
# 有哪些细胞类型?
unique(placenta_tab$`Cell name`)
该表包含的胎盘细胞类型:
-
VCT:绒毛细胞滋养层 (Villous Cytotrophoblast)
-
VCT-p:增殖性 VCT
-
VCT-fusing:融合中的 VCT
-
VCT-CCC:柱状细胞滋养层
-
SCT:合体滋养层 (Syncytiotrophoblast)
-
EVT:绒毛外滋养层 (Extravillous Trophoblast)
-
以及各种免疫细胞、基质细胞、血管周细胞等
3.2 构建基因 → 细胞类型映射表
placenta_tab
g
e
n
e
_
c
l
e
a
n
<
−
p
l
a
c
e
n
t
a
_
t
a
b
gene\\_clean <- placenta\\_tab
gene_clean<−placenta_tab`Cell marker`
# 清洗基因名,建立 gene → cell type 映射
gene_to_celltype <– placenta_tab %>%
group_by(gene_clean) %>%
summarise(cell_type = paste(unique(`Cell name`), collapse =
"; "
),
.groups =
"drop"
)
3.3 找每个 cluster 的差异基因并与 marker 表交叉
以下这段代码的整体逻辑是:首先使用 Seurat 的 FindAllMarkers 对对象 sp 中每个 cluster 进行差异表达分析,其中 only.pos = TRUE 表示只保留上调基因,logfc.threshold = 0.5 用于过滤表达倍数变化小于约 1.41 倍的基因,min.pct = 0.1 则要求基因至少在10%的 spot 中表达,以减少低表达噪音;
随后我们每个簇挑选top100的marker基因,看看是哪些细胞类型。空间转录组(尤其是 10x Genomics Visium)的 marker 表达具有明显的“分散性”:真正的经典 marker(如胎盘里的 VCT/EVT/SCT 标记)不一定排在最前面,尤其在混合 spot 和不同表达比例的情况下,如果只取 top5–50,很容易漏掉关键 marker,导致多个 cluster 完全无法匹配到任何已知 cell type;
最后我们关联到文献marker表,去除掉那些没有筛选到关键基因的行。
# 找差异基因
markers <– FindAllMarkers(sp, only.pos =
TRUE
, logfc.threshold =
0.5
, min.pct =
0.1
)
# 取每个 cluster top 100 高表达基因
top5 <– markers %>%
group_by(cluster) %>%
top_n(n =
100
, wt = avg_log2FC) %>%
arrange(cluster, desc(avg_log2FC))
# 与文献 marker 表交叉
top5_annotated <– top5 %>%
left_join(gene_to_celltype, by = c(
"gene"
=
"gene_clean"
)) %>%
filter(!is.na(cell_type))
🎯 确定细胞类型的核心思路:如果某个 cluster 的 top marker 基因中大量匹配文献里的 VCT marker(如 EGFR、CDH1、TP63),那这个 cluster 很可能就是 VCT。
3.4 手动指定细胞类型
首先我们看看top5_annotated 的结果,除了cluster3之外,其他的都有对应的细胞类型。也能够发现SCT,VCT,EVT,DS_CELL这些结构,说明0.4的分辨率已经能很好划分胎盘的空间组织结构,但由于Visium本身spot为多细胞混合信号,当前cluster更偏向组织功能区域而非纯细胞类型,因此会出现marker重叠与混合注释现象。
p_val avg_log2FC pct.1 pct.2 p_val_adj cluster gene cell_type
<dbl> <dbl> <dbl> <dbl> <dbl> <fct> <chr> <chr>
1 0 0.823 0.99 0.542 0 0 PSG3 SCT
2 0 0.539 0.823 0.531 0 0 EGFR VCT
3 0 2.95 0.764 0.144 0 1 PRL dS_cell
4 0 2.82 0.644 0.104 0 1 WNT4 dS_cell
5 0 2.44 0.996 0.727 0 1 DKK1 dS_cell
6 0 2.42 1 0.999 0 1 IGFBP1 dS_cell
7 0 2.32 1 0.923 0 1 GNLY dNK
8 0 2.25 0.523 0.139 0 1 PRF1 dNK
9 0 3.06 0.999 0.829 0 2 CNN1 uSMC
10 0 2.60 0.371 0.106 0 4 CYP19A1 VCT-p
11 0 1.86 0.524 0.304 0 4 ERVW-1 VCT-fusing; VCT-CCC; SCT
12 0 1.73 0.975 0.626 0 4 PSG3 SCT
13 2.91e- 3 1.30 0.115 0.079 1 4 BCAM VCT
14 0 2.60 0.802 0.275 0 5 FLT4 iEVT; eEVT
15 0 2.52 0.966 0.7 0 5 MMP12 iEVT
16 6.80e-13 2.34 0.13 0.03 0.0000000126 5 L1TD1 VCT
17 0 1.89 0.802 0.345 0 5 LPCAT1 VCT-CCC
18 8.04e-10 1.88 0.181 0.063 0.0000149 5 MKI67 VCT-p
19 0 4.38 0.273 0.015 0 6 NTRK2 PV2
针对这样的现象,后续可以通过配对的单细胞转录组数据进行去卷积分析(如cell2location或RCTD),以估计每个spot的细胞组成,从而有效解决空间转录组中cluster细胞类型混合导致的注释不清问题。我们将在后续的分析教程中示例该方法。
本次我们先根据交叉结果和生物学知识,对聚类进行最终标注:
sp$cell_type_manual <- factor(Idents(sp),
levels = c("0", "1", "2", "3", "4", "5", "6"),
labels = c("SCT", "dS_cell", "uSMC", "Unknown", "VCT", "EVT", "PV2")
)
| 0 | Fibroblasts | SCT | Syncytiotrophoblast(合体滋养层) |
| 1 | Fibroblasts | dS_cell | decidual Stromal cell(蜕膜基质细胞) |
| 2 | Fibroblasts | uSMC | uterine Smooth Muscle Cell(子宫平滑肌细胞) |
| 3 | Fibroblasts | Unknown | 暂未明确 |
| 4 | Fibroblasts | VCT | Villous Cytotrophoblast(绒毛细胞滋养层) |
| 5 | Fibroblasts | EVT | Extravillous Trophoblast(绒毛外滋养层) |
| 6 | Tissue_stem_cells | PV2 | Perivascular cell type 2(血管周细胞 2 型) |
💡 可以看到,手动校正后细胞类型从"几乎全是成纤维细胞"变成了与胎盘组织结构高度吻合的多种细胞类型组合。
📊 四、可视化对比
4.1 UMAP + 空间分布
p1 <- DimPlot(sp, group.by = "cell_type_manual",label = TRUE, repel = TRUE) +
ggtitle("Manual Annotation") + NoAxes()
p2 <- SpatialDimPlot(sp, group.by = "cell_type_manual", label = TRUE, label.size = 3)
p1
p2
p1 + p2
ggsave("Manual_annotation.png", width = 16, height = 6, dpi = 300)


4.2 Marker 基因表达热图(DotPlot)
用每个 cluster 匹配到的文献 marker 基因画点图,直观展示注释依据:
genes_to_plot <- unique(top5_annotated$gene)
DotPlot(sp, features = genes_to_plot, group.by = "cell_type_manual") +
RotatedAxis() +
scale_color_gradientn(colors = c("lightblue", "#bb2222")) +
coord_flip() +
labs(x = '', y = '') +
theme_bw() +
theme(
panel.grid = element_blank(),
axis.text.y = element_text(size = 15, color = 'black'),
axis.text.x = element_text(size = 15, color = 'black', angle = 45, hjust = 1),
axis.ticks = element_blank()
)
ggsave("Manual_heatmap.png", width = 6, height = 8, dpi = 300, bg = 'white')
🎯 DotPlot 中每个 cluster 的 marker 高表达模式是其注释的直接证据——例如 VCT 集群高表达 EGFR、CDH1、TP63,EVT 集群高表达 HLA-G 等经典滋养层分化 marker。

💾 五、保存结果
saveRDS(sp,
"spatial_obj_annotated.rds"
)
write.csv(as.data.frame(pred),
"singleR_annotation_result.csv"
)
✉️ 后台发送关键词"空间转录组分析二"获取本期完整代码。



