annotate vsnp_get_snps.py @ 4:da20c7c76d06 draft

Uploaded
author greg
date Thu, 17 Jun 2021 13:23:41 +0000
parents 14285a94fb13
children 5e4595b9f63c
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
1 #!/usr/bin/env python
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
2
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
3 # Collect quality parsimonious SNPs from vcf files
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
4 # and output alignment files in fasta format.
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
5
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
6 import argparse
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
7 import multiprocessing
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
8 import os
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
9 import queue
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
10 import shutil
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
11 import sys
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
12 import time
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
13 from collections import OrderedDict
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
14 from datetime import datetime
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
15
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
16 import pandas
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
17 import vcf
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
18
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
19
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
20 def get_time_stamp():
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
21 return datetime.fromtimestamp(time.time()).strftime('%Y-%m-%d %H-%M-%S')
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
22
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
23
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
24 def set_num_cpus(num_files, processes):
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
25 num_cpus = int(multiprocessing.cpu_count())
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
26 if num_files < num_cpus and num_files < processes:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
27 return num_files
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
28 if num_cpus < processes:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
29 half_cpus = int(num_cpus / 2)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
30 if num_files < half_cpus:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
31 return num_files
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
32 return half_cpus
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
33 return processes
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
34
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
35
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
36 def setup_all_vcfs(vcf_files, vcf_dirs):
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
37 # Create the all_vcfs directory and link
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
38 # all input vcf files into it for processing.
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
39 all_vcfs_dir = 'all_vcf'
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
40 os.makedirs(all_vcfs_dir)
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
41 vcf_dirs.append(all_vcfs_dir)
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
42 for vcf_file in vcf_files:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
43 file_name_base = os.path.basename(vcf_file)
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
44 dst_file = os.path.join(all_vcfs_dir, file_name_base)
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
45 os.symlink(vcf_file, dst_file)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
46 return vcf_dirs
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
47
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
48
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
49 class SnpFinder:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
50
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
51 def __init__(self, num_files, dbkey, input_excel, all_isolates, ac, min_mq, quality_score_n_threshold, min_quality_score, input_vcf_dir, output_json_avg_mq_dir, output_json_snps_dir, output_snps_dir, output_summary):
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
52 # Allele count
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
53 self.ac = ac
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
54 # Create a group that will contain all isolates.
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
55 self.all_isolates = all_isolates
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
56 # Evolving positions dictionary.
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
57 self.all_positions = None
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
58 # Isolate groups.
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
59 self.groups = []
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
60 # Excel file for grouping.
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
61 self.input_excel = input_excel
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
62 # Directory of input zero coverage vcf files.
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
63 self.input_vcf_dir = input_vcf_dir
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
64 # Minimum map quality value.
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
65 self.min_mq = min_mq
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
66 # Minimum quality score value.
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
67 self.min_quality_score = min_quality_score
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
68 # Number of input zero coverage vcf files.
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
69 self.num_files = num_files
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
70 # Output directory for json average mq files.
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
71 self.output_json_avg_mq_dir = output_json_avg_mq_dir
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
72 # Output directory for json snps files.
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
73 self.output_json_snps_dir = output_json_snps_dir
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
74 # Output directory for snps files.
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
75 self.output_snps_dir = output_snps_dir
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
76 # Quality score N threshold value.
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
77 self.quality_score_n_threshold = quality_score_n_threshold
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
78 self.dbkey = dbkey
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
79 self.start_time = get_time_stamp()
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
80 self.summary_str = ""
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
81 self.timer_start = datetime.now()
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
82 self.initiate_summary(output_summary)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
83
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
84 def append_to_summary(self, html_str):
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
85 # Append a string to the html summary output file.
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
86 self.summary_str = "%s%s" % (self.summary_str, html_str)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
87
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
88 def bin_input_files(self, filename, samples_groups_dict, defining_snps, inverted_defining_snps, found_positions, found_positions_mix):
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
89 # Categorize input files into closely related
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
90 # isolate groups based on discovered SNPs, and
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
91 # return a group dictionary.
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
92 sample_groups_list = []
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
93 table_name = self.get_sample_name(filename)
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
94 defining_snp = False
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
95 # Absolute positions in set union of two lists.
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
96 for abs_position in list(defining_snps.keys() & (found_positions.keys() | found_positions_mix.keys())):
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
97 group = defining_snps[abs_position]
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
98 sample_groups_list.append(group)
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
99 self.check_add_group(group)
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
100 if len(list(defining_snps.keys() & found_positions_mix.keys())) > 0:
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
101 table_name = self.get_sample_name(filename)
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
102 table_name = '%s<font color="red">[[MIXED]]</font>' % table_name
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
103 self.copy_file(filename, group)
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
104 defining_snp = True
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
105 if not set(inverted_defining_snps.keys()).intersection(found_positions.keys() | found_positions_mix.keys()):
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
106 for abs_position in list(inverted_defining_snps.keys()):
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
107 group = inverted_defining_snps[abs_position]
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
108 sample_groups_list.append(group)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
109 self.check_add_group(group)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
110 self.copy_file(filename, group)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
111 defining_snp = True
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
112 if defining_snp:
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
113 samples_groups_dict[table_name] = sorted(sample_groups_list)
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
114 else:
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
115 samples_groups_dict[table_name] = ['<font color="red">No defining SNP</font>']
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
116 return samples_groups_dict
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
117
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
118 def check_add_group(self, group):
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
119 # Add a group if it is npt already in the list.
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
120 if group not in self.groups:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
121 self.groups.append(group)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
122
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
123 def copy_file(self, filename, dir):
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
124 if not os.path.exists(dir):
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
125 os.makedirs(dir)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
126 shutil.copy(filename, dir)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
127
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
128 def decide_snps(self, filename):
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
129 # Find the SNPs in a vcf file to produce a pandas data
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
130 # frame and a dictionary containing sample map qualities.
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
131 positions_dict = self.all_positions
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
132 sample_map_qualities = {}
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
133 # Eliminate the path.
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
134 file_name_base = self.get_sample_name(filename)
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
135 vcf_reader = vcf.Reader(open(filename, 'r'))
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
136 sample_dict = {}
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
137 for record in vcf_reader:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
138 alt = str(record.ALT[0])
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
139 record_position = "%s:%s" % (str(record.CHROM), str(record.POS))
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
140 if record_position in positions_dict:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
141 if alt == "None":
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
142 sample_dict.update({record_position: "-"})
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
143 else:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
144 # On rare occassions MQM gets called "NaN", thus passing
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
145 # a string when a number is expected when calculating average.
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
146 mq_val = self.get_mq_val(record.INFO, filename)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
147 if str(mq_val).lower() not in ["nan"]:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
148 sample_map_qualities.update({record_position: mq_val})
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
149 if len(alt) == 1:
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
150 qual_val = self.val_as_int(record.QUAL)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
151 ac = record.INFO['AC'][0]
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
152 ref = str(record.REF[0])
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
153 if ac == 2 and qual_val > self.quality_score_n_threshold:
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
154 # Add the SNP to a group.
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
155 sample_dict.update({record_position: alt})
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
156 elif ac == 1 and qual_val > self.quality_score_n_threshold:
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
157 # The position is ambiguous.
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
158 alt_ref = "%s%s" % (alt, ref)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
159 if alt_ref == "AG":
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
160 sample_dict.update({record_position: "R"})
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
161 elif alt_ref == "CT":
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
162 sample_dict.update({record_position: "Y"})
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
163 elif alt_ref == "GC":
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
164 sample_dict.update({record_position: "S"})
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
165 elif alt_ref == "AT":
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
166 sample_dict.update({record_position: "W"})
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
167 elif alt_ref == "GT":
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
168 sample_dict.update({record_position: "K"})
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
169 elif alt_ref == "AC":
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
170 sample_dict.update({record_position: "M"})
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
171 elif alt_ref == "GA":
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
172 sample_dict.update({record_position: "R"})
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
173 elif alt_ref == "TC":
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
174 sample_dict.update({record_position: "Y"})
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
175 elif alt_ref == "CG":
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
176 sample_dict.update({record_position: "S"})
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
177 elif alt_ref == "TA":
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
178 sample_dict.update({record_position: "W"})
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
179 elif alt_ref == "TG":
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
180 sample_dict.update({record_position: "K"})
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
181 elif alt_ref == "CA":
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
182 sample_dict.update({record_position: "M"})
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
183 else:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
184 sample_dict.update({record_position: "N"})
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
185 # Poor calls
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
186 elif qual_val <= 50:
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
187 # Call the reference allele.
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
188 # Do not coerce record.REF[0] to a string!
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
189 sample_dict.update({record_position: record.REF[0]})
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
190 elif qual_val <= self.quality_score_n_threshold:
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
191 sample_dict.update({record_position: "N"})
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
192 else:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
193 # Insurance -- Will still report on a possible
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
194 # SNP even if missed with above statements.
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
195 # Do not coerce record.REF[0] to a string!
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
196 sample_dict.update({record_position: record.REF[0]})
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
197 # Merge dictionaries and order
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
198 merge_dict = {}
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
199 merge_dict.update(positions_dict)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
200 merge_dict.update(sample_dict)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
201 sample_df = pandas.DataFrame(merge_dict, index=[file_name_base])
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
202 return sample_df, file_name_base, sample_map_qualities
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
203
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
204 def df_to_fasta(self, parsimonious_df, group):
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
205 # Generate SNP alignment file from
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
206 # the parsimonious_df data frame.
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
207 snps_file = os.path.join(self.output_snps_dir, "%s.fasta" % group)
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
208 test_duplicates = []
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
209 has_sequence_data = False
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
210 for index, row in parsimonious_df.iterrows():
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
211 for pos in row:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
212 if len(pos) > 0:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
213 has_sequence_data = True
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
214 break
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
215 if has_sequence_data:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
216 with open(snps_file, 'w') as fh:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
217 for index, row in parsimonious_df.iterrows():
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
218 test_duplicates.append(row.name)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
219 if test_duplicates.count(row.name) < 2:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
220 print(f'>{row.name}', file=fh)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
221 for pos in row:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
222 print(pos, end='', file=fh)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
223 print("", file=fh)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
224 return has_sequence_data
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
225
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
226 def find_initial_positions(self, filename):
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
227 # Find SNP positions in a vcf file.
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
228 found_positions = {}
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
229 found_positions_mix = {}
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
230 vcf_reader = vcf.Reader(open(filename, 'r'))
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
231 for record in vcf_reader:
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
232 qual_val = self.val_as_int(record.QUAL)
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
233 chrom = record.CHROM
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
234 position = record.POS
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
235 absolute_position = "%s:%s" % (str(chrom), str(position))
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
236 alt = str(record.ALT[0])
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
237 if alt != "None":
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
238 mq_val = self.get_mq_val(record.INFO, filename)
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
239 ac = record.INFO['AC'][0]
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
240 if ac == self.ac and len(record.REF) == 1 and qual_val > self.min_quality_score and mq_val > self.min_mq:
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
241 found_positions.update({absolute_position: record.REF})
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
242 if ac == 1 and len(record.REF) == 1 and qual_val > self.min_quality_score and mq_val > self.min_mq:
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
243 found_positions_mix.update({absolute_position: record.REF})
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
244 return found_positions, found_positions_mix
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
245
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
246 def gather_and_filter(self, prefilter_df, mq_averages, group_dir):
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
247 # Group a data frame of SNPs.
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
248 if self.input_excel is None:
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
249 filtered_all_df = prefilter_df
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
250 sheet_names = None
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
251 else:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
252 # Filter positions to be removed from all.
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
253 xl = pandas.ExcelFile(self.input_excel)
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
254 sheet_names = xl.sheet_names
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
255 # Use the first column to filter "all" postions.
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
256 exclusion_list_all = self.get_position_list(sheet_names, 0)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
257 exclusion_list_group = self.get_position_list(sheet_names, group_dir)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
258 exclusion_list = exclusion_list_all + exclusion_list_group
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
259 # Filters for all applied.
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
260 filtered_all_df = prefilter_df.drop(columns=exclusion_list, errors='ignore')
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
261 json_snps_file = os.path.join(self.output_json_snps_dir, "%s.json" % group_dir)
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
262 parsimonious_df = self.get_parsimonious_df(filtered_all_df)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
263 samples_number, columns = parsimonious_df.shape
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
264 if samples_number >= 4:
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
265 # Sufficient samples have been found
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
266 # to build a phylogenetic tree.
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
267 has_sequence_data = self.df_to_fasta(parsimonious_df, group_dir)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
268 if has_sequence_data:
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
269 json_avg_mq_file = os.path.join(self.output_json_avg_mq_dir, "%s.json" % group_dir)
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
270 mq_averages.to_json(json_avg_mq_file, orient='split')
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
271 parsimonious_df.to_json(json_snps_file, orient='split')
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
272 else:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
273 msg = "<br/>No sequence data"
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
274 if group_dir is not None:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
275 msg = "%s for group: %s" % (msg, group_dir)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
276 self.append_to_summary("%s<br/>\n" % msg)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
277 else:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
278 msg = "<br/>Too few samples to build tree"
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
279 if group_dir is not None:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
280 msg = "%s for group: %s" % (msg, group_dir)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
281 self.append_to_summary("%s<br/>\n" % msg)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
282
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
283 def get_sample_name(self, file_path):
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
284 # Return the sample part of a file name.
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
285 base_file_name = os.path.basename(file_path)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
286 if base_file_name.find(".") > 0:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
287 # Eliminate the extension.
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
288 return os.path.splitext(base_file_name)[0]
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
289 return base_file_name
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
290
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
291 def get_mq_val(self, record_info, filename):
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
292 # Get the MQ (gatk) or MQM (freebayes) value
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
293 # from the record.INFO component of the vcf file.
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
294 try:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
295 mq_val = record_info['MQM']
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
296 return self.return_val(mq_val)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
297 except Exception:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
298 try:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
299 mq_val = record_info['MQ']
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
300 return self.return_val(mq_val)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
301 except Exception:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
302 msg = "Invalid or unsupported vcf header %s in file: %s\n" % (str(record_info), filename)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
303 sys.exit(msg)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
304
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
305 def get_parsimonious_df(self, filtered_all_df):
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
306 # Get the parsimonious SNPs data frame
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
307 # from a data frame of filtered SNPs.
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
308 try:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
309 ref_series = filtered_all_df.loc['root']
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
310 # In all_vcf root needs to be removed.
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
311 filtered_all_df = filtered_all_df.drop(['root'])
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
312 except KeyError:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
313 pass
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
314 parsimony = filtered_all_df.loc[:, (filtered_all_df != filtered_all_df.iloc[0]).any()]
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
315 parsimony_positions = list(parsimony)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
316 parse_df = filtered_all_df[parsimony_positions]
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
317 ref_df = ref_series.to_frame()
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
318 ref_df = ref_df.T
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
319 parsimonious_df = pandas.concat([parse_df, ref_df], join='inner')
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
320 return parsimonious_df
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
321
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
322 def get_position_list(self, sheet_names, group):
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
323 # Get a list of positions defined by an excel file.
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
324 exclusion_list = []
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
325 try:
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
326 filter_to_all = pandas.read_excel(self.input_excel, header=1, usecols=[group])
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
327 for value in filter_to_all.values:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
328 value = str(value[0])
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
329 if "-" not in value.split(":")[-1]:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
330 exclusion_list.append(value)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
331 elif "-" in value:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
332 try:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
333 chrom, sequence_range = value.split(":")
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
334 except Exception as e:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
335 sys.exit(str(e))
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
336 value = sequence_range.split("-")
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
337 for position in range(int(value[0].replace(',', '')), int(value[1].replace(',', '')) + 1):
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
338 exclusion_list.append(chrom + ":" + str(position))
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
339 return exclusion_list
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
340 except ValueError:
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
341 return []
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
342
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
343 def get_snps(self, task_queue, timeout):
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
344 while True:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
345 try:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
346 group_dir = task_queue.get(block=True, timeout=timeout)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
347 except queue.Empty:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
348 break
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
349 # Parse all vcf files to accumulate
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
350 # the SNPs into a data frame.
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
351 positions_dict = {}
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
352 group_files = []
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
353 for file_name in os.listdir(os.path.abspath(group_dir)):
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
354 file_path = os.path.abspath(os.path.join(group_dir, file_name))
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
355 group_files.append(file_path)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
356 for file_name in group_files:
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
357 found_positions, found_positions_mix = self.find_initial_positions(file_name)
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
358 positions_dict.update(found_positions)
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
359 # Order before adding to file to match
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
360 # with ordering of individual samples.
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
361 # all_positions is abs_pos:REF
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
362 self.all_positions = OrderedDict(sorted(positions_dict.items()))
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
363 ref_positions_df = pandas.DataFrame(self.all_positions, index=['root'])
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
364 all_map_qualities = {}
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
365 df_list = []
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
366 for file_name in group_files:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
367 sample_df, file_name_base, sample_map_qualities = self.decide_snps(file_name)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
368 df_list.append(sample_df)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
369 all_map_qualities.update({file_name_base: sample_map_qualities})
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
370 all_sample_df = pandas.concat(df_list)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
371 # All positions have now been selected for each sample,
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
372 # so select parisomony informative SNPs. This removes
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
373 # columns where all fields are the same.
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
374 # Add reference to top row.
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
375 prefilter_df = pandas.concat([ref_positions_df, all_sample_df], join='inner')
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
376 all_mq_df = pandas.DataFrame.from_dict(all_map_qualities)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
377 mq_averages = all_mq_df.mean(axis=1).astype(int)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
378 self.gather_and_filter(prefilter_df, mq_averages, group_dir)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
379 task_queue.task_done()
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
380
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
381 def group_vcfs(self, vcf_files):
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
382 # Parse an excel file to produce a
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
383 # grouping dictionary for SNPs.
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
384 xl = pandas.ExcelFile(self.input_excel)
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
385 sheet_names = xl.sheet_names
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
386 ws = pandas.read_excel(self.input_excel, sheet_name=sheet_names[0])
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
387 defining_snps = ws.iloc[0]
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
388 defsnp_iterator = iter(defining_snps.iteritems())
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
389 next(defsnp_iterator)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
390 defining_snps = {}
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
391 inverted_defining_snps = {}
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
392 for abs_pos, group in defsnp_iterator:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
393 if '!' in abs_pos:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
394 inverted_defining_snps[abs_pos.replace('!', '')] = group
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
395 else:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
396 defining_snps[abs_pos] = group
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
397 samples_groups_dict = {}
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
398 for vcf_file in vcf_files:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
399 found_positions, found_positions_mix = self.find_initial_positions(vcf_file)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
400 samples_groups_dict = self.bin_input_files(vcf_file, samples_groups_dict, defining_snps, inverted_defining_snps, found_positions, found_positions_mix)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
401 # Output summary grouping table.
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
402 self.append_to_summary('<br/>')
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
403 self.append_to_summary('<b>Groupings with %d listed:</b><br/>\n' % len(samples_groups_dict))
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
404 self.append_to_summary('<table cellpadding="5" cellspaging="5" border="1">\n')
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
405 for key, value in samples_groups_dict.items():
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
406 self.append_to_summary('<tr align="left"><th>Sample Name</th>\n')
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
407 self.append_to_summary('<td>%s</td>' % key)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
408 for group in value:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
409 self.append_to_summary('<td>%s</td>\n' % group)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
410 self.append_to_summary('</tr>\n')
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
411 self.append_to_summary('</table><br/>\n')
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
412
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
413 def initiate_summary(self, output_summary):
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
414 # Output summary file handle.
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
415 self.append_to_summary('<html>\n')
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
416 self.append_to_summary('<head></head>\n')
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
417 self.append_to_summary('<body style=\"font-size:12px;">')
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
418 self.append_to_summary("<b>Time started:</b> %s<br/>" % get_time_stamp())
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
419 self.append_to_summary("<b>Number of VCF inputs:</b> %d<br/>" % self.num_files)
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
420 self.append_to_summary("<b>Reference:</b> %s<br/>" % self.dbkey)
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
421 self.append_to_summary("<b>All isolates:</b> %s<br/>" % str(self.all_isolates))
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
422
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
423 def return_val(self, val, index=0):
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
424 # Handle element and single-element list values.
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
425 if isinstance(val, list):
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
426 return val[index]
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
427 return val
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
428
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
429 def val_as_int(self, val):
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
430 # Handle integer value conversion.
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
431 try:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
432 return int(val)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
433 except TypeError:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
434 # val is likely None here.
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
435 return 0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
436
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
437
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
438 if __name__ == '__main__':
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
439
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
440 parser = argparse.ArgumentParser()
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
441
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
442 parser.add_argument('--ac', action='store', dest='ac', type=int, help='Allele count value'),
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
443 parser.add_argument('--all_isolates', action='store_true', dest='all_isolates', required=False, default=False, help='Create table with all isolates'),
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
444 parser.add_argument('--input_excel', action='store', dest='input_excel', required=False, default=None, help='Optional Excel filter file'),
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
445 parser.add_argument('--input_vcf_dir', action='store', dest='input_vcf_dir', help='Input vcf directory'),
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
446 parser.add_argument('--min_mq', action='store', dest='min_mq', type=int, help='Minimum map quality value'),
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
447 parser.add_argument('--min_quality_score', action='store', dest='min_quality_score', type=int, help='Minimum quality score value'),
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
448 parser.add_argument('--output_json_avg_mq_dir', action='store', dest='output_json_avg_mq_dir', help='Output json average mq directory'),
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
449 parser.add_argument('--output_json_snps_dir', action='store', dest='output_json_snps_dir', help='Output json snps directory'),
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
450 parser.add_argument('--output_snps_dir', action='store', dest='output_snps_dir', help='Output snps directory'),
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
451 parser.add_argument('--output_summary', action='store', dest='output_summary', help='Output summary html file'),
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
452 parser.add_argument('--processes', action='store', dest='processes', type=int, help='Configured processes for job'),
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
453 parser.add_argument('--quality_score_n_threshold', action='store', dest='quality_score_n_threshold', type=int, help='Minimum quality score N value for alleles'),
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
454 parser.add_argument('--dbkey', action='store', dest='dbkey', help='Galaxy genome build dbkey'),
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
455
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
456 args = parser.parse_args()
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
457
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
458 # Build the list of all input zero coverage vcf
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
459 # files, both the samples and the "database".
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
460 vcf_files = []
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
461 for file_name in os.listdir(args.input_vcf_dir):
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
462 file_path = os.path.abspath(os.path.join(args.input_vcf_dir, file_name))
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
463 vcf_files.append(file_path)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
464
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
465 multiprocessing.set_start_method('spawn')
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
466 queue1 = multiprocessing.JoinableQueue()
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
467 num_files = len(vcf_files)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
468 cpus = set_num_cpus(num_files, args.processes)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
469 # Set a timeout for get()s in the queue.
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
470 timeout = 0.05
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
471
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
472 # Initialize the snp_finder object.
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
473 snp_finder = SnpFinder(num_files, args.dbkey, args.input_excel, args.all_isolates, args.ac, args.min_mq, args.quality_score_n_threshold, args.min_quality_score, args.input_vcf_dir, args.output_json_avg_mq_dir, args.output_json_snps_dir, args.output_snps_dir, args.output_summary)
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
474
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
475 # Define and make the set of directories into which the input_zc_vcf
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
476 # files will be placed. Selected input values (e.g., the use of
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
477 # an Excel file for grouping and filtering, creating a group with
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
478 # all isolates) are used to define the directories.
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
479 vcf_dirs = []
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
480 if args.input_excel is None:
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
481 vcf_dirs = setup_all_vcfs(vcf_files, vcf_dirs)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
482 else:
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
483 if args.all_isolates:
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
484 vcf_dirs = setup_all_vcfs(vcf_files, vcf_dirs)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
485 # Parse the Excel file to detemine groups for filtering.
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
486 snp_finder.group_vcfs(vcf_files)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
487 # Append the list of group directories created by
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
488 # the above call to the set of directories containing
3
14285a94fb13 Uploaded
greg
parents: 0
diff changeset
489 # vcf files for analysis.
0
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
490 group_dirs = [d for d in os.listdir(os.getcwd()) if os.path.isdir(d) and d in snp_finder.groups]
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
491 vcf_dirs.extend(group_dirs)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
492
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
493 # Populate the queue for job splitting.
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
494 for vcf_dir in vcf_dirs:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
495 queue1.put(vcf_dir)
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
496
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
497 # Complete the get_snps task.
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
498 processes = [multiprocessing.Process(target=snp_finder.get_snps, args=(queue1, timeout, )) for _ in range(cpus)]
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
499 for p in processes:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
500 p.start()
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
501 for p in processes:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
502 p.join()
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
503 queue1.join()
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
504
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
505 # Finish summary log.
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
506 snp_finder.append_to_summary("<br/><b>Time finished:</b> %s<br/>\n" % get_time_stamp())
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
507 total_run_time = datetime.now() - snp_finder.timer_start
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
508 snp_finder.append_to_summary("<br/><b>Total run time:</b> %s<br/>\n" % str(total_run_time))
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
509 snp_finder.append_to_summary('</body>\n</html>\n')
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
510 with open(args.output_summary, "w") as fh:
ee4ef1fc23c6 Uploaded
greg
parents:
diff changeset
511 fh.write("%s" % snp_finder.summary_str)