Mercurial > repos > jankanis > blast2html
comparison blast_html.py @ 18:4434ffab721a
add a parameter for the template
author | Jan Kanis <jan.code@jankanis.nl> |
---|---|
date | Tue, 13 May 2014 15:26:20 +0200 |
parents | db7e4ee3be03 |
children | 67ddcb807b7d |
comparison
equal
deleted
inserted
replaced
17:8e61627a87f1 | 18:4434ffab721a |
---|---|
4 # License: GPL version 3 or higher | 4 # License: GPL version 3 or higher |
5 | 5 |
6 import sys | 6 import sys |
7 import math | 7 import math |
8 import warnings | 8 import warnings |
9 from os import path | |
9 from itertools import repeat | 10 from itertools import repeat |
10 import argparse | 11 import argparse |
11 from lxml import objectify | 12 from lxml import objectify |
12 import jinja2 | 13 import jinja2 |
13 | 14 |
113 # (u'\u2028', r'\u2028'), | 114 # (u'\u2028', r'\u2028'), |
114 # (u'\u2029', r'\u2029') | 115 # (u'\u2029', r'\u2029') |
115 ) | 116 ) |
116 | 117 |
117 # Escape every ASCII character with a value less than 32. This is | 118 # Escape every ASCII character with a value less than 32. This is |
118 # needed a.o. to prevent parsers from jumping out of javascript | 119 # needed a.o. to prevent html parsers from jumping out of javascript |
119 # parsing mode. | 120 # parsing mode. |
120 _js_escapes = (_base_js_escapes + | 121 _js_escapes = (_base_js_escapes + |
121 tuple(('%c' % z, '\\u%04X' % z) for z in range(32))) | 122 tuple(('%c' % z, '\\u%04X' % z) for z in range(32))) |
122 | 123 |
123 @filter | 124 @filter |
139 | 140 |
140 colors = ('black', 'blue', 'green', 'magenta', 'red') | 141 colors = ('black', 'blue', 'green', 'magenta', 'red') |
141 | 142 |
142 max_scale_labels = 10 | 143 max_scale_labels = 10 |
143 | 144 |
144 templatename = 'blast_html.html.jinja' | 145 def __init__(self, input, templatedir, templatename): |
145 | |
146 def __init__(self, input): | |
147 self.input = input | 146 self.input = input |
147 self.templatename = templatename | |
148 | 148 |
149 self.blast = objectify.parse(self.input).getroot() | 149 self.blast = objectify.parse(self.input).getroot() |
150 self.loader = jinja2.FileSystemLoader(searchpath='.') | 150 self.loader = jinja2.FileSystemLoader(searchpath=templatedir) |
151 self.environment = jinja2.Environment(loader=self.loader, | 151 self.environment = jinja2.Environment(loader=self.loader, |
152 lstrip_blocks=True, trim_blocks=True, autoescape=True) | 152 lstrip_blocks=True, trim_blocks=True, autoescape=True) |
153 | 153 |
154 self.environment.filters.update(_filters) | |
154 self.environment.filters['color'] = lambda length: match_colors[color_idx(length)] | 155 self.environment.filters['color'] = lambda length: match_colors[color_idx(length)] |
155 | |
156 for name, filter in _filters.items(): | |
157 self.environment.filters[name] = filter | |
158 | 156 |
159 self.query_length = int(self.blast["BlastOutput_query-len"]) | 157 self.query_length = int(self.blast["BlastOutput_query-len"]) |
160 self.hits = self.blast.BlastOutput_iterations.Iteration.Iteration_hits.Hit | 158 self.hits = self.blast.BlastOutput_iterations.Iteration.Iteration_hits.Hit |
161 # sort hits by longest hotspot first | 159 # sort hits by longest hotspot first |
162 self.ordered_hits = sorted(self.hits, | 160 self.ordered_hits = sorted(self.hits, |
175 | 173 |
176 if len(self.blast.BlastOutput_iterations.Iteration) > 1: | 174 if len(self.blast.BlastOutput_iterations.Iteration) > 1: |
177 warnings.warn("Multiple 'Iteration' elements found, showing only the first") | 175 warnings.warn("Multiple 'Iteration' elements found, showing only the first") |
178 | 176 |
179 output.write(template.render(blast=self.blast, | 177 output.write(template.render(blast=self.blast, |
180 length=self.query_length, | 178 length=self.query_length, |
181 hits=self.blast.BlastOutput_iterations.Iteration.Iteration_hits.Hit, | 179 hits=self.blast.BlastOutput_iterations.Iteration.Iteration_hits.Hit, |
182 colors=self.colors, | 180 colors=self.colors, |
183 match_colors=self.match_colors(), | 181 match_colors=self.match_colors(), |
184 queryscale=self.queryscale(), | 182 queryscale=self.queryscale(), |
185 hit_info=self.hit_info(), | 183 hit_info=self.hit_info(), |
186 genelink=genelink, | 184 genelink=genelink, |
187 params=params)) | 185 params=params)) |
188 | 186 |
189 | 187 |
190 def match_colors(self): | 188 def match_colors(self): |
191 """ | 189 """ |
192 An iterator that yields lists of length-color pairs. | 190 An iterator that yields lists of length-color pairs. |
193 """ | 191 """ |
251 e_value = "{:.4g}".format(min(hsp_val('Hsp_evalue'))), | 249 e_value = "{:.4g}".format(min(hsp_val('Hsp_evalue'))), |
252 # FIXME: is this the correct formula vv? | 250 # FIXME: is this the correct formula vv? |
253 ident = "{:.0%}".format(float(min(hsp.Hsp_identity / hsplen(hsp) for hsp in hsps))), | 251 ident = "{:.0%}".format(float(min(hsp.Hsp_identity / hsplen(hsp) for hsp in hsps))), |
254 accession = hit.Hit_accession) | 252 accession = hit.Hit_accession) |
255 | 253 |
256 | |
257 def main(): | 254 def main(): |
258 | 255 |
259 parser = argparse.ArgumentParser(description="Convert a BLAST XML result into a nicely readable html page", | 256 parser = argparse.ArgumentParser(description="Convert a BLAST XML result into a nicely readable html page", |
260 usage="{} [-i] INPUT [-o OUTPUT]".format(sys.argv[0])) | 257 usage="{} [-i] INPUT [-o OUTPUT]".format(sys.argv[0])) |
261 input_group = parser.add_mutually_exclusive_group(required=True) | 258 input_group = parser.add_mutually_exclusive_group(required=True) |
263 help='The input Blast XML file, same as -i/--input') | 260 help='The input Blast XML file, same as -i/--input') |
264 input_group.add_argument('-i', '--input', type=argparse.FileType(mode='r'), | 261 input_group.add_argument('-i', '--input', type=argparse.FileType(mode='r'), |
265 help='The input Blast XML file') | 262 help='The input Blast XML file') |
266 parser.add_argument('-o', '--output', type=argparse.FileType(mode='w'), default=sys.stdout, | 263 parser.add_argument('-o', '--output', type=argparse.FileType(mode='w'), default=sys.stdout, |
267 help='The output html file') | 264 help='The output html file') |
265 # We just want the file name here, so jinja can open the file | |
266 # itself. But it is easier to just use a FileType so argparse can | |
267 # handle the errors. This introduces a small race condition when | |
268 # jinja later tries to re-open the template file, but we don't | |
269 # care too much. | |
270 parser.add_argument('--template', type=argparse.FileType(mode='r'), default='blast_html.html.jinja', | |
271 help='The template file to use. Defaults to blast_html.html.jinja') | |
268 | 272 |
269 args = parser.parse_args() | 273 args = parser.parse_args() |
270 if args.input == None: | 274 if args.input == None: |
271 args.input = args.positional_arg | 275 args.input = args.positional_arg |
272 if args.input == None: | 276 if args.input == None: |
273 parser.error('no input specified') | 277 parser.error('no input specified') |
274 | 278 |
275 b = BlastVisualize(args.input) | 279 templatedir, templatename = path.split(args.template.name) |
280 args.template.close() | |
281 if not templatedir: | |
282 templatedir = '.' | |
283 | |
284 b = BlastVisualize(args.input, templatedir, templatename) | |
276 b.render(args.output) | 285 b.render(args.output) |
277 | 286 |
278 | 287 |
279 if __name__ == '__main__': | 288 if __name__ == '__main__': |
280 main() | 289 main() |