空间转录组数据类型:10X Visium、Slide-seq、MERFISH 等
做空间转录组分析,第一件事就是搞清楚你拿到的数据是什么来头。
不同技术生成的数据格式千差万别,读取方式也不一样。我刚开始接触这个领域时,就吃过“格式不对”的亏——吭哧吭哧跑完流程,结果发现读进来的坐标全乱套了。嗯,从那以后我养成了习惯:拿到数据先看技术类型,再选对应的导入接口。
今儿咱们就把主流的几种空间转录组数据格式掰开揉碎讲一讲。
10X Visium、Slide-seq、MERFISH……每种都有脾气,别指望用同一套代码通吃。
1. 10X Visium:最成熟的商业方案
10X Visium 是目前最常用的空间转录组平台。它在载玻片上预铺了带空间条形码(spatial barcode)的捕获点,每个点直径 55 µm,相邻点中心距 100 µm。
说白了,这是一张“格子纸”——每个格子对应一个捕获区域,里面可能包含几个到十几个细胞。
Visium 的原始数据格式很好认:
- H5 文件:存放表达矩阵 + 空间坐标(通过 10X 的 spaceranger 软件处理生成)
- CSV / TSV 文件:手工解析的坐标表或矩阵表
- 图像文件(tiff):组织切片 H&E 染色图像
在 Giotto 中,我通常用 createGiottoObjectVisium() 一键加载。举个例子:
library(Giotto)
my_gobject <- createGiottoObjectVisium(
dir_path = "data/visium_raw/",
h5_file = "filtered_feature_bc_matrix.h5",
image_file = "tissue_hires_image.png",
json_file = "scalefactors_json.json"
)
注意看参数:json_file 里存了图像像素到捕获点坐标的缩放比例。没有这个文件,你配不上图像和表达数据——我踩过这个坑。
spatial 文件夹下的 tissue_positions_list.csv,这里存储了每个捕获点的精确像素坐标和是否在组织内的标记。我会用 R 快速看一眼分布:plot(tissue_positions$pxl_col_in_fullres, tissue_positions$pxl_row_in_fullres)如果点分布呈规则六边形网格,说明数据正确。
2. Slide-seq:高分辨率的“珠子”方案
Slide-seq 来自哈佛的实验室,核心是一枚载玻片上面铺了数百万个直径 10 µm 的条形码珠子。每个珠子都有唯一 ID,通过原位测序确定其空间位置。
和 Visium 相比,Slide-seq 的分辨率更高(单个珠子捕捉细胞甚至亚细胞信号),但捕获效率略低。
Slide-seq 的数据格式很特别:
- Digital Expression Matrix(DGE):一般以
.dge.txt或.mtx形式给出 - Bead location file:每个珠子的坐标,通常是
beads.csv或puck.txt - Puck 编号:Slide-seq 不同的批次(puck)坐标基准不同,不能混用
Giotto 可以用 createGiottoObjectSlideSeq() 处理:
go_slideseq <- createGiottoObjectSlideSeq(
expression_matrix = "ST_puck_191128.dge.txt",
spatial_locs = "ST_puck_191128_beads.csv",
expression_format = "raw"
)
这里要尤其注意坐标的单位——Slide-seq 的坐标通常是纳米级精度,但有些公开数据集会人为缩放。我当时跑一个公共数据集,发现点间距太大,结果查了半天:原来是坐标单位被改成了 µm。加个 scale_factor = 1e-3 就对了。
row.names(expr_matrix) <- make.unique(row.names(expr_matrix)) 处理一下。
3. MERFISH:单细胞分辨率的“多轮成像”技术
MERFISH 是单分子荧光原位杂交的扩展版。它用多轮编码探针杂交和成像,同时检测数百到上千种 RNA。
分辨率极高——能达到 0.1~1 µm 级别,可以精确到亚细胞位置。
MERFISH 的数据通常以文件形式分发:
- 表格格式(CSV / HDF5):每一行是一个检测到的 RNA 分子,包含基因、X/Y 坐标、细胞分配等
- 细胞分割结果:有时通过 Cellpose 等工具生成,附在
segmentation.csv - 图像(tiff stacks):多轮杂交的原位图像(可选,用于可视化)
Giotto 没有专用的 MERFISH 导入函数,但我们可以用通用 createGiottoObject() 自己组装。我分享一个实际项目中的脚本:
library(data.table)
molecules <- fread("merfish_molecules.csv")
# 列:gene, x, y, cell_id
# 构建spatial locations:按细胞取平均坐标
cell_locs <- molecules[, .(x = mean(x), y = mean(y)), by = cell_id]
# 构建表达矩阵
expr_mat <- dcast(molecules, gene ~ cell_id, fun.aggregate = length, value.var = "gene")
rownames(expr_mat) <- expr_mat$gene
expr_mat$gene <- NULL
go_merfish <- createGiottoObject(
expression = as.matrix(expr_mat),
spatial_locs = as.data.frame(cell_locs)
)
嗯,这里要注意:MERFISH 的分子级别数据量极大(几千万行是常事),内存不够的话可以先用 data.table 的 fread() 并筛选基因列表,避免一次性全部读入。
4. 三种技术的核心差异一览
我做了一个表,方便快速对比:
| 维度 | 10X Visium | Slide-seq | MERFISH |
|---|---|---|---|
| 分辨率 | 55 µm(多细胞) | 10 µm(近单细胞) | 亚细胞(<1 µm) |
| 捕获方式 | 预打印微阵列点 | 随机分布条形码珠子 | 多轮荧光成像 |
| 基因通量 | 全转录组(~20,000 基因) | 全转录组(捕获效率较低) | 靶向(数百~数千基因) |
| 组织兼容性 | 新鲜冷冻、FFPE | 新鲜冷冻 | 新鲜冷冻、FFPE(需优化) |
| 图像辅助 | 必备 H&E | 可选(明场) | 荧光图像本身是数据 |
| 典型数据大小 | ~100 MB / 样本 | ~500 MB ~ 2 GB / puck | ~50 GB ~ 数百 GB / 组织 |
你看,Visium 胜在成熟和全转录组;Slide-seq 在分辨率与通量之间找到了平衡;MERFISH 则是精准定位之王,但基因数受限。选哪个,取决于你的科学问题。
5. 数据格式对下游分析的影响
不同格式不只是导入方式不同,还直接影响你能做什么分析:
- 分辨率不均一:Visium 每个点混合多个细胞,不适合做单细胞解卷积?其实可以,需要借助 RCTD、Cell2location 等工具。Slide-seq 和 MERFISH 则能直接做单细胞粒度分析。
- 坐标系统一:Visium 的坐标基于图像像素,Slide-seq 基于物理距离(nm/µm)。如果混用不同技术进行整合,需要先做坐标归一化——我一般用
spatScale()将坐标缩放到 [0,1] 范围。 - 稀疏程度不同:MERFISH 的分子数据非常稀疏(每个细胞几十到几百个分子),处理时需要设置
spatial_network的k = 10或更小,否则邻居加权矩阵全是零。
1. 表达矩阵(基因 × 空间单元)
2. 空间坐标(空间单元 × 2/3 列)
3. (可选)图像或邻接关系
弄懂这个,你就能用
createGiottoObject 处理任何自定义格式。
你想想看,理解这三种数据格式的区别,就像手里有了三把不同钥匙。
Visium 是万能钥匙——兼容性好,社区资源最多;Slide-seq 是高精度镊子,适合精细结构分析;MERFISH 是显微镜,适合看 RNA 分子在细胞内的精确定位。
在 Giotto 里,它们最终都能被装进一个统一的 giottoObject,然后跑同样的分析流程。这就是工具包最强大的地方。
拿到任何新数据,先用
summarizeGiottoObject() 看一眼基本信息——检测到多少细胞/点?基因数?坐标范围?如果坐标范围异常(比如 Visium 点坐标超过了十万像素),八成是忘了调缩放比例。