annotate roi_plot_thumbnails.py @ 5:170e48a55078 draft

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