diff roi_plot_thumbnails.py @ 0:61d9bdb6d519 draft

Uploaded
author holtgrewe
date Thu, 18 Apr 2013 08:03:38 -0400
parents
children 0ac4f6f3d984
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/roi_plot_thumbnails.py	Thu Apr 18 08:03:38 2013 -0400
@@ -0,0 +1,188 @@
+#!/usr/bin/env python
+"""Thumbnail Plot Generator.
+
+This report generator uses the binary roi_plot_thumbnails (C++ program, must
+be in PATH) to generate many PNG images with small ROI plots.  It then creates
+a HTML file that includes the PNG and adds an overlay image link map such that
+when the user clicks on a plot, she is transfered to the according position in
+a local IGV or the UCSC genome browser, for example.
+"""
+
+__author__    = 'Manuel Holtgrewe <manuel.holtgrewe@fu-berlin.de>'
+__copyright__ = 'Copyring 2013, Freie Universitaet Berlin'
+__license__   = 'BSD 3-clause'
+
+# TODO(holtgrew): Use Cheetah templates to generate HTML.
+# TODO(holtgrew): Call roi_plot_thumbnails from Python script.
+# TODO(holtgrew): from __future__ use print_function
+
+
+import argparse
+import math
+import os.path
+import sys
+
+import ngs_roi.app
+import ngs_roi.argparse
+import ngs_roi.io
+
+
+class LinkRegion(object):
+    """Region on picture with genomic interval."""
+
+    def __init__(self, x1, y1, x2, y2, ref, begin_pos, end_pos):
+        self.x1 = x1
+        self.x2 = x2
+        self.y1 = y1
+        self.y2 = y2
+        self.ref = ref
+        self.begin_pos = begin_pos
+        self.end_pos = end_pos
+
+
+class RoiPlotGrid(object):
+    """A grid of ROI plots.
+
+    width -- width one one plot
+    height -- height of one plot
+    """
+
+    # Border in each direction.
+    BORDER = 0
+    # Spacing between plots.
+    SPACE = 2
+
+    def __init__(self, width, height, columns, rows, bg_plot=(0, 0, 0, 10),
+                 frame_col=(80, 80, 80, 255), fg_col=(0, 0, 0, 255)):
+        # Properties of the grid.
+        self.width = float(width)
+        self.height = float(height)
+        self.columns = columns
+        self.rows = rows
+        # State.
+        self.idx = 0  # currently drawn plot
+        self.canvas_width = 2 * self.BORDER + columns * width + (columns - 1) * self.SPACE
+        self.canvas_height = 2 * self.BORDER + rows * height + (rows - 1) * self.SPACE
+        # Colors.
+        self.bg_plot = bg_plot
+        self.frame_col = frame_col
+        self.fg_color = fg_col
+        # List of link region for image map.
+        self.link_regions = []
+
+    def plotStart(self, idx):
+        """Return pair with start coordinates of plot."""
+        row = idx / self.columns
+        col = idx % self.columns
+        x = self.BORDER + col * (self.width + self.SPACE)
+        y = self.BORDER + row * (self.height + self.SPACE)
+        return x, y
+
+    def plotRecord(self, record):
+        """Register plotting of a record."""
+        start_x, start_y = self.plotStart(self.idx)
+        self.idx += 1
+        # Register link region.
+        self.link_regions.append(LinkRegion(
+                start_x, start_y, start_x + self.width, start_y + self.height,
+                record.ref, record.start_pos, record.end_pos))
+
+
+class GridLinks(object):
+    """Link information for one grid."""
+
+    def __init__(self, file_name, link_regions):
+        self.file_name = file_name
+        self.link_regions = link_regions
+
+
+class PlotThumbnailsApp(ngs_roi.app.App):
+    def __init__(self, args):
+        # Call parent's constructor.
+        ngs_roi.app.App.__init__(self, args)
+        self.prepareOutDir()
+        # Initialize members.
+        self.grid = None
+        self.plot_idx = 0
+        self.grid_links = []
+
+    def run(self):
+        # Load ROI records.
+        print >>sys.stderr, 'Loading ROI'
+
+        # Create plots.
+        runner = ngs_roi.app.PlotThumbnailsRunner(self.args)
+        runner.run()
+
+        # Create HTML.
+        print >>sys.stderr, 'Creating HTML...'
+        num_plots = self.args.num_cols * self.args.num_rows  # plots on grid
+        for i, roi in enumerate(ngs_roi.io.RoiFile(self.args.in_file)):
+            if self.args.max_rois > 0 and i >= self.args.max_rois:
+                break
+            # Write out old grid (if any) and create new one.
+            if i % num_plots == 0:
+                if self.grid:
+                    print >>sys.stderr, '  Writing plot %d...' % self.plot_idx
+                self.writeGrid()
+                self.grid = RoiPlotGrid(self.args.plot_width, self.args.plot_height,
+                                        self.args.num_cols, self.args.num_rows)
+            # Put the next plot on the grid.
+            self.grid.plotRecord(roi)
+        print >>sys.stderr, '  Writing plot %d...' % self.plot_idx
+        self.writeGrid()  # Write last grid.
+        self.createHtml(self.args.out_file)
+        return 0
+
+    def writeGrid(self):
+        """Register writing of grid."""
+        if not self.grid:
+            return
+        # Append grid info.
+        file_name = 'thumbnail_%d.png' % self.plot_idx
+        file_name = os.path.join(self.args.out_dir, file_name)
+        self.plot_idx += 1
+        self.grid_links.append(GridLinks(os.path.basename(file_name), self.grid.link_regions))
+
+    def createHtml(self, file_name):
+        print >>sys.stderr, 'Writing HTML to %s' % file_name
+        with open(file_name, 'wb') as f:
+            f.write('<html><body>\n')
+            f.write('<iframe name="empty" height="0" width="0" src="about:blank"></iframe>\n')
+            for gl in self.grid_links:
+                vals = (gl.file_name, gl.file_name, self.grid.canvas_width, self.grid.canvas_height)
+                f.write('<img src="%s" usemap="#%s" width="%d" height="%d" />\n' % vals)
+                f.write('<map name="%s">\n' % gl.file_name)
+                for lr in gl.link_regions:
+                    locus = (lr.ref, lr.begin_pos + 1, lr.end_pos)
+                    vals = {'x1': lr.x1, 'x2': lr.x2, 'y1': lr.y1, 'y2': lr.y2,
+                            'title': '%s %d-%d' % locus,
+                            'href': self.buildHref(lr.ref, lr.begin_pos, lr.end_pos),
+                            'onclick': ''}
+                    # Add onclick handler to prevent opening of new window.
+                    vals['target_attr'] = ''
+                    if self.args.link_target:
+                        vals['target_attr'] = ' target="%s"' % self.args.link_target
+                    if self.args.link_type == 'local_igv':
+                        vals['target_attr'] = ' target="empty"'
+                    f.write('  <area shape="rect" coords="%(x1)d,%(y1)d,%(x2)d,%(y2)d" '
+                             'alt="%(title)s" title="%(title)s" href="%(href)s"%(target_attr)s />\n' % vals)
+                f.write('</map>\n')
+            f.write('</body></html>\n')
+
+
+def main():
+    """Program entry point."""
+    parser = argparse.ArgumentParser(description='Plot ROI file.')
+    ngs_roi.argparse.addFileArguments(parser)
+    ngs_roi.argparse.addPlotGridArguments(parser)
+    ngs_roi.argparse.addLinkArguments(parser)
+    args = parser.parse_args()
+    ngs_roi.argparse.applyFileDefaults(args)
+
+    app = PlotThumbnailsApp(args)
+    return app.run()
+
+
+if __name__ == '__main__':
+    sys.exit(main())