GFF3 格式简介:起源、用途、基本结构
说到基因组注释数据交换,GFF3 几乎是绕不过去的标准。我入行那会儿,拿到的第一个注释文件就是 GFF 格式,当时看到一堆制表符分隔的列,差点以为是 Excel 导错了格式。后来才知道,这东西背后有一套严谨的设计哲学。今天咱们就从根源说起,把它彻底聊透。
1.1 起源:为什么要搞出 GFF3?
GFF 全称 General Feature Format,最早是 Sanger 研究所为 GMOD(Generic Model Organism Database)项目设计的。初衷很简单:用纯文本描述基因组上的各种特征——基因、转录本、外显子、重复区等等。
早期版本有个明显痛点:特征之间的关系表达不清。比如一个基因包含多个转录本,转录本又包含外显子和 CDS,旧格式只靠列字段硬堆,解析起来特别容易出错。我在项目中就遇到过用 GFF2 描述可变剪接时,不同转录本的外显子坐标乱成一锅粥的情况。
所以到了 2005 年左右,GFF3 正式发布。它引入了几个关键设计:
- 9 列制表符结构,第 9 列用键值对塞入属性和关系信息。
- ID 和 Parent 机制,用标准属性绑定父子关系。
- 字典顺序要求,确保解析时先遇到父特征再遇到子特征。
- 坑洞(gap)和重复区的规范表达。
说白了,GFF3 就是给基因组注释上了个“关系型数据库”的灵魂,但文件格式还是纯文本,人人都能直接看。
1.2 用途:一条 GFF 能干什么?
你现在打开任意一个真核生物基因组注释项目,NCBI、Ensembl、UCSC,甚至你自己的组装项目,基本都会提供 GFF3 文件。它主要干这几件事:
- 存储基因结构:基因、mRNA、CDS、外显子、非编码 RNA、假基因等的位置和属性。
- 描述同源性和功能:通过第 9 列属性带上 GO 注释、KEGG 通路、PFAM 域等信息。
- 支持可视化:IGV、JBrowse、UCSC Genome Browser 都直接读 GFF3 画基因组轨道图。
- 作为流程中间格式:基因预测软件(如 Augustus、BRAKER)输出 GFF3,再转成其他格式或直接导入数据库。
我个人习惯是:任何注释数据分析的第一步,先对 GFF3 做一轮质控。因为后续所有分析——差异表达、变异注释、富集分析——都依赖这条链上的坐标和关系正确无误。
1.3 基本结构:九列,一个都不能少
GFF3 每行代表一个特征,总共 9 列,列间用 制表符(Tab)分隔。我见过不少新手用空格分割文件,结果解析报错找不到列,白白浪费半天时间。来看看每一列的具体含义:
| 列号 | 名称 | 描述 | 示例 |
|---|---|---|---|
| 1 | seqid | 序列 ID(染色体、scaffold 名称) | chr1 |
| 2 | source | 注释来源(软件名、数据库、实验方法) | Augustus |
| 3 | type | 特征类型(gene, mRNA, CDS, exon, UTR 等) | gene |
| 4 | start | 起始位置(1-based 闭区间) | 1000 |
| 5 | end | 终止位置 | 2000 |
| 6 | score | 得分或置信度(可选,可以用 . 表示缺失) | 0.95 |
| 7 | strand | 链方向(+ 或 - 或 . 表示未知) | + |
| 8 | phase | CDS 相位(0,1,2 表示阅读框偏移,非 CDS 用 .) | 0 |
| 9 | attributes | 键值对(分号分隔,ID 和 Parent 是核心) | ID=gene001;Name=BRCA2 |
awk -F'\t' '{print NF}' 检查每行列数。如果出现 NF!=9 的行,那多半是文件里有注释行(以 # 开头)被误处理,或者有空格冒充制表符。我当年在 Ensembl 下载的 GFF3 里就发现过几行因为 format 转换丢了一个空列,差点被坑。
1.4 核心关系:ID 与 Parent
GFF3 最精妙但也最容易出错的地方,就是第 9 列里的 ID 和 Parent 属性。它们把分散在各行的特征串成一棵层次树。举个例子:
chr1 . gene 1000 2000 . + . ID=gene001;Name=BRCA2
chr1 . mRNA 1000 1900 . + . ID=mRNA001;Parent=gene001
chr1 . exon 1000 1200 . + . ID=exon001;Parent=mRNA001
chr1 . exon 1300 1500 . + . ID=exon002;Parent=mRNA001
chr1 . CDS 1000 1200 . + 0 ID=cds001;Parent=mRNA001
chr1 . CDS 1300 1500 . + 1 ID=cds002;Parent=mRNA001
注意看:mRNA001 的 Parent=gene001,说明它属于基因 gene001;外显子和 CDS 的 Parent=mRNA001,又属于该转录本。这样解析器就能重建出整个基因结构——基因下挂多个转录本,每个转录本下挂外显子和 CDS。至于顺序,GFF3 要求所有特征按字典序排列,确保父特征先出现,不然解析器会报错。
Parent=gene001,跳过了 mRNA 层。结果下游计算转录本长度时,把所有外显子坐标混在一起,长度翻了三倍。这种错误必须靠严格校验“基因→mRNA→外显子/CDS”的层级完整性才能发现。
1.5 一张图看懂 GFF3 核心结构
下面我用一张示意图把上面说的层次关系画出来,你看了就能记住。
从图里你能看到:基因是顶层容器,mRNA 是子层,外显子和 CDS 是孙层。每个特征通过 Parent 向上指向,形成严格的三层树。我建议你在处理 GFF3 时,脑子里时刻装着这张树图——解析代码的 bug 往往就出在“父子关系断裂”上。
1.6 一个小回顾:你真正要记住的要点
- 9 列制表符分割:空格、逗号、多余的空列都会直接导致解析失败。
- ID 唯一性:整个文件中每个 ID 只能出现一次,不能重名。
- Parent 必须存在:子特征引用的 Parent 必须已经在前面的行出现。
- 坐标顺序:start ≤ end,正链上 coordinate 递增,负链上保持原样(坐标仍然写小的在左,大的在右)。
- phase 只在 CDS 有效:非 CDS 行记得用
.,填了数值会被某些工具理解成阅读框。
实战金句:GFF3 不是人类阅读友好的,但机器解析时必须严格遵循规范。你写解析代码时,建议每一列都用 .strip() 处理,并提前检查是否包含 \t。另外,attributes 列里键值对的分隔符是 ;,键值对内部的键和值用 = 连接——别把 = 写成 : 或空格。
嗯,这一章先让你对 GFF3 有个整体认识。起点和基本结构清楚了,后面我们才能聊质控的具体坑——比如坐标越界、ID 重复、缺失必要列、字典序混乱等等。那些都是我在真实项目中系统踩过的,后面会一节一节拆给你看。