空间转录组数据类型: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 里存了图像像素到捕获点坐标的缩放比例。没有这个文件,你配不上图像和表达数据——我踩过这个坑。

个人习惯:拿到 Visium 数据后,先检查 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 就对了。

避坑指南:我曾经下载了一个 Slide-seq V2 的数据,发现表达矩阵里基因名重复。原因是该数据用了 Ensembl ID 但未去重。建议在导入前先用 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 VisiumSlide-seqMERFISH
分辨率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 或更小,否则邻居加权矩阵全是零。
核心思路:不管哪种格式,最终都要转化为 Giotto 能理解的三个核心对象:
1. 表达矩阵(基因 × 空间单元)
2. 空间坐标(空间单元 × 2/3 列)
3. (可选)图像或邻接关系
弄懂这个,你就能用 createGiottoObject 处理任何自定义格式。
空间转录组数据格式核心对比 10X Visium Slide-seq MERFISH 预印微阵列 随机条形码珠子 多轮成像 ~55 µm(多细胞) ~10 µm(近单细胞) <1 µm(亚细胞) 全转录组(~20k) 全转录组(较低) 靶向(数百~千) 选择技术:空间分辨率 vs 基因通量 vs 样本兼容性的权衡

你想想看,理解这三种数据格式的区别,就像手里有了三把不同钥匙。
Visium 是万能钥匙——兼容性好,社区资源最多;Slide-seq 是高精度镊子,适合精细结构分析;MERFISH 是显微镜,适合看 RNA 分子在细胞内的精确定位。
在 Giotto 里,它们最终都能被装进一个统一的 giottoObject,然后跑同样的分析流程。这就是工具包最强大的地方。

我的工作流:
拿到任何新数据,先用 summarizeGiottoObject() 看一眼基本信息——检测到多少细胞/点?基因数?坐标范围?如果坐标范围异常(比如 Visium 点坐标超过了十万像素),八成是忘了调缩放比例。