annotate get_contigs_from_re_archive.py @ 0:ea6a3059a6af draft

Uploaded
author petr-novak
date Mon, 18 Oct 2021 11:01:20 +0000
parents
children 814cba36e435
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
1 #!/usr/bin/env python
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
2 '''
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
3 parse .aln file - output from cap3 program. Output is fasta file and
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
4 profile file
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
5 '''
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
6 import argparse
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
7 import re
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
8 import zipfile
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
9 import tempfile
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
10 import textwrap
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
11
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
12 def parse_args():
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
13 '''Argument parsin'''
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
14 description = """
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
15 parsing cap3 assembly aln output
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
16 """
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
17
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
18 parser = argparse.ArgumentParser(
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
19 description=description, formatter_class=argparse.RawTextHelpFormatter)
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
20 parser.add_argument('-re',
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
21 '--re_file',
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
22 default=None,
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
23 required=True,
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
24 help="RepeatExlorer archive or directory",
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
25 type=str,
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
26 action='store')
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
27 parser.add_argument('-f',
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
28 '--fasta',
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
29 default=None,
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
30 required=True,
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
31 help="fasta output file name",
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
32 type=str,
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
33 action='store')
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
34 parser.add_argument('-m',
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
35 '--min_coverage',
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
36 default=5,
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
37 required=False,
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
38 help="minimum contig coverage",
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
39 type=int,
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
40 action="store")
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
41 parser.add_argument('-L',
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
42 '--min_contig_length',
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
43 default=50,
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
44 required=False,
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
45 help="minimum contig length",
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
46 type=int,
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
47 action="store")
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
48 return parser.parse_args()
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
49
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
50
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
51 def get_header(f):
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
52 aln_header = " . : . : . : . : . : . :"
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
53 contig_lead = "******************"
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
54 aln_start = -1
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
55 while True:
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
56 line = f.readline()
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
57 if not line:
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
58 return None, None
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
59 if line[0:18] == contig_lead:
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
60 line2 = f.readline()
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
61 else:
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
62 continue
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
63 if aln_header in line2:
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
64 aln_start = line2.index(aln_header)
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
65 break
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
66 contig_name = line.split()[1] + line.split()[2]
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
67 return contig_name, aln_start
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
68
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
69
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
70 def segment_start(f):
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
71 pos = f.tell()
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
72 line = f.readline()
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
73 # detect next contig or end of file
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
74 if "********" in line or line == "" or "Number of segment pairs = " in line:
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
75 segment = False
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
76 else:
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
77 segment = True
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
78 f.seek(pos)
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
79 return segment
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
80
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
81
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
82 def get_segment(f, seq_start):
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
83 if not segment_start(f):
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
84 return None, None
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
85 aln = []
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
86 while True:
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
87 line = f.readline()
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
88 if ". : . :" in line:
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
89 continue
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
90 if "__________" in line:
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
91 consensus = f.readline().rstrip('\n')[seq_start:]
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
92 f.readline() # empty line
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
93 break
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
94 else:
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
95 aln.append(line.rstrip('\n')[seq_start:])
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
96 return aln, consensus
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
97
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
98
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
99 def aln2coverage(aln):
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
100 coverage = [0] * len(aln[0])
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
101 for a in aln:
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
102 for i, c in enumerate(a):
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
103 if c not in " -":
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
104 coverage[i] += 1
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
105 return coverage
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
106
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
107
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
108 def read_contig(f, seq_start):
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
109 contig = ""
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
110 coverage = []
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
111 while True:
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
112 aln, consensus = get_segment(f, seq_start)
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
113 if aln:
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
114 contig += consensus
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
115 coverage += aln2coverage(aln)
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
116 else:
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
117 break
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
118 return contig, coverage
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
119
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
120
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
121 def remove_gaps(consensus, coverage):
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
122 if "-" not in consensus:
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
123 return consensus, coverage
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
124 new_coverage = [
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
125 cov for cons, cov in zip(consensus, coverage) if cons != "-"
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
126 ]
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
127 new_consensus = consensus.replace("-", "")
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
128 return new_consensus, new_coverage
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
129
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
130
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
131 def extract_contigs_from_re_archive(archive, aln_output):
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
132 with zipfile.ZipFile(archive, 'r') as zip_object, open(aln_output,
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
133 'w') as fout:
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
134 flist = zip_object.infolist()
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
135 for fn in flist:
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
136 if re.match('seqclust.+[.]aln$', fn.filename):
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
137 with zip_object.open(fn.filename) as aln:
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
138 for l in aln:
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
139 fout.write(l.decode('utf-8'))
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
140 return aln_output
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
141
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
142 def read_tarean_fasta(fobj):
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
143 ids = []
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
144 s = []
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
145 for i in fobj:
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
146 ii = i.decode('utf-8')
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
147 if ii[0] == ">":
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
148 ids.append(ii)
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
149 s.append("")
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
150 else:
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
151 s[-1] = s[-1] + ii.strip()
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
152 return ids, s
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
153
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
154 def extract_tarean_contigs_from_re_archive(archive):
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
155 with zipfile.ZipFile(archive, 'r') as zip_object:
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
156 flist = zip_object.infolist()
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
157 seqs_all = []
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
158 ids_all = []
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
159 for fn in flist:
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
160 if re.match("seqclust.+dir_CL[0-9]+[/]tarean_contigs.fasta", fn.filename):
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
161 print(fn.filename)
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
162 with zip_object.open(fn.filename) as fobj:
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
163 ids, seqs = read_tarean_fasta(fobj)
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
164 # wrap sequences
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
165 seqs = ["\n".join(textwrap.wrap(s + s, 80)) for s in seqs]
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
166 seqs_all += seqs
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
167 ids_all += ids
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
168 return ids_all, seqs_all
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
169
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
170
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
171 def extract_contigs_from_re_directory(dir, aln_output):
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
172 # TODO
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
173 pass
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
174
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
175
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
176 def filter_contigs(consensus, coverage, min_coverage=5):
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
177 x = "".join([
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
178 s if cov >= min_coverage else " "
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
179 for s, cov in zip(consensus, coverage)
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
180 ]).strip()
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
181 consensus_N = "\n".join(textwrap.wrap(x.replace(" ", "N"),80))
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
182 return consensus_N
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
183
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
184
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
185 def main():
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
186 args = parse_args()
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
187 # extract aln from archive
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
188 ids, seqs = extract_tarean_contigs_from_re_archive(args.re_file)
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
189 aln_file = extract_contigs_from_re_archive(
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
190 args.re_file,
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
191 tempfile.NamedTemporaryFile().name)
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
192 with open(aln_file, 'r') as f1, open(args.fasta, 'w') as ffasta:
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
193 while True:
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
194 contig_name, seq_start = get_header(f1)
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
195 if contig_name:
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
196 consensus, coverage = remove_gaps(*read_contig(f1, seq_start))
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
197 clean_consensus = filter_contigs(consensus, coverage,
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
198 args.min_coverage)
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
199 if len(clean_consensus) >= args.min_contig_length:
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
200 ffasta.write(">{}\n".format(contig_name))
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
201 ffasta.write("{}\n".format(clean_consensus))
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
202 else:
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
203 break
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
204
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
205 # write tarean sequences:
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
206 for i, s in zip(ids, seqs):
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
207 ffasta.write(i)
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
208 ffasta.write(s + "\n")
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
209
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
210
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
211
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
212 if __name__ == "__main__":
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
213
ea6a3059a6af Uploaded
petr-novak
parents:
diff changeset
214 main()