3. 空间转录组数据格式:ST、Visium、Slide-seq、MERFISH
做空间聚类,第一步就是跟数据格式打交道。不同平台产出的数据,结构差异很大。你拿Slide-seq的格式去跑Visium的流程,准报错。我入行头半年就犯过这个错——拿Visium的代码直接读Slide-seq的bead数据,结果解析出来的坐标全是NaN,折腾了两天才发现是格式不兼容。
这一章咱们把四种主流格式掰开看:ST、Visium、Slide-seq、MERFISH。我会结合项目踩坑经验,帮你理清每种格式的核心字段、存储结构,以及对应的空间聚类适配要点。
3.1 ST 格式(空间转录组学第一代)
ST(Spatial Transcriptomics)是2016年推出的原位捕获技术。它的数据格式比较原始——说白了就是一张高分辨率的组织切片图,加上一个手动分割的网格坐标文件。
典型的ST数据包含两个核心文件:
- 组织图像(.tif或.png):高分辨率H&E染色图,用于定位点阵。
- 坐标文件(.txt或.csv):每行一个spot,包含列名如
x_pixel,y_pixel,tissue_flag。
每个spot直径约100μm,中心间距200μm。圈出来的点阵通常对应图像上的特定区域。我最早处理ST数据时,最头疼的是手工对齐——图像旋转了0.5度,坐标就全偏了。后来我写了个脚本用图像配准做了自动校正,才解放了双手。
# ST 坐标文件示例
spot_id x_pixel y_pixel tissue_flag
spot_01 120.5 340.2 1
spot_02 320.8 341.1 1
spot_03 120.3 540.6 0
ST格式的基因表达矩阵通常按spot×gene存储,行名对应spot ID,列名是基因名。它和Visium最大的区别是没有条形码(barcode)字段——spot的标识就是手动命名的字符串。
3.2 Visium 格式(10x Genomics 的进化版)
Visium是10x Genomics在2019年推出的升级版。它继承了ST的网格思想,但做了标准化:每个spot直径55μm,中心间距100μm,密度翻了近4倍。最关键的是——每个spot带了唯一的条形码(barcode),读取可以直接通过barcode匹配到空间位置。
Visium的标准输出是H5文件(Space Ranger流程生成)和三个辅助文件:
- filtered_feature_bc_matrix.h5:基因表达矩阵,HDF5格式,包含barcode、feature(基因)和计数。
- tissue_positions_list.csv:四个字段:barcode、in_tissue、row、col(行列索引)以及像素坐标(pxl_row_in_fullres, pxl_col_in_fullres)。
- scalefactors_json.json:图像缩放参数,用于对齐坐标。
- tissue_hires_image.png:高通量组织图像。
# tissue_positions_list.csv 片段
barcode,in_tissue,array_row,array_col,pxl_row_in_fullres,pxl_col_in_fullres
AAACCCAAGATATGCT-1,1,0,0,112.5,98.3
AAACCCACAGTGACTT-1,1,0,1,212.7,99.1
AAACCCAGTATTACGG-1,0,1,0,113.0,198.5
Visium的坐标系统是统一的——每个capture area有固定尺寸(6.5mm × 6.5mm),包含4992个spot(其中大约3500-4000落在组织内)。
scanpy.read_visium(),它会自动解析H5和CSV文件。我之前手写解析踩了图像缩放的坑——原始像素坐标是fullres级别的,如果不乘以scalefactors,坐标范围会差好几倍。
3.3 Slide-seq 格式(高分辨率的“球”时代)
Slide-seq是Broad Institute开发的基于DNA条形码球形微珠(bead)的方法。它的分辨率远高于Visium——单个bead直径10μm,中心间距约20μm。每个bead携带一个唯一的DNA条形码(barcode),用来标记空间位置。
Slide-seq的数据格式很特别:
- 表达矩阵:bead × gene,稀疏矩阵(通常用mtx格式或h5ad)。
- bead坐标文件(.csv或.tsv):每个bead的三维坐标(x, y, z)以及对应的barcode。注意:z坐标通常是0(因为切片是2D),但有些版本会有小范围的高度变化。
- meta文件:包含bead的测序质量、组织归属标记。
我处理Slide-seq数据时最头疼的是坐标精度——Visium的阵列坐标是整数(row, col),而Slide-seq的真实坐标是连续浮点数,且由于制造工艺,bead位置会有±5μm的随机偏移。如果你直接做网格划分,很容易把近邻的bead分到不同格子里。
# Slide-seq 坐标文件示例 (beads.csv)
barcode,x,y,z
CGTACGAT-1,102.34,88.72,0.00
ACTGAGTA-2,104.56,89.04,0.00
TGACATCG-3,98.12,87.90,0.00
Slide-seq的另一个特点是数据稀疏——每个bead通常只捕获几十到几百个基因,而Visium每个spot能测到数千个。所以在做空间聚类前,我习惯先用k近邻计算bead之间的空间权重矩阵,再用BayesSpace的增强模型处理稀疏性。
3.4 MERFISH 格式(单细胞分辨率的多重成像)
MERFISH(Multiplexed Error-Robust Fluorescence In Situ Hybridization)是单细胞分辨率的技术——每个细胞可被独立分辨,而不是像前三种那样依赖固定网格。它的数据格式更像单细胞RNA-seq,但多了一组空间坐标。
MERFISH的典型数据包含:
- 细胞分割掩膜(.tif或分水岭结果):每个细胞的轮廓多边形。
- 表达矩阵(cell × gene):每个细胞中每个基因的RNA计数。
- 细胞质心坐标(.csv):每个细胞的中心点位置(x, y,有时包括z)。
- 细胞形态学特征:面积、周长、圆形度等,用于质量控制。
# MERFISH 细胞坐标示例
cell_id,center_x,center_y,area,p_ratio
cell_001,120.5,340.2,135.6,0.78
cell_002,320.8,341.1,142.3,0.81
cell_003,120.3,540.6,98.7,0.65
MERFISH的坐标直接对应细胞质心,不需要从网格映射。看起来简单,但有个坑:细胞分割的精度直接影响聚类质量。我曾在MERFISH数据上做过一次空间聚类,结果发现几个“细胞”其实是死细胞碎片——分割算法把碎片当成了细胞,导致聚类结果中出现一堆很小的异常簇。后来我加了面积和圆形度过滤(p_ratio < 0.5的扔掉),才得到干净的聚类结果。
- ST/Visium:网格点阵,每个spot混合多个细胞,适合组织区域剖析。
- Slide-seq:高密度珠粒,接近单细胞分辨,数据稀疏。
- MERFISH:真正的单细胞分辨,坐标来自细胞质心,但依赖分割精度。
3.5 四种格式的对比与BayesSpace适配
BayesSpace虽然最初是为ST和Visium设计的,但经过改进后可以兼容Slide-seq和MERFISH。关键是提供合适的空间邻接矩阵和坐标系统。下表总结了四种格式的关键属性和BayesSpace适配要点:
| 属性 | ST | Visium | Slide-seq | MERFISH |
|---|---|---|---|---|
| 分辨率 | 100μm spot | 55μm spot | 10μm bead | 单细胞 |
| 坐标来源 | 手动/图像对齐 | 阵列行列+像素 | 连续坐标(μm) | 质心坐标(μm) |
| 基因数/位点 | ~500-1000 | ~2000-5000 | ~100-500 | ~10000 |
| 数据稀疏性 | 低 | 中 | 高 | 低 |
| BayesSpace适配 | 直接支持 | 直接支持 | 需构建KNN图 | 需构建细胞邻接图 |
我记得处理一个Slide-seq数据集时,因为bead之间距离不均匀,直接用固定半径邻接矩阵效果很差。后来我改用自适应KNN(k=10),让每个bead只连接最近的10个邻居,BayesSpace聚类才收敛。
- Visium数据直接用
BayesSpace::readVisium()。 - Slide-seq先读入坐标,用
dbscan::kNN()构建邻接矩阵,再转为SpatialExperiment对象。 - MERFISH数据注意过滤低质量细胞(面积<50μm²或p_ratio<0.5的剔除)。
3.6 知识结构图:四种格式的核心处理流程
下面这张图梳理了四种格式从原始数据到BayesSpace输入的关键流程。你理解清楚这个框架,后续章节的聚类实战就会顺畅很多。
这张图展示了从四种原始数据格式,到中间预处理(坐标对齐/缩放/分割过滤),再到构建统一的SpatialExperiment对象,最后送入BayesSpace进行聚类的完整思路。你在实战中可以直接套用这个框架——改动的只是读入和预处理部分的代码。
好了,空间转录组的数据格式就聊到这。你得把这些格式的差异刻在脑子里——后续几章我们会用真正的代码把每种格式的数据喂给BayesSpace,到时候你就知道哪种预处理最省心了。