第四章:Visium数据格式——空间barcode、UMI与基因表达矩阵
好,咱们现在进入一个实操上非常关键的话题。你拿到的Visium原始数据,到底长什么样?
我记得第一次拿到10x Visium的数据时,对着那个文件夹愣了好一会儿。一堆`.bam`、`.fastq`、`.h5`,完全不知道从哪下手。后来才发现,这些东西的核心就三个概念:空间barcode、UMI、基因表达矩阵。
说白了,这就是Visium给每个“像素点”打上的唯一标识和计数规则。今天咱们就把它拆明白。
4.1 空间barcode:每个组织点的身份证
Visium的捕获芯片上,整齐排列着几千个捕获点。每个点都有一个独一无二的序列,这个序列就是空间barcode。
为什么需要它?
- 定位:每个barcode对应芯片上一个固定的坐标(row, col)。
- 溯源:测序后,只要读到这个序列,就知道它来自组织片的哪个位置。
- 去重:防止同一个点被多次统计。
我建议你把它想象成超市里每个商品的条码。只不过,这里的“商品”是组织切片上55微米直径的一个小点。
关键参数:Visium v1芯片包含约5000个捕获点,v2版本提升到了约14000个。每个barcode长度为16碱基(v1)或27碱基(v2)。
在实际项目中,我曾经遇到一个坑:
有个样本的barcode质量分布图显示很多低质量点。排查后发现是组织切片贴歪了,导致边缘的捕获点只粘到部分细胞,barcode信号极弱。嗯,这里要注意——barcode的质量直接决定了你后续哪些点能用。
4.2 UMI:真正的分子计数器
聊完空间barcode,咱们说说UMI。全称是Unique Molecular Identifier,唯一分子标识符。
为什么需要它?
PCR扩增的过程中,同一个mRNA分子会被复制成很多份。如果没有UMI,你统计出来的“表达量”其实是PCR扩增后的产物数量,不是初始mRNA分子的数量。你想想看,这样会带来多大的偏差?
UMI就是解决这个问题的。它是一个随机的8-10碱基序列,在反转录前就连接到每个mRNA分子上。测序后,我们通过UMI去重,就能还原出初始的分子数。
举个例子:
测序得到的读段:
Read1: AAGCCTATGCC... (空间barcode + UMI)
Read2: GCTGATCGTAC... (cDNA序列)
如果两个读段有相同的barcode和UMI,只算一次。这就是“分子计数”的核心逻辑。
提示:我个人习惯用UMI计数而非读段计数来做下游分析。因为前者更能反映真实的基因表达水平。你可以在Space Ranger的输出表格里看到这两列。
4.3 基因表达矩阵:最终的数据产品
现在我们把所有东西串起来。经过Space Ranger的处理(barcode校正、UMI去重、基因比对),最终会产出一个基因表达矩阵。
The 矩阵长这样:
| 空间barcode | 基因A | 基因B | 基因C | ... |
|---|---|---|---|---|
| AAACCCAAGTTTACCA-1 | 12 | 0 | 5 | ... |
| AAACCCAGTCCGAGTA-1 | 0 | 8 | 0 | ... |
| AAACCCAGTCGCGCAA-1 | 3 | 2 | 7 | ... |
| ... | ... | ... | ... | ... |
每一行是一个空间barcode(也就是一个捕获点),每一列是一个基因。单元格里的数字是UMI计数,代表该点在组织切片上检测到的该基因表达量。
这个矩阵是空间转录组分析的核心数据源。后续的聚类、差异表达、空间可视化,全都基于它。
4.4 数据流程与文件类型
为了让你更清楚整个过程,我画了一个流程图:
从图中可以看到,最终你会得到两种主要格式的文件:
- HDF5格式 (.h5):二进制的压缩文件,里面包含了表达矩阵、barcode列表、基因列表、以及空间坐标信息。适合用R或Python直接读取。
- Market Exchange格式 (Matrix Market):包含三个文件——
matrix.mtx(稀疏矩阵)、barcodes.tsv、features.tsv。文本格式,便于查看和调试。
注意:不要直接打开.mtx文件去数数字,几百兆甚至上G的文件会让你的文本编辑器直接崩掉。我推荐用R的Seurat或Python的Scanpy来加载。
4.5 实测:如何加载数据
理论讲完了,咱们看个实际例子。假设你的输出目录结构如下:
output/
├── filtered_feature_bc_matrix.h5
├── filtered_feature_bc_matrix/
│ ├── barcodes.tsv.gz
│ ├── features.tsv.gz
│ └── matrix.mtx.gz
├── analysis/
│ ├── clustering/
│ │ └── graphclust/
│ └── pca/
└── spatial/
├── tissue_lowres_image.png
└── tissue_positions_list.csv
用R加载时我会这样做:
library(Seurat)
# 从h5文件读取
visium_data <- Load10X_Spatial(
data.dir = "output/",
filename = "filtered_feature_bc_matrix.h5"
)
# 查看表达矩阵的维度
dim(GetAssayData(visium_data, assay = "Spatial"))
# 前6个barcode的空间坐标
head(visium_data@images[[1]]@coordinates)
输出类似这样:
[1] 31053 4992
# 31053个基因,4992个捕获点
tissue row col imagerow imagecol
AAACCCAAGTTTACCA-1 0 28 80 24.7 31.2
AAACCCAGTCCGAGTA-1 0 32 85 28.1 34.8
AAACCCAGTCGCGCAA-1 0 35 91 30.4 37.5
看到没有?每个barcode都对应了它在组织片上的物理坐标(row, col),以及它在低分辨率图像上的像素坐标(imagerow, imagecol)。这些坐标就是后续画空间特征图的依据。
核心结论:空间barcode + UMI + 基因表达矩阵,三者合一才构成了Visium数据的完整格式。缺少任何一个,你都无法做出正确的空间聚类分析。
好了,Visium的数据格式就讲到这里。现在你可以清楚地知道,那些看似杂乱的文件夹里到底藏着什么。记住,barcode决定了“在哪”,UMI决定了“多少”,矩阵决定了“表达什么”。搞清楚这三者的关系,你就能自如地操控Visium数据了。