-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathextract_genes.py
More file actions
100 lines (77 loc) · 3.15 KB
/
Copy pathextract_genes.py
File metadata and controls
100 lines (77 loc) · 3.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import re
from Bio import SeqIO
from Bio.Seq import Seq
from Bio.SeqRecord import SeqRecord
import argparse
def parse_gff_genes(gff_file):
"""Parse GFF file to extract gene coordinates and attributes"""
genes = {}
with open(gff_file, 'r') as f:
for line in f:
if line.startswith('#'):
continue
fields = line.strip().split('\t')
if len(fields) < 9:
continue
feature_type = fields[2]
if feature_type != 'gene':
continue
contig = fields[0]
start = int(fields[3]) - 1 # Convert to 0-based
end = int(fields[4])
strand = fields[6]
attributes = fields[8]
gene_id = None
gene_name = None
for attr in attributes.split(';'):
if attr.startswith('ID='):
gene_id = attr.split('=')[1]
elif attr.startswith('Name='):
gene_name = attr.split('=')[1]
elif attr.startswith('gene_id='):
gene_id = attr.split('=')[1]
elif attr.startswith('gene_name='):
gene_name = attr.split('=')[1]
if gene_id:
genes[gene_id] = {
'contig': contig,
'start': start,
'end': end,
'strand': strand,
'name': gene_name or gene_id
}
return genes
def extract_gene_sequences(fasta_file, genes, output_file):
"""Extract gene sequences from fasta file"""
ref_sequences = SeqIO.to_dict(SeqIO.parse(fasta_file, 'fasta'))
gene_records = []
for gene_id, gene_info in genes.items():
contig = gene_info['contig']
start = gene_info['start']
end = gene_info['end']
strand = gene_info['strand']
name = gene_info['name']
if contig not in ref_sequences:
print(f"Warning: Contig {contig} not found in reference fasta")
continue
seq = ref_sequences[contig].seq[start:end]
if strand == '-':
seq = seq.reverse_complement()
record = SeqRecord(
seq,
id=name,
description=f"gene_id={gene_id} {contig}:{start+1}-{end} strand={strand}"
)
gene_records.append(record)
SeqIO.write(gene_records, output_file, 'fasta')
print(f"Extracted {len(gene_records)} genes to {output_file}")
def main():
parser = argparse.ArgumentParser(description='Extract gene sequences from reference assembly')
parser.add_argument('--fasta', required=True, help='Reference assembly fasta file')
parser.add_argument('--gff', required=True, help='GFF annotation file')
parser.add_argument('--output', required=True, help='Output fasta file with gene sequences')
args = parser.parse_args()
genes = parse_gff_genes(args.gff)
extract_gene_sequences(args.fasta, genes, args.output)
if __name__ == '__main__':
main()