Python 中的简单 GFF3 解析器
问题:
你需要解析包含序列特征信息的 GFF3 文件。你倾向于使用最小、无依赖的解决方案,而不是立即将 GFF3 数据导入数据库。然而,你需要一个标准兼容的解析器
解决方案
以下解析器完全兼容 SequenceOntology GFF3 页面描述的格式,并已使用 Broad Institute 的 transcript.gff3 示例文件测试。
它包含一个完全标准兼容的属性解析器并正确处理。
几乎每个软件都有其略有不同的 GFF 格式规范。我们建议你在软件生成的示例 GFF 数据集上运行解析器,然后更改实现以满足你的要求。
与 BioPython 等软件相比,这种构建块方法不要求你要么使用标准兼容格式,要么自己编写整个解析器。
gff3_parser.py
#!/usr/bin/env python3
"""
GFF3 格式的简单解析器。
使用以下地址的 transcripts.gff3 测试
http://www.broadinstitute.org/annotation/gebo/help/gff3.html。
格式规范来源:
http://www.sequenceontology.org/gff3.shtml
版本 1.1:Python3 就绪
"""
from collections import namedtuple
import gzip
import urllib.request, urllib.parse, urllib.error
__author__ = "Uli Köhler"
__license__ = "Apache License v2.0"
__version__ = "1.1"
#初始化 GeneInfo 命名元组。注意:namedtuple 是不可变的
gffInfoFields = ["seqid", "source", "type", "start", "end", "score", "strand", "phase", "attributes"]
GFFRecord = namedtuple("GFFRecord", gffInfoFields)
def parseGFFAttributes(attributeString):
"""解析 GFF3 属性列并返回字典"""#
if attributeString == ".": return {}
ret = {}
for attribute in attributeString.split(";"):
key, value = attribute.split("=")
ret[urllib.parse.unquote(key)] = urllib.parse.unquote(value)
return ret
def parseGFF3(filename):
"""
精简的 GFF3 格式解析器。
生成包含单个 GFF3 特征信息的对象。
支持透明 gzip 解压缩。
"""
#以透明解压缩解析
openFunc = gzip.open if filename.endswith(".gz") else open
with openFunc(filename) as infile:
for line in infile:
if line.startswith("#"): continue
parts = line.strip().split("\t")
#如果失败,文件格式不兼容标准
assert len(parts) == len(gffInfoFields)
#规范化数据
normalizedInfo = {
"seqid": None if parts[0] == "." else urllib.parse.unquote(parts[0]),
"source": None if parts[1] == "." else urllib.parse.unquote(parts[1]),
"type": None if parts[2] == "." else urllib.parse.unquote(parts[2]),
"start": None if parts[3] == "." else int(parts[3]),
"end": None if parts[4] == "." else int(parts[4]),
"score": None if parts[5] == "." else float(parts[5]),
"strand": None if parts[6] == "." else urllib.parse.unquote(parts[6]),
"phase": None if parts[7] == "." else urllib.parse.unquote(parts[7]),
"attributes": parseGFFAttributes(parts[8])
}
#或者,你可以在此处发出字典,如果你需要可变性:
# yield normalizedInfo
yield GFFRecord(**normalizedInfo)
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("file", help="GFF3 输入文件(允许 .gz)")
parser.add_argument("--print-records", action="store_true", help="打印所有 GeneInfo 对象,不仅仅是")
parser.add_argument("--filter-type", help="忽略不具有给定类型的记录")
args = parser.parse_args()
#执行解析器
recordCount = 0
for record in parseGFF3(args.file):
#应用过滤器(如果有)
if args.filter_type and record.type != args.filter_type:
continue
#如果用户指定则打印记录
if args.print_records: print(record)
#像这样访问属性:my_strand = record.strand
recordCount += 1
print("Total records: %d" % recordCount)Check out similar posts by category:
Bioinformatics, Python
If this post helped you, please consider buying me a coffee or donating via PayPal to support research & publishing of new posts on TechOverflow