annotate jbrowse2/blastxml_to_gapped_gff3.py @ 10:0db895a99532 draft default tip

Uploaded
author fubar
date Fri, 05 Jan 2024 22:26:16 +0000
parents 234cf4490901
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
1 #!/usr/bin/env python
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
2 import argparse
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
3 import copy
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
4 import logging
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
5 import re
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
6 import sys
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
7
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
8 from BCBio import GFF
6
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
9
0
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
10 logging.basicConfig(level=logging.INFO)
6
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
11 log = logging.getLogger(name="blastxml2gff3")
0
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
12
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
13 __doc__ = """
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
14 BlastXML files, when transformed to GFF3, do not normally show gaps in the
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
15 blast hits. This tool aims to fill that "gap".
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
16 """
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
17
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
18
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
19 def blastxml2gff3(blastxml, min_gap=3, trim=False, trim_end=False, include_seq=False):
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
20 from Bio.Blast import NCBIXML
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
21 from Bio.Seq import Seq
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
22 from Bio.SeqRecord import SeqRecord
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
23 from Bio.SeqFeature import SeqFeature, SimpleLocation
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
24
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
25 blast_records = NCBIXML.parse(blastxml)
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
26 for idx_record, record in enumerate(blast_records):
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
27 # http://www.sequenceontology.org/browser/release_2.4/term/SO:0000343
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
28 match_type = { # Currently we can only handle BLASTN, BLASTP
6
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
29 "BLASTN": "nucleotide_match",
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
30 "BLASTP": "protein_match",
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
31 }.get(record.application, "match")
0
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
32
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
33 recid = record.query
6
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
34 if " " in recid:
7
234cf4490901 Uploaded
fubar
parents: 6
diff changeset
35 recid = recid[0: recid.index(" ")]
0
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
36
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
37 rec = SeqRecord(Seq("ACTG"), id=recid)
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
38 for idx_hit, hit in enumerate(record.alignments):
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
39 for idx_hsp, hsp in enumerate(hit.hsps):
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
40 qualifiers = {
6
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
41 "ID": "b2g.%s.%s.%s" % (idx_record, idx_hit, idx_hsp),
0
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
42 "source": "blast",
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
43 "score": hsp.expect,
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
44 "accession": hit.accession,
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
45 "hit_id": hit.hit_id,
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
46 "length": hit.length,
6
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
47 "hit_titles": hit.title.split(" >"),
0
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
48 }
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
49 if include_seq:
6
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
50 qualifiers.update(
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
51 {
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
52 "blast_qseq": hsp.query,
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
53 "blast_sseq": hsp.sbjct,
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
54 "blast_mseq": hsp.match,
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
55 }
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
56 )
0
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
57
6
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
58 for prop in (
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
59 "score",
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
60 "bits",
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
61 "identities",
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
62 "positives",
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
63 "gaps",
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
64 "align_length",
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
65 "strand",
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
66 "frame",
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
67 "query_start",
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
68 "query_end",
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
69 "sbjct_start",
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
70 "sbjct_end",
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
71 ):
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
72 qualifiers["blast_" + prop] = getattr(hsp, prop, None)
0
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
73
6
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
74 desc = hit.title.split(" >")[0]
7
234cf4490901 Uploaded
fubar
parents: 6
diff changeset
75 qualifiers["description"] = desc[desc.index(" "):]
0
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
76
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
77 # This required a fair bit of sketching out/match to figure out
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
78 # the first time.
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
79 #
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
80 # the match_start location must account for queries and
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
81 # subjecst that start at locations other than 1
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
82 parent_match_start = hsp.query_start - hsp.sbjct_start
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
83 # The end is the start + hit.length because the match itself
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
84 # may be longer than the parent feature, so we use the supplied
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
85 # subject/hit length to calculate the real ending of the target
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
86 # protein.
6
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
87 parent_match_end = hsp.query_start + hit.length + hsp.query.count("-")
0
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
88
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
89 # If we trim the left end, we need to trim without losing information.
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
90 used_parent_match_start = parent_match_start
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
91 if trim:
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
92 if parent_match_start < 1:
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
93 used_parent_match_start = 0
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
94
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
95 if trim or trim_end:
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
96 if parent_match_end > hsp.query_end:
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
97 parent_match_end = hsp.query_end + 1
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
98
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
99 # The ``match`` feature will hold one or more ``match_part``s
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
100 top_feature = SeqFeature(
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
101 SimpleLocation(used_parent_match_start, parent_match_end, strand=0),
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
102 type=match_type,
6
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
103 qualifiers=qualifiers,
0
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
104 )
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
105
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
106 # Unlike the parent feature, ``match_part``s have sources.
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
107 part_qualifiers = {
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
108 "source": "blast",
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
109 }
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
110 top_feature.sub_features = []
6
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
111 for idx_part, (start, end, cigar) in enumerate(
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
112 generate_parts(
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
113 hsp.query, hsp.match, hsp.sbjct, ignore_under=min_gap
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
114 )
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
115 ):
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
116 part_qualifiers["Gap"] = cigar
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
117 part_qualifiers["ID"] = qualifiers["ID"] + (".%s" % idx_part)
0
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
118
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
119 # Otherwise, we have to account for the subject start's location
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
120 match_part_start = parent_match_start + hsp.sbjct_start + start - 1
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
121
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
122 # We used to use hsp.align_length here, but that includes
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
123 # gaps in the parent sequence
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
124 #
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
125 # Furthermore align_length will give calculation errors in weird places
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
126 # So we just use (end-start) for simplicity
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
127 match_part_end = match_part_start + (end - start)
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
128
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
129 top_feature.sub_features.append(
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
130 SeqFeature(
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
131 SimpleLocation(match_part_start, match_part_end, strand=1),
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
132 type="match_part",
6
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
133 qualifiers=copy.deepcopy(part_qualifiers),
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
134 )
0
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
135 )
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
136
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
137 rec.features.append(top_feature)
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
138 rec.annotations = {}
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
139 yield rec
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
140
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
141
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
142 def __remove_query_gaps(query, match, subject):
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
143 """remove positions in all three based on gaps in query
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
144
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
145 In order to simplify math and calculations...we remove all of the gaps
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
146 based on gap locations in the query sequence::
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
147
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
148 Q:ACTG-ACTGACTG
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
149 S:ACTGAAC---CTG
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
150
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
151 will become::
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
152
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
153 Q:ACTGACTGACTG
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
154 S:ACTGAC---CTG
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
155
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
156 which greatly simplifies the process of identifying the correct location
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
157 for a match_part
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
158 """
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
159 prev = 0
6
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
160 fq = ""
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
161 fm = ""
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
162 fs = ""
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
163 for position in re.finditer("-", query):
7
234cf4490901 Uploaded
fubar
parents: 6
diff changeset
164 fq += query[prev: position.start()]
234cf4490901 Uploaded
fubar
parents: 6
diff changeset
165 fm += match[prev: position.start()]
234cf4490901 Uploaded
fubar
parents: 6
diff changeset
166 fs += subject[prev: position.start()]
0
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
167 prev = position.start() + 1
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
168 fq += query[prev:]
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
169 fm += match[prev:]
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
170 fs += subject[prev:]
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
171
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
172 return (fq, fm, fs)
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
173
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
174
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
175 def generate_parts(query, match, subject, ignore_under=3):
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
176 region_q = []
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
177 region_m = []
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
178 region_s = []
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
179
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
180 (query, match, subject) = __remove_query_gaps(query, match, subject)
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
181
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
182 region_start = -1
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
183 region_end = -1
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
184 mismatch_count = 0
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
185 for i, (q, m, s) in enumerate(zip(query, match, subject)):
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
186
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
187 # If we have a match
6
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
188 if m != " " or m == "+":
0
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
189 if region_start == -1:
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
190 region_start = i
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
191 # It's a new region, we need to reset or it's pre-seeded with
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
192 # spaces
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
193 region_q = []
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
194 region_m = []
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
195 region_s = []
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
196 region_end = i
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
197 mismatch_count = 0
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
198 else:
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
199 mismatch_count += 1
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
200
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
201 region_q.append(q)
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
202 region_m.append(m)
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
203 region_s.append(s)
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
204
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
205 if mismatch_count >= ignore_under and region_start != -1 and region_end != -1:
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
206 region_q = region_q[0:-ignore_under]
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
207 region_m = region_m[0:-ignore_under]
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
208 region_s = region_s[0:-ignore_under]
6
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
209 yield region_start, region_end + 1, cigar_from_string(
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
210 region_q, region_m, region_s, strict_m=True
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
211 )
0
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
212 region_q = []
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
213 region_m = []
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
214 region_s = []
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
215
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
216 region_start = -1
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
217 region_end = -1
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
218 mismatch_count = 0
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
219
6
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
220 yield region_start, region_end + 1, cigar_from_string(
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
221 region_q, region_m, region_s, strict_m=True
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
222 )
0
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
223
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
224
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
225 def _qms_to_matches(query, match, subject, strict_m=True):
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
226 matchline = []
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
227
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
228 for (q, m, s) in zip(query, match, subject):
6
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
229 ret = ""
0
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
230
6
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
231 if m != " " or m == "+":
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
232 ret = "="
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
233 elif m == " ":
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
234 if q == "-":
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
235 ret = "D"
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
236 elif s == "-":
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
237 ret = "I"
0
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
238 else:
6
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
239 ret = "X"
0
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
240 else:
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
241 log.warn("Bad data: \n\t%s\n\t%s\n\t%s\n" % (query, match, subject))
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
242
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
243 if strict_m:
6
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
244 if ret == "=" or ret == "X":
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
245 ret = "M"
0
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
246
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
247 matchline.append(ret)
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
248 return matchline
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
249
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
250
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
251 def _matchline_to_cigar(matchline):
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
252 cigar_line = []
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
253 last_char = matchline[0]
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
254 count = 0
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
255 for char in matchline:
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
256 if char == last_char:
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
257 count += 1
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
258 else:
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
259 cigar_line.append("%s%s" % (last_char, count))
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
260 count = 1
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
261 last_char = char
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
262 cigar_line.append("%s%s" % (last_char, count))
6
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
263 return " ".join(cigar_line)
0
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
264
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
265
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
266 def cigar_from_string(query, match, subject, strict_m=True):
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
267 matchline = _qms_to_matches(query, match, subject, strict_m=strict_m)
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
268 if len(matchline) > 0:
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
269 return _matchline_to_cigar(matchline)
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
270 else:
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
271 return ""
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
272
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
273
6
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
274 if __name__ == "__main__":
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
275 parser = argparse.ArgumentParser(
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
276 description="Convert Blast XML to gapped GFF3", epilog=""
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
277 )
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
278 parser.add_argument(
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
279 "blastxml", type=argparse.FileType("r"), help="Blast XML Output"
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
280 )
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
281 parser.add_argument(
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
282 "--min_gap",
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
283 type=int,
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
284 help="Maximum gap size before generating a new match_part",
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
285 default=3,
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
286 )
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
287 parser.add_argument(
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
288 "--trim",
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
289 action="store_true",
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
290 help="Trim blast hits to be only as long as the parent feature",
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
291 )
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
292 parser.add_argument(
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
293 "--trim_end", action="store_true", help="Cut blast results off at end of gene"
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
294 )
88b9b105c09b Uploaded
fubar
parents: 0
diff changeset
295 parser.add_argument("--include_seq", action="store_true", help="Include sequence")
0
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
296 args = parser.parse_args()
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
297
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
298 for rec in blastxml2gff3(**vars(args)):
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
299 if len(rec.features):
cd5d63cd0eb5 Uploaded
fubar
parents:
diff changeset
300 GFF.write([rec], sys.stdout)