///|
fn is_transcript_feature(feature : Feature) -> Bool {
feature.feature_type == "mRNA" ||
feature.feature_type == "transcript" ||
feature.feature_type == "lnc_RNA" ||
feature.feature_type == "ncRNA"
}
///|
fn child_kind(feature : Feature) -> String {
match feature.feature_type {
"exon" => "exon"
"CDS" => "cds"
"five_prime_UTR" => "utr"
"three_prime_UTR" => "utr"
"UTR" => "utr"
_ => "other"
}
}
///|
fn first_some(left : String?, right : String?) -> String? {
match left {
Some(_) => left
None => right
}
}
///|
fn build_transcript(
annotation : Annotation,
tx : Feature,
tx_id : String,
) -> TranscriptModel {
let exons : Array[Feature] = []
let cds : Array[Feature] = []
let utrs : Array[Feature] = []
let others : Array[Feature] = []
for feature in annotation.features {
let belongs = match annotation.format {
GFF3 => feature.attribute("Parent") == Some(tx_id)
GTF =>
feature.attribute("transcript_id") == Some(tx_id) &&
feature.feature_type != "transcript"
}
if belongs {
match child_kind(feature) {
"exon" => exons.push(feature)
"cds" => cds.push(feature)
"utr" => utrs.push(feature)
_ => others.push(feature)
}
}
}
{
id: tx_id,
name: first_some(tx.attribute("Name"), tx.attribute("transcript_name")),
feature: tx,
exons,
cds,
utrs,
others,
}
}
///|
fn build_gene(
annotation : Annotation,
gene : Feature,
gene_id : String,
) -> GeneModel {
let transcripts : Array[TranscriptModel] = []
let others : Array[Feature] = []
for feature in annotation.features {
match annotation.format {
GFF3 =>
if is_transcript_feature(feature) &&
feature.attribute("Parent") == Some(gene_id) {
let tx_id = feature.attribute("ID").unwrap_or(feature.feature_type)
transcripts.push(build_transcript(annotation, feature, tx_id))
} else if feature.attribute("Parent") == Some(gene_id) {
others.push(feature)
}
GTF =>
if is_transcript_feature(feature) &&
feature.attribute("gene_id") == Some(gene_id) {
let tx_id = feature
.attribute("transcript_id")
.unwrap_or(feature.feature_type)
transcripts.push(build_transcript(annotation, feature, tx_id))
}
}
}
{
id: gene_id,
name: first_some(gene.attribute("Name"), gene.attribute("gene_name")),
feature: gene,
transcripts,
others,
}
}
///|
pub fn Annotation::to_gene_models(self : Annotation) -> Array[GeneModel] {
let genes : Array[GeneModel] = []
for feature in self.features {
match self.format {
GFF3 =>
if feature.feature_type == "gene" {
let gene_id = feature.attribute("ID").unwrap_or(feature.seqid)
genes.push(build_gene(self, feature, gene_id))
}
GTF =>
if feature.feature_type == "gene" {
let gene_id = feature.attribute("gene_id").unwrap_or(feature.seqid)
genes.push(build_gene(self, feature, gene_id))
}
}
}
genes
}