ORForise 1.4.3__py3-none-any.whl → 1.5.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ORForise/Aggregate_Compare.py +318 -133
- ORForise/Annotation_Compare.py +294 -125
- ORForise/Comparator.py +656 -576
- ORForise/ORForise_Analysis/genome_Metrics.py +51 -33
- ORForise/Tools/Augustus/Augustus.py +30 -23
- ORForise/Tools/Balrog/Balrog.py +31 -23
- ORForise/Tools/EasyGene/EasyGene.py +30 -22
- ORForise/Tools/FGENESB/FGENESB.py +32 -25
- ORForise/Tools/FragGeneScan/FragGeneScan.py +29 -22
- ORForise/Tools/GFF/GFF.py +51 -47
- ORForise/Tools/GLIMMER_3/GLIMMER_3.py +34 -27
- ORForise/Tools/GeneMark/GeneMark.py +46 -40
- ORForise/Tools/GeneMark_HA/GeneMark_HA.py +29 -22
- ORForise/Tools/GeneMark_HMM/GeneMark_HMM.py +29 -22
- ORForise/Tools/GeneMark_S/GeneMark_S.py +29 -22
- ORForise/Tools/GeneMark_S_2/GeneMark_S_2.py +29 -25
- ORForise/Tools/MetaGene/MetaGene.py +29 -22
- ORForise/Tools/MetaGeneAnnotator/MetaGeneAnnotator.py +30 -23
- ORForise/Tools/MetaGeneMark/MetaGeneMark.py +30 -23
- ORForise/Tools/Prodigal/Prodigal.py +30 -26
- ORForise/Tools/Prokka/Prokka.py +30 -25
- ORForise/Tools/StORF_Reporter/StORF_Reporter.py +33 -26
- ORForise/Tools/TransDecoder/TransDecoder.py +29 -22
- ORForise/utils.py +204 -2
- {orforise-1.4.3.dist-info → orforise-1.5.1.dist-info}/METADATA +7 -31
- {orforise-1.4.3.dist-info → orforise-1.5.1.dist-info}/RECORD +30 -30
- {orforise-1.4.3.dist-info → orforise-1.5.1.dist-info}/entry_points.txt +5 -0
- {orforise-1.4.3.dist-info → orforise-1.5.1.dist-info}/WHEEL +0 -0
- {orforise-1.4.3.dist-info → orforise-1.5.1.dist-info}/licenses/LICENSE +0 -0
- {orforise-1.4.3.dist-info → orforise-1.5.1.dist-info}/top_level.txt +0 -0
ORForise/Annotation_Compare.py
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
from importlib import import_module
|
|
2
2
|
import argparse
|
|
3
|
-
import
|
|
4
|
-
import csv
|
|
5
|
-
|
|
3
|
+
import sys, os
|
|
4
|
+
import gzip, csv
|
|
5
|
+
import logging
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
|
|
8
|
+
|
|
6
9
|
try:
|
|
7
10
|
from Comparator import tool_comparison
|
|
8
11
|
except ImportError:
|
|
@@ -13,46 +16,43 @@ try:
|
|
|
13
16
|
except ImportError:
|
|
14
17
|
from ORForise.utils import *
|
|
15
18
|
|
|
19
|
+
|
|
20
|
+
##########################
|
|
21
|
+
|
|
22
|
+
# Consolidate printing and logging into a single block
|
|
23
|
+
def _pct(n, total):
|
|
24
|
+
try:
|
|
25
|
+
return format(100 * n / total, '.2f') + '%'
|
|
26
|
+
except Exception:
|
|
27
|
+
return 'N/A'
|
|
28
|
+
|
|
16
29
|
##########################
|
|
17
30
|
|
|
18
31
|
def comparator(options):
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
try:
|
|
29
|
-
if "CDS" in line[2] and len(line) == 9:
|
|
30
|
-
start = int(line[3])
|
|
31
|
-
stop = int(line[4])
|
|
32
|
-
strand = line[6]
|
|
33
|
-
gene_details = [start,stop,strand]
|
|
34
|
-
ref_genes.update({count:gene_details})
|
|
35
|
-
count += 1
|
|
36
|
-
except IndexError:
|
|
37
|
-
continue
|
|
38
|
-
ref_genes = sortGenes(ref_genes) # sorted GFF refernce
|
|
39
|
-
else: # IF using a tool as reference
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
try:
|
|
35
|
+
try: # Detect whether fasta/gff files are .gz or text and read accordingly
|
|
36
|
+
fasta_in = gzip.open(options.genome_dna, 'rt')
|
|
37
|
+
dna_regions = fasta_load(fasta_in)
|
|
38
|
+
except:
|
|
39
|
+
fasta_in = open(options.genome_dna, 'r', encoding='unicode_escape')
|
|
40
|
+
dna_regions = fasta_load(fasta_in)
|
|
40
41
|
try:
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
except
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
ref_genes.update({i:[pos[0],pos[1],details[0]]})
|
|
42
|
+
gff_in = gzip.open(options.reference_annotation, 'rt')
|
|
43
|
+
dna_regions = gff_load(options, gff_in, dna_regions)
|
|
44
|
+
except:
|
|
45
|
+
gff_in = open(options.reference_annotation, 'r', encoding='unicode_escape')
|
|
46
|
+
dna_regions = gff_load(options, gff_in, dna_regions)
|
|
47
|
+
except AttributeError:
|
|
48
|
+
sys.exit("Attribute Error:\nStORF'ed GFF probably already exists - Must be deleted before running (-overwrite)")
|
|
49
|
+
except FileNotFoundError:
|
|
50
|
+
split_path = options.gff.split(os.sep)
|
|
51
|
+
sys.exit("Directory '" + split_path[-2] + "' missing fna/gff files")
|
|
52
|
+
###############################################
|
|
53
|
+
total_ref_genes = sum(
|
|
54
|
+
len(v[2]) if isinstance(v[2], (list, tuple, set, dict, str)) else 1 for v in dna_regions.values())
|
|
55
|
+
|
|
56
56
|
#############################################
|
|
57
57
|
try:
|
|
58
58
|
tool_ = import_module('Tools.' + options.tool + '.' + options.tool, package='my_current_pkg')
|
|
@@ -62,90 +62,237 @@ def comparator(options):
|
|
|
62
62
|
except ModuleNotFoundError:
|
|
63
63
|
sys.exit("Tool not available - Did you get the name right?")
|
|
64
64
|
tool_ = getattr(tool_, options.tool)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
ref_genes, orfs, genome_Seq, options.verbose)
|
|
68
|
-
############################################# To get default output filename from input file details
|
|
69
|
-
genome_name = options.reference_annotation.split('/')[-1].split('.')[0]
|
|
70
|
-
metric_description = list(all_Metrics.keys())
|
|
71
|
-
metrics = list(all_Metrics.values())
|
|
72
|
-
rep_metric_description = list(all_rep_Metrics.keys())
|
|
73
|
-
rep_metrics = list(all_rep_Metrics.values())
|
|
65
|
+
all_orfs = tool_(options.tool_prediction, dna_regions)
|
|
66
|
+
results = tool_comparison(all_orfs, dna_regions, options.verbose)
|
|
74
67
|
############## Printing to std-out and optional csv file
|
|
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
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
68
|
+
# Ensure the output directory exists
|
|
69
|
+
os.makedirs(options.outdir, exist_ok=True)
|
|
70
|
+
# Use outname as a directory, basename for files is output-outname
|
|
71
|
+
base_out = os.path.join(options.outdir, f"{os.path.basename(options.outname)}")
|
|
72
|
+
|
|
73
|
+
# Prepare to collect summary stats for all contigs
|
|
74
|
+
contig_summaries = []
|
|
75
|
+
|
|
76
|
+
if options.outdir:
|
|
77
|
+
# Ensure the output directory exists
|
|
78
|
+
os.makedirs(options.outdir, exist_ok=True)
|
|
79
|
+
# Use outname as a directory, basename for files is output-outname
|
|
80
|
+
base_out = os.path.join(options.outdir, f"{os.path.basename(options.outname)}")
|
|
81
|
+
with open(f"{base_out}_summary.txt", 'w', encoding='utf-8') as out_file:
|
|
82
|
+
out_file.write('Genome Used: ' + str(options.genome_dna.split('/')[-1]) + '\n')
|
|
83
|
+
if options.reference_tool:
|
|
84
|
+
out_file.write('Reference Tool Used: ' + str(options.reference_tool) + '\n')
|
|
85
|
+
else:
|
|
86
|
+
out_file.write('Reference Used: ' + str(options.reference_annotation.split('/')[-1]) + '\n')
|
|
87
|
+
out_file.write('Tool Compared: ' + str(options.tool) + '\n')
|
|
88
|
+
out_file.write('Total Number of Reference Genes: ' + str(total_ref_genes) + '\n')
|
|
89
|
+
out_file.write('Number of Contigs: ' + str(len(dna_regions)) + '\n')
|
|
90
|
+
out_file.write(
|
|
91
|
+
'Contig\tGenes\tORFs\tPerfect_Matches\tPartial_Matches\tMissed_Genes\tUnmatched_ORFs\tMulti_Matched_ORFs\n')
|
|
92
|
+
|
|
93
|
+
for dna_region, result in results.items():
|
|
94
|
+
if result:
|
|
95
|
+
num_current_genes = len(dna_regions[dna_region][2])
|
|
96
|
+
num_orfs = result['pred_metrics']['Number_of_ORFs']
|
|
97
|
+
num_perfect = result['pred_metrics']['Number_of_Perfect_Matches']
|
|
98
|
+
num_partial = len(result['pred_metrics']['partial_Hits'])
|
|
99
|
+
num_missed = len(result['rep_metrics']['genes_Undetected'])
|
|
100
|
+
num_unmatched = len(result['pred_metrics']['unmatched_ORFs'])
|
|
101
|
+
num_multi = len(result['pred_metrics']['multi_Matched_ORFs'])
|
|
102
|
+
# Collect summary for this contig
|
|
103
|
+
contig_summaries.append([dna_region, num_current_genes, num_orfs, num_perfect, num_partial, num_missed, num_unmatched, num_multi])
|
|
104
|
+
num_current_genes = len(dna_regions[dna_region][2])
|
|
105
|
+
genome_name = options.reference_annotation.split('/')[-1].split('.')[0]
|
|
106
|
+
rep_metric_description, rep_metrics = get_rep_metrics(result)
|
|
107
|
+
all_metric_description, all_metrics = get_all_metrics(result)
|
|
108
|
+
|
|
109
|
+
# Safely extract metric values
|
|
110
|
+
num_orfs = result.get('pred_metrics', {}).get('Number_of_ORFs') if isinstance(result, dict) else 'N/A'
|
|
111
|
+
perfect = result.get('pred_metrics', {}).get('Number_of_Perfect_Matches') if isinstance(result, dict) else 0
|
|
112
|
+
partial = len(result.get('pred_metrics', {}).get('partial_Hits', [])) if isinstance(result, dict) else 'N/A'
|
|
113
|
+
missed = len(result.get('rep_metrics', {}).get('genes_Undetected', [])) if isinstance(result, dict) else 'N/A'
|
|
114
|
+
unmatched = len(result.get('pred_metrics', {}).get('unmatched_ORFs', [])) if isinstance(result, dict) else 'N/A'
|
|
115
|
+
multi = len(result.get('pred_metrics', {}).get('multi_Matched_ORFs', [])) if isinstance(result, dict) else 'N/A'
|
|
116
|
+
|
|
117
|
+
lines = [
|
|
118
|
+
f"These are the results for: {dna_region}",
|
|
119
|
+
f"Current Contig: {dna_region}",
|
|
120
|
+
f"Number of Genes: {num_current_genes}",
|
|
121
|
+
f"Number of ORFs: {num_orfs}",
|
|
122
|
+
f"Perfect Matches: {perfect} [{num_current_genes}] - {_pct(perfect, num_current_genes) if isinstance(num_current_genes, (int, float)) else 'N/A'}",
|
|
123
|
+
f"Partial Matches: {partial} [{num_current_genes}] - {_pct(partial, num_current_genes) if isinstance(num_current_genes, (int, float)) else 'N/A'}",
|
|
124
|
+
f"Missed Genes: {missed} [{num_current_genes}] - {_pct(missed, num_current_genes) if isinstance(num_current_genes, (int, float)) else 'N/A'}",
|
|
125
|
+
f"Unmatched ORFs: {unmatched} [{num_current_genes}] - {_pct(unmatched, num_current_genes) if isinstance(num_current_genes, (int, float)) else 'N/A'}",
|
|
126
|
+
f"Multi-matched ORFs: {multi} [{num_current_genes}] - {_pct(multi, num_current_genes) if isinstance(num_current_genes, (int, float)) else 'N/A'}"
|
|
127
|
+
]
|
|
128
|
+
|
|
129
|
+
full_msg = '\n'.join(lines) + '\n'
|
|
130
|
+
if options.verbose:
|
|
131
|
+
print(full_msg)
|
|
132
|
+
options.output_logger.info(full_msg)
|
|
133
|
+
|
|
134
|
+
# print("These are the results for: " + dna_region + '\n')
|
|
135
|
+
# print('Current Contig: ' + str(dna_region))
|
|
136
|
+
# print('Number of Genes: ' + str(num_current_genes))
|
|
137
|
+
# print('Number of ORFs: ' + str(result['pred_metrics']['Number_of_ORFs']))
|
|
138
|
+
# print('Perfect Matches: ' + str(result['pred_metrics']['Number_of_Perfect_Matches']) + ' [' + str(num_current_genes)+ '] - '+ format(100 * result['pred_metrics']['Number_of_Perfect_Matches']/num_current_genes,'.2f')+'%')
|
|
139
|
+
# print('Partial Matches: ' + str(len(result['pred_metrics']['partial_Hits'])) + ' [' + str(num_current_genes)+ '] - '+ format(100 * len(result['pred_metrics']['partial_Hits'])/num_current_genes,'.2f')+'%')
|
|
140
|
+
# print('Missed Genes: ' + str(len(result['rep_metrics']['genes_Undetected'])) + ' [' + str(num_current_genes)+ '] - '+ format(100 * len(result['rep_metrics']['genes_Undetected'])/num_current_genes,'.2f')+'%')
|
|
141
|
+
# print('Unmatched ORFs: ' + str(len(result['pred_metrics']['unmatched_ORFs'])) + ' [' + str(num_current_genes)+ '] - '+ format(100 * len(result['pred_metrics']['unmatched_ORFs'])/num_current_genes,'.2f')+'%')
|
|
142
|
+
# print('Multi-matched ORFs: ' + str(len(result['pred_metrics']['multi_Matched_ORFs'])) + ' [' + str(num_current_genes)+ '] - '+ format(100 * len(result['pred_metrics']['multi_Matched_ORFs'])/num_current_genes,'.2f')+'%')
|
|
143
|
+
|
|
144
|
+
# Prepare output directory and file names for each contig
|
|
145
|
+
contig_save = dna_region.replace('/', '_').replace('\\', '_')
|
|
146
|
+
contig_dir = os.path.join(options.outdir, contig_save)
|
|
147
|
+
os.makedirs(contig_dir, exist_ok=True)
|
|
148
|
+
summary_file = os.path.join(contig_dir, "summary.txt")
|
|
149
|
+
csv_file = os.path.join(contig_dir, "metrics.csv")
|
|
150
|
+
perfect_fasta = os.path.join(contig_dir, "perfect_matches.fasta")
|
|
151
|
+
partial_fasta = os.path.join(contig_dir, "partial_matches.fasta")
|
|
152
|
+
missed_fasta = os.path.join(contig_dir, "missed_genes.fasta")
|
|
153
|
+
unmatched_fasta = os.path.join(contig_dir, "unmatched_orfs.fasta")
|
|
154
|
+
multi_fasta = os.path.join(contig_dir, "multi_matched_orfs.fasta")
|
|
155
|
+
|
|
156
|
+
# Write summary to text file
|
|
157
|
+
with open(summary_file, 'w', encoding='utf-8') as sf:
|
|
158
|
+
sf.write('Current Contig: ' + str(dna_region) + '\n')
|
|
159
|
+
sf.write('Number of Genes: ' + str(num_current_genes) + '\n')
|
|
160
|
+
sf.write('Number of ORFs: ' + str(result['pred_metrics']['Number_of_ORFs']) + '\n')
|
|
161
|
+
sf.write('Perfect Matches: ' + str(result['pred_metrics']['Number_of_Perfect_Matches']) + ' [' + str(
|
|
162
|
+
num_current_genes) + '] - ' + format(
|
|
163
|
+
100 * result['pred_metrics']['Number_of_Perfect_Matches'] / num_current_genes, '.2f') + '%\n')
|
|
164
|
+
sf.write('Partial Matches: ' + str(len(result['pred_metrics']['partial_Hits'])) + ' [' + str(
|
|
165
|
+
num_current_genes) + '] - ' + format(
|
|
166
|
+
100 * len(result['pred_metrics']['partial_Hits']) / num_current_genes, '.2f') + '%\n')
|
|
167
|
+
sf.write('Missed Genes: ' + str(len(result['rep_metrics']['genes_Undetected'])) + ' [' + str(
|
|
168
|
+
num_current_genes) + '] - ' + format(
|
|
169
|
+
100 * len(result['rep_metrics']['genes_Undetected']) / num_current_genes, '.2f') + '%\n')
|
|
170
|
+
sf.write('Unmatched ORFs: ' + str(len(result['pred_metrics']['unmatched_ORFs'])) + ' [' + str(
|
|
171
|
+
num_current_genes) + '] - ' + format(
|
|
172
|
+
100 * len(result['pred_metrics']['unmatched_ORFs']) / num_current_genes, '.2f') + '%\n')
|
|
173
|
+
sf.write('Multi-matched ORFs: ' + str(len(result['pred_metrics']['multi_Matched_ORFs'])) + ' [' + str(
|
|
174
|
+
num_current_genes) + '] - ' + format(
|
|
175
|
+
100 * len(result['pred_metrics']['multi_Matched_ORFs']) / num_current_genes, '.2f') + '%\n')
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
# Write metrics to CSV
|
|
179
|
+
with open(csv_file, 'w', newline='\n', encoding='utf-8') as out_file:
|
|
180
|
+
tool_out = csv.writer(out_file, quoting=csv.QUOTE_NONE, escapechar=" ")
|
|
181
|
+
tool_out.writerow(['Representative_Metrics:'])
|
|
182
|
+
tool_out.writerow(rep_metric_description.split(','))
|
|
183
|
+
tool_out.writerow([*rep_metrics])
|
|
184
|
+
tool_out.writerow(['Prediction_Metrics:'])
|
|
185
|
+
tool_out.writerow(all_metric_description.split(','))
|
|
186
|
+
tool_out.writerow([*all_metrics])
|
|
187
|
+
tool_out.writerow(['Reference_CDS_Gene_Coverage_of_Genome'])
|
|
188
|
+
tool_out.writerow([''.join(map(str, result['rep_metrics']['gene_Coverage_Genome']))])
|
|
189
|
+
tool_out.writerow(['Predicted_CDS_Coverage_of_Genome'])
|
|
190
|
+
tool_out.writerow([''.join(map(str, result['pred_metrics']['orf_Coverage_Genome']))])
|
|
191
|
+
tool_out.writerow(['Matched_Predicted_CDS_Coverage_of_Genome'])
|
|
192
|
+
tool_out.writerow([''.join(map(str, result['pred_metrics']['matched_ORF_Coverage_Genome']))])
|
|
193
|
+
# tool_out.writerow(['Start_Position_Difference:'])
|
|
194
|
+
# tool_out.writerow(result.get('start_Difference', []))
|
|
195
|
+
# tool_out.writerow(['Stop_Position_Difference:'])
|
|
196
|
+
# tool_out.writerow(result.get('stop_Difference', []))
|
|
197
|
+
# tool_out.writerow(['Alternative_Starts_Predicted:'])
|
|
198
|
+
# tool_out.writerow(result.get('other_Starts', []))
|
|
199
|
+
# tool_out.writerow(['Alternative_Stops_Predicted:'])
|
|
200
|
+
# tool_out.writerow(result.get('other_Stops', []))
|
|
201
|
+
# tool_out.writerow(['Undetected_Gene_Metrics:'])
|
|
202
|
+
# tool_out.writerow([
|
|
203
|
+
# 'ATG_Start,GTG_Start,TTG_Start,ATT_Start,CTG_Start,Alternative_Start_Codon,TGA_Stop,TAA_Stop,TAG_Stop,Alternative_Stop_Codon,Median_Length,ORFs_on_Positive_Strand,ORFs_on_Negative_Strand'
|
|
204
|
+
# ])
|
|
205
|
+
# tool_out.writerow(result.get('undetected_Gene_Metrics', []))
|
|
206
|
+
# tool_out.writerow(['\nPredicted_CDSs_Without_Corresponding_Gene_In_Reference_Metrics:'])
|
|
207
|
+
# tool_out.writerow([
|
|
208
|
+
# 'ATG_Start,GTG_Start,TTG_Start,ATT_Start,CTG_Start,Alternative_Start_Codon,TGA_Stop,TAA_Stop,TAG_Stop,Alternative_Stop_Codon,Median_Length,ORFs_on_Positive_Strand,ORFs_on_Negative_Strand'
|
|
209
|
+
# ])
|
|
210
|
+
# tool_out.writerow(result.get('unmatched_ORF_Metrics', []))
|
|
211
|
+
|
|
212
|
+
# Write perfect matches to FASTA
|
|
213
|
+
with open(perfect_fasta, 'w', encoding='utf-8') as f:
|
|
214
|
+
for key, value in result['pred_metrics'].get('perfect_Matches', {}).items():
|
|
215
|
+
key_parts = key.split(',')
|
|
216
|
+
id = f">{genome_name}_{key_parts[0]}_{key_parts[1]}_{key_parts[2]}_{key_parts[5]}"
|
|
217
|
+
f.write(f"{id}\n{value}\n")
|
|
218
|
+
|
|
219
|
+
# Write partial matches to FASTA
|
|
220
|
+
with open(partial_fasta, 'w', encoding='utf-8') as f:
|
|
221
|
+
for key, value in result['pred_metrics'].get('partial_Hits', {}).items():
|
|
222
|
+
key_parts = key.split(';')
|
|
223
|
+
gene_Seq = value[0]
|
|
224
|
+
orf_Seq = value[1]
|
|
225
|
+
f.write(f">{key_parts[0]}_gene\n{gene_Seq}\n>{key_parts[1]}_orf\n{orf_Seq}\n")
|
|
226
|
+
|
|
227
|
+
# Write missed genes to FASTA
|
|
228
|
+
with open(missed_fasta, 'w', encoding='utf-8') as f:
|
|
229
|
+
for key, value in result['rep_metrics'].get('genes_Undetected', {}).items():
|
|
230
|
+
key_parts = key.split(',')
|
|
231
|
+
id = f">{genome_name}_{key_parts[0]}_{key_parts[1]}_{key_parts[2]}"
|
|
232
|
+
f.write(f"{id}\n{value}\n")
|
|
233
|
+
|
|
234
|
+
# Write unmatched ORFs to FASTA
|
|
235
|
+
with open(unmatched_fasta, 'w', encoding='utf-8') as f:
|
|
236
|
+
for key, value in result['pred_metrics'].get('unmatched_ORFs', {}).items():
|
|
237
|
+
key_parts = key.split(',')
|
|
238
|
+
id = f">{options.tool}_{key_parts[0]}_{key_parts[1]}_{key_parts[2]}"
|
|
239
|
+
f.write(f"{id}\n{value}\n")
|
|
240
|
+
|
|
241
|
+
# Write multi-matched ORFs to FASTA
|
|
242
|
+
with open(multi_fasta, 'w', encoding='utf-8') as f:
|
|
243
|
+
for key, value in result['pred_metrics'].get('multi_Matched_ORFs', {}).items():
|
|
244
|
+
key_parts = key.split(',')
|
|
245
|
+
multi = f">Predicted_CDS:{key_parts[0]}-{key_parts[1]}_Genes:{'|'.join(value)}"
|
|
246
|
+
f.write(f"{multi}\n")
|
|
247
|
+
else:
|
|
248
|
+
if options.verbose:
|
|
249
|
+
print(f"No results to process for dna region - " + str(dna_region))
|
|
250
|
+
options.output_logger.info(f"No results to process for dna region - " + str(dna_region))
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
# After all contigs, append the summary table to the main summary file
|
|
254
|
+
if options.outdir and contig_summaries:
|
|
255
|
+
with open(f"{base_out}_summary.txt", 'a', encoding='utf-8') as out_file:
|
|
256
|
+
for row in contig_summaries:
|
|
257
|
+
out_file.write('\t'.join(map(str, row)) + '\n')
|
|
258
|
+
# Optionally, add overall totals
|
|
259
|
+
total_genes = sum(row[1] for row in contig_summaries)
|
|
260
|
+
total_orfs = sum(row[2] for row in contig_summaries)
|
|
261
|
+
total_perfect = sum(row[3] for row in contig_summaries)
|
|
262
|
+
total_partial = sum(row[4] for row in contig_summaries)
|
|
263
|
+
total_missed = sum(row[5] for row in contig_summaries)
|
|
264
|
+
total_unmatched = sum(row[6] for row in contig_summaries)
|
|
265
|
+
total_multi = sum(row[7] for row in contig_summaries)
|
|
266
|
+
out_file.write('\nOverall Summary:\n')
|
|
267
|
+
out_file.write(f'Number of Genes: {total_genes}\n')
|
|
268
|
+
out_file.write(f'Number of ORFs: {total_orfs}\n')
|
|
269
|
+
out_file.write(
|
|
270
|
+
f'Perfect Matches: {total_perfect} [{total_genes}] - {format(100 * total_perfect / total_genes, ".2f")}%\n')
|
|
271
|
+
out_file.write(
|
|
272
|
+
f'Partial Matches: {total_partial} [{total_genes}] - {format(100 * total_partial / total_genes, ".2f")}%\n')
|
|
273
|
+
out_file.write(
|
|
274
|
+
f'Missed Genes: {total_missed} [{total_genes}] - {format(100 * total_missed / total_genes, ".2f")}%\n')
|
|
275
|
+
out_file.write(
|
|
276
|
+
f'Unmatched ORFs: {total_unmatched} [{total_genes}] - {format(100 * total_unmatched / total_genes, ".2f")}%\n')
|
|
277
|
+
out_file.write(
|
|
278
|
+
f'Multi-matched ORFs: {total_multi} [{total_genes}] - {format(100 * total_multi / total_genes, ".2f")}%\n')
|
|
279
|
+
|
|
280
|
+
lines = [
|
|
281
|
+
f"Combined metrics for all contigs:",
|
|
282
|
+
f"Number of Genes: {total_genes}",
|
|
283
|
+
f"Number of ORFs: {total_orfs}",
|
|
284
|
+
f"Perfect Matches: {total_perfect} [{total_genes}] - {format(100 * total_perfect / total_genes, ".2f")}%",
|
|
285
|
+
f"Partial Matches: {total_partial} [{total_genes}] - {format(100 * total_partial / total_genes, ".2f")}%",
|
|
286
|
+
f"Missed Genes: {total_missed} [{total_genes}] - {format(100 * total_missed / total_genes, ".2f")}%",
|
|
287
|
+
f"Unmatched ORFs: {total_unmatched} [{total_genes}] - {format(100 * total_unmatched / total_genes, ".2f")}%",
|
|
288
|
+
f"Multi-matched ORFs: {total_multi} [{total_genes}] - {format(100 * total_multi / total_genes, ".2f")}%"
|
|
289
|
+
]
|
|
290
|
+
|
|
291
|
+
full_msg = '\n'.join(lines) + '\n'
|
|
292
|
+
if options.verbose:
|
|
293
|
+
print(full_msg)
|
|
294
|
+
options.output_logger.info(full_msg)
|
|
295
|
+
|
|
149
296
|
|
|
150
297
|
def main():
|
|
151
298
|
print("Thank you for using ORForise\nPlease report any issues to: https://github.com/NickJD/ORForise/issues\n#####")
|
|
@@ -154,7 +301,7 @@ def main():
|
|
|
154
301
|
parser._action_groups.pop()
|
|
155
302
|
|
|
156
303
|
required = parser.add_argument_group('Required Arguments')
|
|
157
|
-
required.add_argument('-dna', dest='
|
|
304
|
+
required.add_argument('-dna', dest='genome_dna', required=True, help='Genome DNA file (.fa) which both annotations '
|
|
158
305
|
'are based on')
|
|
159
306
|
required.add_argument('-ref', dest='reference_annotation', required=True,
|
|
160
307
|
help='Which reference annotation file to use as reference?')
|
|
@@ -164,19 +311,41 @@ def main():
|
|
|
164
311
|
' are compared individually via separate files')
|
|
165
312
|
|
|
166
313
|
optional = parser.add_argument_group('Optional Arguments')
|
|
314
|
+
optional.add_argument('-gene_ident', action='store', dest='gene_ident', default='CDS',
|
|
315
|
+
help='What features to consider as genes? - Default: CDS - '
|
|
316
|
+
'Provide comma separated list of features to consider as genes (e.g. CDS,exon)')
|
|
167
317
|
optional.add_argument('-rt', dest='reference_tool', required=False,
|
|
168
318
|
help='What type of Annotation to compare to? -- Leave blank for Ensembl reference'
|
|
169
319
|
'- Provide tool name to compare output from two tools')
|
|
170
320
|
|
|
171
321
|
output = parser.add_argument_group('Output')
|
|
172
|
-
output.add_argument('-o', dest='
|
|
173
|
-
help='Define
|
|
322
|
+
output.add_argument('-o', dest='outdir', required=True,
|
|
323
|
+
help='Define directory where detailed output should be places')
|
|
324
|
+
output.add_argument('-n', dest='outname', required=False,
|
|
325
|
+
help='Define output filename(s) prefix - If not provided, filename of reference '
|
|
326
|
+
'annotation file will be used- <outname>_<contig_id>_ORF_Comparison.csv')
|
|
174
327
|
|
|
175
328
|
misc = parser.add_argument_group('Misc')
|
|
176
329
|
misc.add_argument('-v', dest='verbose', default='False', type=eval, choices=[True, False],
|
|
177
330
|
help='Default - False: Print out runtime status')
|
|
178
331
|
options = parser.parse_args()
|
|
179
332
|
|
|
333
|
+
options.outname = options.outname if options.outname else options.reference_annotation.split('/')[-1].split('.')[0]
|
|
334
|
+
|
|
335
|
+
# Initialise loggers once and store on options
|
|
336
|
+
if not getattr(options, 'logger_initialized', False):
|
|
337
|
+
os.makedirs(options.outdir, exist_ok=True)
|
|
338
|
+
output_log = os.path.join(options.outdir, f"ORForise_{options.outname}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log")
|
|
339
|
+
logger = logging.getLogger('ORForise.output')
|
|
340
|
+
logger.setLevel(logging.INFO)
|
|
341
|
+
fh_out = logging.FileHandler(output_log, encoding='utf-8')
|
|
342
|
+
fh_out.setFormatter(logging.Formatter('%(message)s'))
|
|
343
|
+
logger.addHandler(fh_out)
|
|
344
|
+
|
|
345
|
+
options.output_logger = logger
|
|
346
|
+
options.logger_initialized = True
|
|
347
|
+
|
|
348
|
+
|
|
180
349
|
comparator(options)
|
|
181
350
|
|
|
182
351
|
if __name__ == "__main__":
|