2. 空间转录组常用数据格式介绍
做空间转录组分析,绕不开几个文件格式。H5、MTX、JSON,这三个你天天打交道。我刚开始接触Visium数据时,被这些后缀搞得晕头转向,还差点删了重要文件……后来才明白,它们各有各的用处。今天咱们把底裤都翻出来,一次性说清楚。
2.1 H5——承载一切的“集装箱”
H5(HDF5)是10x Genomics官方跑完Space Ranger后最核心的输出。说白了,它是一个二进制的大箱子,能装矩阵、索引、属性、元数据,甚至同时放多个数据集。我在项目里接过一个客户提供的“非标准”H5文件,打开一看居然少了个关键group——当时排查了一整天。
Visium的H5文件内部大概长这样:
/ (根节点)
└── matrix (HDF5 group)
├── barcodes (1D dataset, 字符串)
├── data (1D dataset, 稀疏矩阵的非零值)
├── indices (1D dataset, 行索引)
├── indptr (1D dataset, 列指针)
├── shape (1D dataset, [基因数, 斑点数])
└── features (HDF5 group)
├── _all_tag_keys (1D dataset)
├── feature_type (1D dataset, 通常是 "Gene Expression")
├── genome (1D dataset)
├── id (1D dataset, ensembl ID)
└── name (1D dataset, 基因名)
shape 是 [基因, 斑点] 还是 [斑点, 基因]?10x官方用的是前者。如果你用scanpy读取,它会自动转置,但直接撸HDF5接口时一定要看清楚。
用Python读H5很简单,但我不推荐每次都手动h5py。我习惯用scanpy一行搞定:
import scanpy as sc
adata = sc.read_10x_h5("filtered_feature_bc_matrix.h5")
print(adata.shape) # (基因数, 斑点数)
嗯,这里要注意:10x同时输出 raw_feature_bc_matrix.h5 和 filtered_feature_bc_matrix.h5,前者包含所有空滴(没有组织、没有RNA),后者只保留有足够UMI的斑点。实际分析就用filtered版本。
2.2 MTX——稀疏矩阵的“省油灯”
MTX(Matrix Market Exchange Format)专门存稀疏矩阵,效率极高。Visium的输出目录里经常看到 matrix.mtx 和 barcodes.tsv、features.tsv 三件套。我曾经犯过一个低级错误——把三个文件分开放到不同子目录,结果scanpy找不到它们,报错了半小时……后来乖乖按标准目录结构来。
MTX文件的开头几行:
%%MatrixMarket matrix coordinate integer general
% 说明:三列分别是 行ID(从1开始)、列ID(从1开始)、表达值
9264 5000 120345
1 1 3
1 2 0
1 3 5
...
第一行的 9264 5000 120345 是【基因数 斑点数 非零元素个数】。不过,MTX只存了数值,基因名和条形码分居在另外两个TSV文件里。所以读取时必须三合一。
sc.read_10x_mtx,它会自动把三个文件配对。如果你非要手动读,可以用 scipy.io.mmread 读出稀疏矩阵,再自己拼上barcodes和features。
为什么10x还要保留MTX格式?因为H5虽然集成度高,但对下游工具不够“友好”。很多经典R包(比如Seurat)直接支持MTX,而Scanpy则两个都吃。我建议初学者先熟悉MTX三件套,因为它更容易手工检查数据完整性——数一数行数就知道文件有没有损坏。
2.3 JSON——空间坐标与元数据的“说明书”
JSON格式在空间转录组里主要负责两件事:组织分割(tissue segmentation) 和 空间坐标。我见过最典型的就是Space Ranger输出的 spatial/tissue_positions_list.csv 和 spatial/tissue_hires_image.png 的元数据,但这些信息经常被包装在JSON文件里供下游使用。
具体来说,Visium的JSON主要有两类:
- tissue_hires_image.json – 记录高分辨率图像元数据(尺寸、缩放因子等)
- scalefactors_json.json – 存储斑点大小的缩放因子,用于将spot坐标映射到像素坐标
看一个典型 scalefactors_json.json:
{
"tissue_hires_scalef": 0.087,
"tissue_lowres_scalef": 0.087,
"spot_diameter_fullres": 55.0,
"fiducial_diameter_fullres": 110.0,
"image_pixel_size_um": 0.5
}
为什么JSON重要?因为它告诉你如何把芯片上的物理坐标(像“A1, B2”这类)转成像素位置。没有这个缩放因子,你画的点图绝对对不准组织图像——我在指导实习生时就踩过这个坑,他直接把绝对坐标扔进matplotlib,结果斑点全飘到图像外面去了。
array_row/array_col(芯片坐标)和 pxl_row_in_fullres/pxl_col_in_fullres(像素坐标)。JSON里的缩放因子只适用于像素坐标。千万不要把芯片坐标直接乘缩放因子!
2.4 三种格式的对比与互转
表格来了。我根据自己的实战经验,整理了一份对比备忘:
| 特征 | H5 | MTX | JSON |
|---|---|---|---|
| 存储类型 | 二进制 HDF5 | 文本稀疏矩阵 | 文本/字典 |
| 主要用途 | 表达矩阵 + 元数据 | 表达矩阵(仅数值) | 空间坐标 + 图像缩放 + 元数据 |
| 支持多数据集 | 是(同一文件多个group) | 否(一个文件一个矩阵) | 否(一个JSON对应一个样本) |
| 读取速度 | 快(流式读取部分数据) | 中等(全部加载到内存) | 极快(体积小) |
| 人工可读 | 否(需工具) | 半可读(首行是维度,后面是坐标值) | 是(纯文本结构清晰) |
| 常见扩展名 | .h5 | .mtx / .mtx.gz | .json |
它们之间的互转也很简单。比如把MTX转成H5,可以用scanpy或Seurat;但反过来H5转MTX一般不会做,因为会丢失元数据。我一般以H5作为通用交换格式,因为它一个文件搞定所有信息,发给别人也干净。
2.5 一张图看明白数据流转
结构上讲,H5 和 MTX 都存储表达矩阵(数值+基因+斑点索引),只是组织方式不同;JSON 则负责空间位置和图像变换参数。实际分析中,你拿到一个Visium样本,至少需要 H5(或MTX)+ JSON 才能完整构建空间对象。我习惯把H5作为主要数据源,用JSON补充空间信息,这样后面做批次校正时也不会把坐标搞乱。
2.6 避坑指南
- 文件名大小写敏感: Linux下
filtered_feature_bc_matrix.h5和Filtered_Feature_BC_Matrix.h5是不同文件。我曾因为重命名时改了大写导致自动流程失败——排查了一个小时! - MTX的“0”问题: MTX文件只存储非零元素,但有些工具生成的MTX会包含零值条目。读取后最好用
.eliminate_zeros()清理,否则后续归一化会多出虚假零。 - JSON中的坐标序:
pxl_row_in_fullres和pxl_col_in_fullres,分别对应图像的行(y轴)和列(x轴)。绘制时记得用imshow(…, origin='lower')才能对齐。
adata.obs 的行数与JSON中的spot id数是否一致。我在一个项目中遇到过H5里多出几个空spots(因为Space Ranger参数设置不对),导致后续空间坐标匹配不上。用 set(adata.obs_names) ^ set(json_ids) 快速找差异。
这一节内容不少,但都是实战基础。搞懂了H5、MTX、JSON,你就能在任意工具之间自由倒腾数据,不会因为格式问题卡壳。