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()