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)分隔。我见过不少新手用空格分割文件,结果解析报错找不到列,白白浪费半天时间。来看看每一列的具体含义:

列号名称描述示例
1seqid序列 ID(染色体、scaffold 名称)chr1
2source注释来源(软件名、数据库、实验方法)Augustus
3type特征类型(gene, mRNA, CDS, exon, UTR 等)gene
4start起始位置(1-based 闭区间)1000
5end终止位置2000
6score得分或置信度(可选,可以用 . 表示缺失)0.95
7strand链方向(+ 或 - 或 . 表示未知)+
8phaseCDS 相位(0,1,2 表示阅读框偏移,非 CDS 用 .)0
9attributes键值对(分号分隔,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 要求所有特征按字典序排列,确保父特征先出现,不然解析器会报错。

经典避坑现场:我曾经处理过一个第三方提供的 GFF3,发现有的外显子居然直接 Parent=gene001,跳过了 mRNA 层。结果下游计算转录本长度时,把所有外显子坐标混在一起,长度翻了三倍。这种错误必须靠严格校验“基因→mRNA→外显子/CDS”的层级完整性才能发现。

1.5 一张图看懂 GFF3 核心结构

下面我用一张示意图把上面说的层次关系画出来,你看了就能记住。

GFF3 层次结构与 9 列关系 seqid | source | type | start | end | score | strand | phase | attributes type=gene ID=gene001 type=mRNA Parent=gene001 type=mRNA Parent=gene001 exon (2个) exon (2个) exon (2个) exon (2个) CDS 与 exon 共享坐标,但多了 phase 列(0/1/2) Parent 必须指向对应 mRNA,不能直接指 gene

从图里你能看到:基因是顶层容器,mRNA 是子层,外显子和 CDS 是孙层。每个特征通过 Parent 向上指向,形成严格的三层树。我建议你在处理 GFF3 时,脑子里时刻装着这张树图——解析代码的 bug 往往就出在“父子关系断裂”上。

1.6 一个小回顾:你真正要记住的要点

  • 9 列制表符分割:空格、逗号、多余的空列都会直接导致解析失败。
  • ID 唯一性:整个文件中每个 ID 只能出现一次,不能重名。
  • Parent 必须存在:子特征引用的 Parent 必须已经在前面的行出现。
  • 坐标顺序:start ≤ end,正链上 coordinate 递增,负链上保持原样(坐标仍然写小的在左,大的在右)。
  • phase 只在 CDS 有效:非 CDS 行记得用 .,填了数值会被某些工具理解成阅读框。

实战金句:GFF3 不是人类阅读友好的,但机器解析时必须严格遵循规范。你写解析代码时,建议每一列都用 .strip() 处理,并提前检查是否包含 \t。另外,attributes 列里键值对的分隔符是 ;,键值对内部的键和值用 = 连接——别把 = 写成 : 或空格。

嗯,这一章先让你对 GFF3 有个整体认识。起点和基本结构清楚了,后面我们才能聊质控的具体坑——比如坐标越界、ID 重复、缺失必要列、字典序混乱等等。那些都是我在真实项目中系统踩过的,后面会一节一节拆给你看。