四、空间坐标系统与组织区域标注

说起空间坐标系统,我刚开始搞空间转录组时,总觉得这玩意儿就是个“给每个捕获点贴个坐标标签”的事。后来踩了几个坑才发现——坐标系统搞不对,后面所有邻域分析都是白搭。今天咱们就把这个基础扎稳。

4.1 坐标系统:空间数据的“第一性原理”

空间坐标系统,说白了就是给每个捕获点(比如Spot、Bead、Cell)一个物理位置。我习惯把它分成两大类:非网格坐标和网格坐标。这俩的区别,你想想看,就像随意撒了一把豆子和把豆子整整齐齐码在格子里。

类型 代表平台 坐标特点 邻域计算代价
非网格坐标 Slide-seq、MERFISH 浮点数坐标,点间距不均匀 高(需KD-Tree或近似算法)
网格坐标 10x Visium、HD 整数或离散坐标,点有固定间距 低(可直接用索引偏移)

在项目里我遇到过这样一个情况:用Float64存的坐标文件,读进来做KD-Tree构建,内存直接飙到32GB。后来换成整数索引再加空间哈希,瞬间降到4GB。值不值得?你自己掂量。

4.2 坐标数据的标准格式

我个人习惯用统一的表格结构来管理坐标数据,尽量避免“一个平台一个格式”的局面。下面是我常用的坐标元数据表结构:

spot_id      x        y      array_row   array_col  tissue
VIS_001    124.5   322.1         1           2        1
VIS_002    125.1   323.4         1           3        1
VIS_003    110.2   298.7         2           5        0

tissue 字段标记该点是否落在组织内,0为背景,1为组织区域。这个字段虽然不起眼,但在切片配准的时候特别有用。我曾经因为没加这个标记,把一堆背景点的噪声算进了邻域统计里,结果捣腾了三天才发现问题。

4.3 组织区域标注:从坐标到区域

有了坐标之后,下一步就是给每个点赋予“区域标签”。常见的方法有三种:

  1. 手动标注——基于H&E图像或荧光图像,人工画出区域多边形。
  2. 基于基因表达的聚类标注——先聚类,再根据已知Marker基因给区域命名。
  3. 基于组织学图像的分割——用像素分割模型(比如Hover-Net)自动切出区域。

我推荐的做法是“先自动、后手动矫正”。自动化能省力气,但边界区域的错标率往往很高。我在一个心脏切片项目里,算法把心肌边界多划了100微米,结果下游的配受体分析全偏了。最后还是靠手动逐张校准。

4.4 标注数据的存储与关联

标注结果(区域标签)和坐标数据要对应起来。通常有两种存储思路:

思路一:在坐标表里直接加区域列。适合标注区域少、结构固定的场景。比如:

spot_id      x        y      region_label
VIS_001    124.5   322.1   "Cortex_LAYER2"
VIS_002    125.1   323.4   "Cortex_LAYER2"

思路二:用区域坐标范围查询。把区域存成一个多边形列表,然后通过空间索引动态查询每个点落在哪个多边形里。优点是很灵活,适合区域边界复杂的场景。我自己写过一个简化版:

regions = {
    "Cortex_L2": {"type": "polygon", "coords": [(120,320), (130,320), (130,330), (120,330)]},
    "Cortex_L3": {"type": "polygon", "coords": [(120,330), (130,330), (130,340), (120,340)]},
}

然后写一个函数判断点是否在多边形内:

def point_in_region(x, y, region_coords):
    # 射线法判断
    inside = False
    n = len(region_coords)
    j = n - 1
    for i in range(n):
        xi, yi = region_coords[i]
        xj, yj = region_coords[j]
        if ((yi > y) != (yj > y)) and (x < (xj - xi) * (y - yi) / (yj - yi) + xi):
            inside = not inside
        j = i
    return inside

一点经验:记得把区域边界向外多扩展一个点的间距。我曾为了卡边界卡得太死,导致边界上的细胞丢了将近1/3。预留一个缓冲半径,比如Visium可以设50微米,就能把大部分交界区域的细胞保住。

4.5 坐标同源性:跨切片对齐的关键

当你要分析多个切片、多个样本时,它们之间的坐标系统必须“同源”。什么意思呢?就是同一套坐标原点、同一套缩放比例、同一套切片朝向。我不止一次看到有人把一个样本的芯片坐标当成物理坐标去跟另一个样本硬对齐,结果差了几百微米。

我建议的坐标同源流程:

  • 先统一用芯片坐标(array_row, array_col)做基础对齐。
  • 再根据H&E图像计算的仿射变换,把坐标映射到统一的物理空间。
  • 最后用手工标注的解剖地标(比如海马体、皮质条纹)做二次配准。

注意:千万别把一个切片在显微镜下的旋转角度忽略掉。2度的旋转在1毫米的切片边缘就能造成35微米的偏移。一个完整的数据处理流程中,旋转纠偏应该是默认开启的步骤。

4.6 知识体系总览

下面这张图帮你把本章的逻辑理一理。从坐标系统到区域标注,再到数据整合,整个链路一次串清楚。

空间坐标系统与组织区域标注 · 知识体系 坐标系统 非网格坐标 Slide-seq, MERFISH 网格坐标 10x Visium, HD 坐标同源 + 旋转纠偏 组织区域标注 手动标注 H&E 图像勾画 聚类+Marker 基因表达驱动 “先自动、后手动” 数据整合与输出 坐标表 + 区域标签 空间索引(KD-Tree/哈希) 跨切片对齐(仿射变换) 下游邻域特征建模 ⚡ 坐标系统是空间数据的“地基”——地基歪了,上面的分析再好看也是危房

坐标对齐和组织标注这两步,看起来像是数据预处理的“体力活”,但实际上它决定了后面所有分析的准确性。我每次拿起一个新的空间数据集,前30%的时间都花在确认坐标正确、标注完整上。别嫌慢,磨刀不误砍柴工。