0
|
1 #!/usr/bin/env python
|
|
2 """Thumbnail Plot Generator.
|
|
3
|
|
4 This report generator uses the binary roi_plot_thumbnails (C++ program, must
|
|
5 be in PATH) to generate many PNG images with small ROI plots. It then creates
|
|
6 a HTML file that includes the PNG and adds an overlay image link map such that
|
|
7 when the user clicks on a plot, she is transfered to the according position in
|
|
8 a local IGV or the UCSC genome browser, for example.
|
|
9 """
|
|
10
|
|
11 __author__ = 'Manuel Holtgrewe <manuel.holtgrewe@fu-berlin.de>'
|
|
12 __copyright__ = 'Copyring 2013, Freie Universitaet Berlin'
|
|
13 __license__ = 'BSD 3-clause'
|
|
14
|
|
15 # TODO(holtgrew): Use Cheetah templates to generate HTML.
|
|
16 # TODO(holtgrew): Call roi_plot_thumbnails from Python script.
|
|
17 # TODO(holtgrew): from __future__ use print_function
|
|
18
|
|
19
|
5
|
20 try:
|
|
21 import argparse
|
|
22 except ImportError:
|
|
23 import argparse26 as argparse
|
0
|
24 import math
|
|
25 import os.path
|
|
26 import sys
|
|
27
|
|
28 import ngs_roi.app
|
|
29 import ngs_roi.argparse
|
|
30 import ngs_roi.io
|
|
31
|
|
32
|
|
33 class LinkRegion(object):
|
|
34 """Region on picture with genomic interval."""
|
|
35
|
|
36 def __init__(self, x1, y1, x2, y2, ref, begin_pos, end_pos):
|
|
37 self.x1 = x1
|
|
38 self.x2 = x2
|
|
39 self.y1 = y1
|
|
40 self.y2 = y2
|
|
41 self.ref = ref
|
|
42 self.begin_pos = begin_pos
|
|
43 self.end_pos = end_pos
|
|
44
|
|
45
|
|
46 class RoiPlotGrid(object):
|
|
47 """A grid of ROI plots.
|
|
48
|
|
49 width -- width one one plot
|
|
50 height -- height of one plot
|
|
51 """
|
|
52
|
|
53 # Border in each direction.
|
|
54 BORDER = 0
|
|
55 # Spacing between plots.
|
|
56 SPACE = 2
|
|
57
|
|
58 def __init__(self, width, height, columns, rows, bg_plot=(0, 0, 0, 10),
|
|
59 frame_col=(80, 80, 80, 255), fg_col=(0, 0, 0, 255)):
|
|
60 # Properties of the grid.
|
|
61 self.width = float(width)
|
|
62 self.height = float(height)
|
|
63 self.columns = columns
|
|
64 self.rows = rows
|
|
65 # State.
|
|
66 self.idx = 0 # currently drawn plot
|
|
67 self.canvas_width = 2 * self.BORDER + columns * width + (columns - 1) * self.SPACE
|
|
68 self.canvas_height = 2 * self.BORDER + rows * height + (rows - 1) * self.SPACE
|
|
69 # Colors.
|
|
70 self.bg_plot = bg_plot
|
|
71 self.frame_col = frame_col
|
|
72 self.fg_color = fg_col
|
|
73 # List of link region for image map.
|
|
74 self.link_regions = []
|
|
75
|
|
76 def plotStart(self, idx):
|
|
77 """Return pair with start coordinates of plot."""
|
|
78 row = idx / self.columns
|
|
79 col = idx % self.columns
|
|
80 x = self.BORDER + col * (self.width + self.SPACE)
|
|
81 y = self.BORDER + row * (self.height + self.SPACE)
|
|
82 return x, y
|
|
83
|
|
84 def plotRecord(self, record):
|
|
85 """Register plotting of a record."""
|
|
86 start_x, start_y = self.plotStart(self.idx)
|
|
87 self.idx += 1
|
|
88 # Register link region.
|
|
89 self.link_regions.append(LinkRegion(
|
|
90 start_x, start_y, start_x + self.width, start_y + self.height,
|
|
91 record.ref, record.start_pos, record.end_pos))
|
|
92
|
|
93
|
|
94 class GridLinks(object):
|
|
95 """Link information for one grid."""
|
|
96
|
|
97 def __init__(self, file_name, link_regions):
|
|
98 self.file_name = file_name
|
|
99 self.link_regions = link_regions
|
|
100
|
|
101
|
|
102 class PlotThumbnailsApp(ngs_roi.app.App):
|
|
103 def __init__(self, args):
|
|
104 # Call parent's constructor.
|
|
105 ngs_roi.app.App.__init__(self, args)
|
|
106 self.prepareOutDir()
|
|
107 # Initialize members.
|
|
108 self.grid = None
|
|
109 self.plot_idx = 0
|
|
110 self.grid_links = []
|
|
111
|
|
112 def run(self):
|
|
113 # Load ROI records.
|
|
114 print >>sys.stderr, 'Loading ROI'
|
|
115
|
|
116 # Create plots.
|
|
117 runner = ngs_roi.app.PlotThumbnailsRunner(self.args)
|
|
118 runner.run()
|
|
119
|
|
120 # Create HTML.
|
|
121 print >>sys.stderr, 'Creating HTML...'
|
|
122 num_plots = self.args.num_cols * self.args.num_rows # plots on grid
|
|
123 for i, roi in enumerate(ngs_roi.io.RoiFile(self.args.in_file)):
|
|
124 if self.args.max_rois > 0 and i >= self.args.max_rois:
|
|
125 break
|
|
126 # Write out old grid (if any) and create new one.
|
|
127 if i % num_plots == 0:
|
|
128 if self.grid:
|
|
129 print >>sys.stderr, ' Writing plot %d...' % self.plot_idx
|
|
130 self.writeGrid()
|
|
131 self.grid = RoiPlotGrid(self.args.plot_width, self.args.plot_height,
|
|
132 self.args.num_cols, self.args.num_rows)
|
|
133 # Put the next plot on the grid.
|
|
134 self.grid.plotRecord(roi)
|
|
135 print >>sys.stderr, ' Writing plot %d...' % self.plot_idx
|
|
136 self.writeGrid() # Write last grid.
|
|
137 self.createHtml(self.args.out_file)
|
|
138 return 0
|
|
139
|
|
140 def writeGrid(self):
|
|
141 """Register writing of grid."""
|
|
142 if not self.grid:
|
|
143 return
|
|
144 # Append grid info.
|
|
145 file_name = 'thumbnail_%d.png' % self.plot_idx
|
|
146 file_name = os.path.join(self.args.out_dir, file_name)
|
|
147 self.plot_idx += 1
|
|
148 self.grid_links.append(GridLinks(os.path.basename(file_name), self.grid.link_regions))
|
|
149
|
|
150 def createHtml(self, file_name):
|
|
151 print >>sys.stderr, 'Writing HTML to %s' % file_name
|
|
152 with open(file_name, 'wb') as f:
|
|
153 f.write('<html><body>\n')
|
1
|
154 f.write('<h1>ROI Thumbnail Plots</h1>')
|
0
|
155 for gl in self.grid_links:
|
|
156 vals = (gl.file_name, gl.file_name, self.grid.canvas_width, self.grid.canvas_height)
|
|
157 f.write('<img src="%s" usemap="#%s" width="%d" height="%d" />\n' % vals)
|
|
158 f.write('<map name="%s">\n' % gl.file_name)
|
|
159 for lr in gl.link_regions:
|
|
160 locus = (lr.ref, lr.begin_pos + 1, lr.end_pos)
|
|
161 vals = {'x1': lr.x1, 'x2': lr.x2, 'y1': lr.y1, 'y2': lr.y2,
|
|
162 'title': '%s %d-%d' % locus,
|
|
163 'href': self.buildHref(lr.ref, lr.begin_pos, lr.end_pos),
|
|
164 'onclick': ''}
|
|
165 # Add onclick handler to prevent opening of new window.
|
|
166 vals['target_attr'] = ''
|
|
167 if self.args.link_target:
|
|
168 vals['target_attr'] = ' target="%s"' % self.args.link_target
|
|
169 if self.args.link_type == 'local_igv':
|
|
170 vals['target_attr'] = ' target="empty"'
|
|
171 f.write(' <area shape="rect" coords="%(x1)d,%(y1)d,%(x2)d,%(y2)d" '
|
|
172 'alt="%(title)s" title="%(title)s" href="%(href)s"%(target_attr)s />\n' % vals)
|
|
173 f.write('</map>\n')
|
1
|
174 f.write('<iframe name="empty" height="0" width="0" src="about:blank"></iframe>\n')
|
|
175 f.write('<div><code>' + str(self.args) + '</code></div></body></html>\n')
|
0
|
176
|
|
177
|
|
178 def main():
|
|
179 """Program entry point."""
|
|
180 parser = argparse.ArgumentParser(description='Plot ROI file.')
|
|
181 ngs_roi.argparse.addFileArguments(parser)
|
|
182 ngs_roi.argparse.addPlotGridArguments(parser)
|
|
183 ngs_roi.argparse.addLinkArguments(parser)
|
|
184 args = parser.parse_args()
|
|
185 ngs_roi.argparse.applyFileDefaults(args)
|
|
186
|
|
187 app = PlotThumbnailsApp(args)
|
|
188 return app.run()
|
|
189
|
|
190
|
|
191 if __name__ == '__main__':
|
|
192 sys.exit(main())
|