Mercurial > repos > cstrittmatter > ss2v110
comparison SalmID.py @ 0:fc22ec8e924e draft
planemo upload commit 6b0a9d0f0ef4bdb0c2e2c54070b510ff28125f7a
| author | cstrittmatter |
|---|---|
| date | Tue, 21 Apr 2020 12:45:34 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:fc22ec8e924e |
|---|---|
| 1 #!/usr/bin/env python3 | |
| 2 | |
| 3 | |
| 4 import gzip | |
| 5 import io | |
| 6 import pickle | |
| 7 import os | |
| 8 import sys | |
| 9 | |
| 10 from argparse import ArgumentParser | |
| 11 try: | |
| 12 from .version import SalmID_version | |
| 13 except ImportError: | |
| 14 SalmID_version = "version unknown" | |
| 15 | |
| 16 | |
| 17 def reverse_complement(sequence): | |
| 18 """return the reverse complement of a nucleotide (including IUPAC ambiguous nuceotide codes)""" | |
| 19 complement = {'A': 'T', 'C': 'G', 'G': 'C', 'T': 'A', 'N': 'N', 'M': 'K', 'R': 'Y', 'W': 'W', | |
| 20 'S': 'S', 'Y': 'R', 'K': 'M', 'V': 'B', 'H': 'D', 'D': 'H', 'B': 'V'} | |
| 21 return "".join(complement[base] for base in reversed(sequence)) | |
| 22 | |
| 23 | |
| 24 def parse_args(): | |
| 25 "Parse the input arguments, use '-h' for help." | |
| 26 parser = ArgumentParser(description='SalmID - rapid Kmer based Salmonella identifier from sequence data') | |
| 27 # inputs | |
| 28 parser.add_argument('-v', '--version', action='version', version='%(prog)s ' + SalmID_version) | |
| 29 parser.add_argument( | |
| 30 '-i', '--input_file', type=str, required=False, default='None', metavar='your_fastqgz', | |
| 31 help='Single fastq.gz file input, include path to file if file is not in same directory ') | |
| 32 parser.add_argument( | |
| 33 '-e', '--extension', type=str, required=False, default='.fastq.gz', metavar='file_extension', | |
| 34 help='File extension, if specified without "--input_dir", SalmID will attempt to ID all files\n' + | |
| 35 ' with this extension in current directory, otherwise files in input directory') | |
| 36 | |
| 37 parser.add_argument( | |
| 38 '-d', '--input_dir', type=str, required=False, default='.', metavar='directory', | |
| 39 help='Directory which contains data for identification, when not specified files in current directory will be analyzed.') | |
| 40 parser.add_argument( | |
| 41 '-r', '--report', type=str, required=False, default='percentage', metavar='percentage, coverage or taxonomy', | |
| 42 help='Report either percentage ("percentage") of clade specific kmers recovered, average kmer-coverage ("cov"), or ' | |
| 43 'taxonomy (taxonomic species ID, plus observed mean k-mer coverages and expected coverage).') | |
| 44 parser.add_argument( | |
| 45 '-m', '--mode', type=str, required=False, default='quick', metavar='quick or thorough', | |
| 46 help='Quick [quick] or thorough [thorough] mode') | |
| 47 if len(sys.argv) == 1: | |
| 48 parser.print_help(sys.stderr) | |
| 49 sys.exit(1) | |
| 50 return parser.parse_args() | |
| 51 | |
| 52 | |
| 53 def get_av_read_length(file): | |
| 54 """Samples the first 100 reads from a fastq file and return the average read length.""" | |
| 55 i = 1 | |
| 56 n_reads = 0 | |
| 57 total_length = 0 | |
| 58 if file.endswith(".gz"): | |
| 59 file_content = io.BufferedReader(gzip.open(file)) | |
| 60 else: | |
| 61 file_content = open(file, "r").readlines() | |
| 62 for line in file_content: | |
| 63 if i % 4 == 2: | |
| 64 total_length += len(line.strip()) | |
| 65 n_reads += 1 | |
| 66 i += 1 | |
| 67 if n_reads == 100: | |
| 68 break | |
| 69 return total_length / 100 | |
| 70 | |
| 71 | |
| 72 def createKmerDict_reads(list_of_strings, kmer): | |
| 73 """Count occurence of K-mers in a list of strings | |
| 74 | |
| 75 Args: | |
| 76 list_of_strings(list of str): nucleotide sequences as a list of strings | |
| 77 kmer(int): length of the K-mer to count | |
| 78 | |
| 79 Returns: | |
| 80 dict: dictionary with kmers as keys, counts for each kmer as values""" | |
| 81 kmer_table = {} | |
| 82 for string in list_of_strings: | |
| 83 sequence = string.strip('\n') | |
| 84 if len(sequence) >= kmer: | |
| 85 for i in range(len(sequence) - kmer + 1): | |
| 86 new_mer = sequence[i:i + kmer] | |
| 87 new_mer_rc = reverse_complement(new_mer) | |
| 88 if new_mer in kmer_table: | |
| 89 kmer_table[new_mer.upper()] += 1 | |
| 90 else: | |
| 91 kmer_table[new_mer.upper()] = 1 | |
| 92 if new_mer_rc in kmer_table: | |
| 93 kmer_table[new_mer_rc.upper()] += 1 | |
| 94 else: | |
| 95 kmer_table[new_mer_rc.upper()] = 1 | |
| 96 return kmer_table | |
| 97 | |
| 98 | |
| 99 def target_read_kmerizer_multi(file, k, kmerDict_1, kmerDict_2, mode): | |
| 100 mean_1 = None | |
| 101 mean_2 = None | |
| 102 i = 1 | |
| 103 n_reads_1 = 0 | |
| 104 n_reads_2 = 0 | |
| 105 total_coverage_1 = 0 | |
| 106 total_coverage_2 = 0 | |
| 107 reads_1 = [] | |
| 108 reads_2 = [] | |
| 109 total_reads = 0 | |
| 110 if file.endswith(".gz"): | |
| 111 file_content = io.BufferedReader(gzip.open(file)) | |
| 112 else: | |
| 113 file_content = open(file, "r").readlines() | |
| 114 for line in file_content: | |
| 115 start = int((len(line) - k) // 2) | |
| 116 if i % 4 == 2: | |
| 117 total_reads += 1 | |
| 118 if file.endswith(".gz"): | |
| 119 s1 = line[start:k + start].decode() | |
| 120 line = line.decode() | |
| 121 else: | |
| 122 s1 = line[start:k + start] | |
| 123 if s1 in kmerDict_1: | |
| 124 n_reads_1 += 1 | |
| 125 total_coverage_1 += len(line) | |
| 126 reads_1.append(line) | |
| 127 if s1 in kmerDict_2: | |
| 128 n_reads_2 += 1 | |
| 129 total_coverage_2 += len(line) | |
| 130 reads_2.append(line) | |
| 131 i += 1 | |
| 132 if mode == 'quick': | |
| 133 if total_coverage_2 >= 800000: | |
| 134 break | |
| 135 | |
| 136 if len(reads_1) == 0: | |
| 137 kmer_Dict1 = {} | |
| 138 else: | |
| 139 kmer_Dict1 = createKmerDict_reads(reads_1, k) | |
| 140 mers_1 = set([key for key in kmer_Dict1]) | |
| 141 mean_1 = sum([kmer_Dict1[key] for key in kmer_Dict1]) / len(mers_1) | |
| 142 if len(reads_2) == 0: | |
| 143 kmer_Dict2 = {} | |
| 144 else: | |
| 145 kmer_Dict2 = createKmerDict_reads(reads_2, k) | |
| 146 mers_2 = set([key for key in kmer_Dict2]) | |
| 147 mean_2 = sum([kmer_Dict2[key] for key in kmer_Dict2]) / len(mers_2) | |
| 148 return kmer_Dict1, kmer_Dict2, mean_1, mean_2, total_reads | |
| 149 | |
| 150 | |
| 151 def mean_cov_selected_kmers(iterable, kmer_dict, clade_specific_kmers): | |
| 152 ''' | |
| 153 Given an iterable (list, set, dictrionary) returns mean coverage for the kmers in iterable | |
| 154 :param iterable: set, list or dictionary containing kmers | |
| 155 :param kmer_dict: dictionary with kmers as keys, kmer-frequency as value | |
| 156 :param clade_specific_kmers: list, dict or set of clade specific kmers | |
| 157 :return: mean frequency as float | |
| 158 ''' | |
| 159 if len(iterable) == 0: | |
| 160 return 0 | |
| 161 return sum([kmer_dict[value] for value in iterable]) / len(clade_specific_kmers) | |
| 162 | |
| 163 | |
| 164 def kmer_lists(query_fastq_gz, k, | |
| 165 allmers, allmers_rpoB, | |
| 166 uniqmers_bongori, | |
| 167 uniqmers_I, | |
| 168 uniqmers_IIa, | |
| 169 uniqmers_IIb, | |
| 170 uniqmers_IIIa, | |
| 171 uniqmers_IIIb, | |
| 172 uniqmers_IV, | |
| 173 uniqmers_VI, | |
| 174 uniqmers_VII, | |
| 175 uniqmers_VIII, | |
| 176 uniqmers_bongori_rpoB, | |
| 177 uniqmers_S_enterica_rpoB, | |
| 178 uniqmers_Escherichia_rpoB, | |
| 179 uniqmers_Listeria_ss_rpoB, | |
| 180 uniqmers_Lmono_rpoB, | |
| 181 mode): | |
| 182 dict_invA, dict_rpoB, mean_invA, mean_rpoB, total_reads = target_read_kmerizer_multi(query_fastq_gz, k, allmers, | |
| 183 allmers_rpoB, mode) | |
| 184 target_mers_invA = set([key for key in dict_invA]) | |
| 185 target_mers_rpoB = set([key for key in dict_rpoB]) | |
| 186 if target_mers_invA == 0: | |
| 187 print('No reads found matching invA, no Salmonella in sample?') | |
| 188 else: | |
| 189 p_bongori = (len(uniqmers_bongori & target_mers_invA) / len(uniqmers_bongori)) * 100 | |
| 190 p_I = (len(uniqmers_I & target_mers_invA) / len(uniqmers_I)) * 100 | |
| 191 p_IIa = (len(uniqmers_IIa & target_mers_invA) / len(uniqmers_IIa)) * 100 | |
| 192 p_IIb = (len(uniqmers_IIb & target_mers_invA) / len(uniqmers_IIb)) * 100 | |
| 193 p_IIIa = (len(uniqmers_IIIa & target_mers_invA) / len(uniqmers_IIIa)) * 100 | |
| 194 p_IIIb = (len(uniqmers_IIIb & target_mers_invA) / len(uniqmers_IIIb)) * 100 | |
| 195 p_VI = (len(uniqmers_VI & target_mers_invA) / len(uniqmers_VI)) * 100 | |
| 196 p_IV = (len(uniqmers_IV & target_mers_invA) / len(uniqmers_IV)) * 100 | |
| 197 p_VII = (len(uniqmers_VII & target_mers_invA) / len(uniqmers_VII)) * 100 | |
| 198 p_VIII = (len(uniqmers_VIII & target_mers_invA) / len(uniqmers_VIII)) * 100 | |
| 199 p_bongori_rpoB = (len(uniqmers_bongori_rpoB & target_mers_rpoB) / len(uniqmers_bongori_rpoB)) * 100 | |
| 200 p_Senterica = (len(uniqmers_S_enterica_rpoB & target_mers_rpoB) / len(uniqmers_S_enterica_rpoB)) * 100 | |
| 201 p_Escherichia = (len(uniqmers_Escherichia_rpoB & target_mers_rpoB) / len(uniqmers_Escherichia_rpoB)) * 100 | |
| 202 p_Listeria_ss = (len(uniqmers_Listeria_ss_rpoB & target_mers_rpoB) / len(uniqmers_Listeria_ss_rpoB)) * 100 | |
| 203 p_Lmono = (len(uniqmers_Lmono_rpoB & target_mers_rpoB) / len(uniqmers_Lmono_rpoB)) * 100 | |
| 204 bongori_invA_cov = mean_cov_selected_kmers(uniqmers_bongori & target_mers_invA, dict_invA, uniqmers_bongori) | |
| 205 I_invA_cov = mean_cov_selected_kmers(uniqmers_I & target_mers_invA, dict_invA, uniqmers_I) | |
| 206 IIa_invA_cov = mean_cov_selected_kmers(uniqmers_IIa & target_mers_invA, dict_invA, uniqmers_IIa) | |
| 207 IIb_invA_cov = mean_cov_selected_kmers(uniqmers_IIb & target_mers_invA, dict_invA, uniqmers_IIb) | |
| 208 IIIa_invA_cov = mean_cov_selected_kmers(uniqmers_IIIa & target_mers_invA, dict_invA, uniqmers_IIIa) | |
| 209 IIIb_invA_cov = mean_cov_selected_kmers(uniqmers_IIIb & target_mers_invA, dict_invA, uniqmers_IIIb) | |
| 210 IV_invA_cov = mean_cov_selected_kmers(uniqmers_IV & target_mers_invA, dict_invA, uniqmers_IV) | |
| 211 VI_invA_cov = mean_cov_selected_kmers(uniqmers_VI & target_mers_invA, dict_invA, uniqmers_VI) | |
| 212 VII_invA_cov = mean_cov_selected_kmers(uniqmers_VII & target_mers_invA, dict_invA, uniqmers_VII) | |
| 213 VIII_invA_cov = mean_cov_selected_kmers(uniqmers_VIII & target_mers_invA, dict_invA, uniqmers_VIII) | |
| 214 S_enterica_rpoB_cov = mean_cov_selected_kmers((uniqmers_S_enterica_rpoB & target_mers_rpoB), dict_rpoB, | |
| 215 uniqmers_S_enterica_rpoB) | |
| 216 S_bongori_rpoB_cov = mean_cov_selected_kmers((uniqmers_bongori_rpoB & target_mers_rpoB), dict_rpoB, | |
| 217 uniqmers_bongori_rpoB) | |
| 218 Escherichia_rpoB_cov = mean_cov_selected_kmers((uniqmers_Escherichia_rpoB & target_mers_rpoB), dict_rpoB, | |
| 219 uniqmers_Escherichia_rpoB) | |
| 220 Listeria_ss_rpoB_cov = mean_cov_selected_kmers((uniqmers_Listeria_ss_rpoB & target_mers_rpoB), dict_rpoB, | |
| 221 uniqmers_Listeria_ss_rpoB) | |
| 222 Lmono_rpoB_cov = mean_cov_selected_kmers((uniqmers_Lmono_rpoB & target_mers_rpoB), dict_rpoB, | |
| 223 uniqmers_Lmono_rpoB) | |
| 224 coverages = [Listeria_ss_rpoB_cov, Lmono_rpoB_cov, Escherichia_rpoB_cov, S_bongori_rpoB_cov, | |
| 225 S_enterica_rpoB_cov, bongori_invA_cov, I_invA_cov, IIa_invA_cov, IIb_invA_cov, | |
| 226 IIIa_invA_cov, IIIb_invA_cov, IV_invA_cov, VI_invA_cov, VII_invA_cov, VIII_invA_cov] | |
| 227 locus_scores = [p_Listeria_ss, p_Lmono, p_Escherichia, p_bongori_rpoB, p_Senterica, p_bongori, | |
| 228 p_I, p_IIa, p_IIb, p_IIIa, p_IIIb, p_IV, p_VI, p_VII, p_VIII] | |
| 229 return locus_scores, coverages, total_reads | |
| 230 | |
| 231 | |
| 232 def report_taxon(locus_covs, average_read_length, number_of_reads): | |
| 233 list_taxa = [ 'Listeria ss', 'Listeria monocytogenes', 'Escherichia sp.', # noqa: E201 | |
| 234 'Salmonella bongori (rpoB)', 'Salmonella enterica (rpoB)', | |
| 235 'Salmonella bongori (invA)', 'S. enterica subsp. enterica (invA)', | |
| 236 'S. enterica subsp. salamae (invA: clade a)', 'S. enterica subsp. salamae (invA: clade b)', | |
| 237 'S. enterica subsp. arizonae (invA)', 'S. enterica subsp. diarizonae (invA)', | |
| 238 'S. enterica subsp. houtenae (invA)', 'S. enterica subsp. indica (invA)', | |
| 239 'S. enterica subsp. VII (invA)', 'S. enterica subsp. salamae (invA: clade VIII)' ] # noqa: E202 | |
| 240 if sum(locus_covs) < 1: | |
| 241 rpoB = ('No rpoB matches!', 0) | |
| 242 invA = ('No invA matches!', 0) | |
| 243 return rpoB, invA, 0.0 | |
| 244 else: | |
| 245 # given list of scores get taxon | |
| 246 if sum(locus_covs[0:5]) > 0: | |
| 247 best_rpoB = max(range(len(locus_covs[1:5])), key=lambda x: locus_covs[1:5][x]) + 1 | |
| 248 all_rpoB = max(range(len(locus_covs[0:5])), key=lambda x: locus_covs[0:5][x]) | |
| 249 if (locus_covs[best_rpoB] != 0) & (all_rpoB == 0): | |
| 250 rpoB = (list_taxa[best_rpoB], locus_covs[best_rpoB]) | |
| 251 elif (all_rpoB == 0) & (round(sum(locus_covs[1:5]), 1) < 1): | |
| 252 rpoB = (list_taxa[0], locus_covs[0]) | |
| 253 else: | |
| 254 rpoB = (list_taxa[best_rpoB], locus_covs[best_rpoB]) | |
| 255 else: | |
| 256 rpoB = ('No rpoB matches!', 0) | |
| 257 if sum(locus_covs[5:]) > 0: | |
| 258 best_invA = max(range(len(locus_covs[5:])), key=lambda x: locus_covs[5:][x]) + 5 | |
| 259 invA = (list_taxa[best_invA], locus_covs[best_invA]) | |
| 260 else: | |
| 261 invA = ('No invA matches!', 0) | |
| 262 if 'Listeria' in rpoB[0]: | |
| 263 return rpoB, invA, (average_read_length * number_of_reads) / 3000000 | |
| 264 else: | |
| 265 return rpoB, invA, (average_read_length * number_of_reads) / 5000000 | |
| 266 | |
| 267 | |
| 268 def main(): | |
| 269 ex_dir = os.path.dirname(os.path.realpath(__file__)) | |
| 270 args = parse_args() | |
| 271 input_file = args.input_file | |
| 272 if input_file != 'None': | |
| 273 files = [input_file] | |
| 274 else: | |
| 275 extension = args.extension | |
| 276 inputdir = args.input_dir | |
| 277 files = [inputdir + '/' + f for f in os.listdir(inputdir) if f.endswith(extension)] | |
| 278 report = args.report | |
| 279 mode = args.mode | |
| 280 f_invA = open(ex_dir + "/invA_mers_dict", "rb") | |
| 281 sets_dict_invA = pickle.load(f_invA) | |
| 282 f_invA.close() | |
| 283 allmers = sets_dict_invA['allmers'] | |
| 284 uniqmers_I = sets_dict_invA['uniqmers_I'] | |
| 285 uniqmers_IIa = sets_dict_invA['uniqmers_IIa'] | |
| 286 uniqmers_IIb = sets_dict_invA['uniqmers_IIb'] | |
| 287 uniqmers_IIIa = sets_dict_invA['uniqmers_IIIa'] | |
| 288 uniqmers_IIIb = sets_dict_invA['uniqmers_IIIb'] | |
| 289 uniqmers_IV = sets_dict_invA['uniqmers_IV'] | |
| 290 uniqmers_VI = sets_dict_invA['uniqmers_VI'] | |
| 291 uniqmers_VII = sets_dict_invA['uniqmers_VII'] | |
| 292 uniqmers_VIII = sets_dict_invA['uniqmers_VIII'] | |
| 293 uniqmers_bongori = sets_dict_invA['uniqmers_bongori'] | |
| 294 | |
| 295 f = open(ex_dir + "/rpoB_mers_dict", "rb") | |
| 296 sets_dict = pickle.load(f) | |
| 297 f.close() | |
| 298 | |
| 299 allmers_rpoB = sets_dict['allmers'] | |
| 300 uniqmers_bongori_rpoB = sets_dict['uniqmers_bongori'] | |
| 301 uniqmers_S_enterica_rpoB = sets_dict['uniqmers_S_enterica'] | |
| 302 uniqmers_Escherichia_rpoB = sets_dict['uniqmers_Escherichia'] | |
| 303 uniqmers_Listeria_ss_rpoB = sets_dict['uniqmers_Listeria_ss'] | |
| 304 uniqmers_Lmono_rpoB = sets_dict['uniqmers_L_mono'] | |
| 305 # todo: run kmer_lists() once, create list of tuples containing data to be used fro different reports | |
| 306 if report == 'taxonomy': | |
| 307 print('file\trpoB\tinvA\texpected coverage') | |
| 308 for f in files: | |
| 309 locus_scores, coverages, reads = kmer_lists(f, 27, | |
| 310 allmers, allmers_rpoB, | |
| 311 uniqmers_bongori, | |
| 312 uniqmers_I, | |
| 313 uniqmers_IIa, | |
| 314 uniqmers_IIb, | |
| 315 uniqmers_IIIa, | |
| 316 uniqmers_IIIb, | |
| 317 uniqmers_IV, | |
| 318 uniqmers_VI, | |
| 319 uniqmers_VII, | |
| 320 uniqmers_VIII, | |
| 321 uniqmers_bongori_rpoB, | |
| 322 uniqmers_S_enterica_rpoB, | |
| 323 uniqmers_Escherichia_rpoB, | |
| 324 uniqmers_Listeria_ss_rpoB, | |
| 325 uniqmers_Lmono_rpoB, | |
| 326 mode) | |
| 327 pretty_covs = [round(cov, 1) for cov in coverages] | |
| 328 report = report_taxon(pretty_covs, get_av_read_length(f), reads) | |
| 329 print(f.split('/')[-1] + '\t' + report[0][0] + '[' + str(report[0][1]) + ']' + '\t' + report[1][0] + | |
| 330 '[' + str(report[1][1]) + ']' + | |
| 331 '\t' + str(round(report[2], 1))) | |
| 332 else: | |
| 333 print( | |
| 334 'file\tListeria sensu stricto (rpoB)\tL. monocytogenes (rpoB)\tEscherichia spp. (rpoB)\tS. bongori (rpoB)\tS. enterica' + # noqa: E122 | |
| 335 '(rpoB)\tS. bongori (invA)\tsubsp. I (invA)\tsubsp. II (clade a: invA)\tsubsp. II' + # noqa: E122 | |
| 336 ' (clade b: invA)\tsubsp. IIIa (invA)\tsubsp. IIIb (invA)\tsubsp.IV (invA)\tsubsp. VI (invA)\tsubsp. VII (invA)' + # noqa: E122 | |
| 337 '\tsubsp. II (clade VIII : invA)') | |
| 338 if report == 'percentage': | |
| 339 for f in files: | |
| 340 locus_scores, coverages, reads = kmer_lists(f, 27, | |
| 341 allmers, allmers_rpoB, | |
| 342 uniqmers_bongori, | |
| 343 uniqmers_I, | |
| 344 uniqmers_IIa, | |
| 345 uniqmers_IIb, | |
| 346 uniqmers_IIIa, | |
| 347 uniqmers_IIIb, | |
| 348 uniqmers_IV, | |
| 349 uniqmers_VI, | |
| 350 uniqmers_VII, | |
| 351 uniqmers_VIII, | |
| 352 uniqmers_bongori_rpoB, | |
| 353 uniqmers_S_enterica_rpoB, | |
| 354 uniqmers_Escherichia_rpoB, | |
| 355 uniqmers_Listeria_ss_rpoB, | |
| 356 uniqmers_Lmono_rpoB, | |
| 357 mode) | |
| 358 pretty_scores = [str(round(score)) for score in locus_scores] | |
| 359 print(f.split('/')[-1] + '\t' + '\t'.join(pretty_scores)) | |
| 360 else: | |
| 361 for f in files: | |
| 362 locus_scores, coverages, reads = kmer_lists(f, 27, | |
| 363 allmers, allmers_rpoB, | |
| 364 uniqmers_bongori, | |
| 365 uniqmers_I, | |
| 366 uniqmers_IIa, | |
| 367 uniqmers_IIb, | |
| 368 uniqmers_IIIa, | |
| 369 uniqmers_IIIb, | |
| 370 uniqmers_IV, | |
| 371 uniqmers_VI, | |
| 372 uniqmers_VII, | |
| 373 uniqmers_VIII, | |
| 374 uniqmers_bongori_rpoB, | |
| 375 uniqmers_S_enterica_rpoB, | |
| 376 uniqmers_Escherichia_rpoB, | |
| 377 uniqmers_Listeria_ss_rpoB, | |
| 378 uniqmers_Lmono_rpoB, | |
| 379 mode) | |
| 380 pretty_covs = [str(round(cov, 1)) for cov in coverages] | |
| 381 print(f.split('/')[-1] + '\t' + '\t'.join(pretty_covs)) | |
| 382 | |
| 383 | |
| 384 if __name__ == '__main__': | |
| 385 main() | |
| 386 |
