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