def __init__(self, filename): self.cube = DataCube(filename, calc_noise_dev=False) win = gtk.Window() win.connect("destroy", lambda x: gtk.main_quit()) win.set_default_size(800,600) win.set_title("{ln} spectral line map of {o}".format(o=self.cube.object_name,ln=self.cube.line_name)) # Create our three main widgets: # A CubeViewWidget and a connected DendrogramViewWidget in the top row: self.cube_view = CubeViewWidget(self.cube, win) self.dendro_view = DendrogramViewWidget(self.cube, win) first_row = gtk.HPaned() first_row.pack1(self.cube_view, resize=True, shrink=True) first_row.pack2(self.dendro_view, resize=True, shrink=True) # and an IPython command widget in the bottom row: ipython_namespace = {'cube': self.cube, 'cube_view': self.cube_view, 'dendro_view': self.dendro_view, 'create_highlighter': self.create_highlighter, 'set_color_map': self.set_color_map, 'set_data': self.set_data, 'make_dendrogram': self.dendro_view.make_dendrogram, 'export_pdf': self.export_pdf, 'export_png': self.export_png } self.ipython_widget = IPythonView() for key,val in ipython_namespace.items(): self.ipython_widget.IP.user_ns[key] = val # An IPython widget does not support scrolling by itself... self.ipython_widget.set_wrap_mode(gtk.WRAP_CHAR) ipython_scroller = gtk.ScrolledWindow() # so we wrap it in a scrolled window ipython_scroller.set_size_request(-1,75) ipython_scroller.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS) ipython_scroller.add(self.ipython_widget) main_pane = gtk.VPaned() main_pane.pack1(first_row, resize=True, shrink=True) main_pane.pack2(ipython_scroller, resize=True, shrink=False) main_pane.set_position(9000) # Expand the figure to be as big as possible win.add(main_pane) self.win = win # Set up events: self.cube_view.on_click(self.cube_clicked) self.cube_highlight = self.cube_view.create_highlighter() self.dendro_view.on_click(self.dendro_clicked) self.dendro_view.on_compute(self.dendro_computed) self.highlighted_item = None
class DendroViewer: def __init__(self, filename): self.cube = DataCube(filename, calc_noise_dev=False) win = gtk.Window() win.connect("destroy", lambda x: gtk.main_quit()) win.set_default_size(800,600) win.set_title("{ln} spectral line map of {o}".format(o=self.cube.object_name,ln=self.cube.line_name)) # Create our three main widgets: # A CubeViewWidget and a connected DendrogramViewWidget in the top row: self.cube_view = CubeViewWidget(self.cube, win) self.dendro_view = DendrogramViewWidget(self.cube, win) first_row = gtk.HPaned() first_row.pack1(self.cube_view, resize=True, shrink=True) first_row.pack2(self.dendro_view, resize=True, shrink=True) # and an IPython command widget in the bottom row: ipython_namespace = {'cube': self.cube, 'cube_view': self.cube_view, 'dendro_view': self.dendro_view, 'create_highlighter': self.create_highlighter, 'set_color_map': self.set_color_map, 'set_data': self.set_data, 'make_dendrogram': self.dendro_view.make_dendrogram, 'export_pdf': self.export_pdf, 'export_png': self.export_png } self.ipython_widget = IPythonView() for key,val in ipython_namespace.items(): self.ipython_widget.IP.user_ns[key] = val # An IPython widget does not support scrolling by itself... self.ipython_widget.set_wrap_mode(gtk.WRAP_CHAR) ipython_scroller = gtk.ScrolledWindow() # so we wrap it in a scrolled window ipython_scroller.set_size_request(-1,75) ipython_scroller.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS) ipython_scroller.add(self.ipython_widget) main_pane = gtk.VPaned() main_pane.pack1(first_row, resize=True, shrink=True) main_pane.pack2(ipython_scroller, resize=True, shrink=False) main_pane.set_position(9000) # Expand the figure to be as big as possible win.add(main_pane) self.win = win # Set up events: self.cube_view.on_click(self.cube_clicked) self.cube_highlight = self.cube_view.create_highlighter() self.dendro_view.on_click(self.dendro_clicked) self.dendro_view.on_compute(self.dendro_computed) self.highlighted_item = None def run(self): self.win.show_all() gtk.main() def dendro_computed(self, dendrogram): self.ipython_widget.IP.user_ns['dendro'] = dendrogram def cube_clicked(self, coords, flux): item_clicked = self.dendro_view.set_clicked_item_by_coords(coords) if (item_clicked): self.highlight_item_in_cube(item_clicked) def dendro_clicked(self, item): if item: if item != self.highlighted_item: self.highlighted_item = item self.highlight_item_in_cube(item) else: # User has clicked on the item already highlighted. # Mark the point of greatest flux in the view: _,max_coords,_ = item.get_peak_recursive() self.cube_view.x, self.cube_view.y, self.cube_view.z = max_coords else: self.highlighted_item = None self.cube_highlight.clear() def highlight_item_in_cube(self, item): mapdata = np.zeros(self.cube.data.shape) item.add_footprint(mapdata, 1) mapdata[mapdata>1] = 0.75 # Set the child items to be semi-transparent self.cube_highlight.highlight(mapdata) ### Convenience methods for the user to enter via IPython shell: def set_data(self, data): """ Call this method to change the data shown in the cube view and used to compute the dendrogram. """ self.cube.data = data self.cube_view.update() self.dendro_view.data = data # This will also clear the dendrogram def set_color_map(self, cmap = CubeViewWidget.default_cmap): """ Sets the color map used by the cube view (left hand side). Use "bone" (greyscale), "spectral", or any other matplotlib color map. Pass no argument for the default color map. """ self.cube_view.imgplot.set_cmap(cmap) self.cube_view.axes.figure.canvas.draw() def export_pdf(self, filename, title="default", subtitle="default", include_cube_slice=True): """ Create a standardized one or two -page PDF of the current figures Filename is e.g. "export1.pdf" Title gets put on every figure in the PDF Set include_cube_slice to False to export only the dendrogram If include_cube_slide is true, the cube view will be exported, at the Z value currently visible in the viewer. """ pp = PdfPages(filename) # Figure out the titles and subtitles cube_subtitle = None # This gets prepended to the subitle of the cube only, not the dendrogram if title is "default": # Default title: title = "Dendrogram from {obj} {line}".format(obj=self.cube.object_name, line=self.cube.line_name) if subtitle is "default": subtitle = "Dendrogram parameters: min. flux {f}, min. npix {n:.0f}, min. delta {d}".format( f=self.dendro_view.dendrogram.min_flux, n=self.dendro_view.dendrogram.min_npix, d=self.dendro_view.dendrogram.min_delta, ) if include_cube_slice: if self.cube.has_coords: cube_subtitle = "@ {v:.2f} km/s (z={z}). {rest}".format( v=self.cube.velocity_at(self.cube_view.z), z=self.cube_view.z, rest=subtitle, ) else: cube_subtitle = "@ z={z}. {rest}".format(z=self.cube_view.z, rest=subtitle) export_size = (10,7.5) # in inches if include_cube_slice: cfig = self.cube_view.fig self.cube_view._check_redraw() old_size_cfig = (cfig.get_figwidth(), cfig.get_figheight()) cfig.set_size_inches(*export_size) if title: ctitle = cfig.suptitle(title, weight='heavy', size='large') if cube_subtitle: ctitle2 = cfig.suptitle(cube_subtitle, y=0.95) pp.savefig(cfig) # Reset the figure to how it was before: if title: ctitle.set_visible(False) # Closest we can come to deleting these titles if cube_subtitle: ctitle2.set_visible(False) cfig.set_figwidth(old_size_cfig[0]) cfig.set_figheight(old_size_cfig[1]) # Now export the dendrogram figure: dfig = self.dendro_view.fig #old_size_dfig = dfig.get_size_inches() old_size_dfig = (dfig.get_figwidth(), dfig.get_figheight()) dfig.set_size_inches(*export_size) if title: dtitle = dfig.suptitle(title, weight='heavy', size='large') if subtitle: dtitle2 = dfig.suptitle(subtitle, y=0.95) pp.savefig(self.dendro_view.fig) # Reset the figure to how it was before: if title: dtitle.set_visible(False) if subtitle: dtitle2.set_visible(False) #dfig.set_size_inches(old_size_dfig) dfig.set_figwidth(old_size_dfig[0]) dfig.set_figheight(old_size_dfig[1]) # Finalize the PDF: if title: pp.infodict()['Title'] = title pp.close() pp = None # Now the draw() method must be called, or some of the dendrogram # plot artists will cache the PDF renderer and cause bugs, due to # the dendro_view's special handling of rendering self.dendro_view.fig.canvas.draw() def export_png(self, filename_cube, filename_dendro): from matplotlib.backends.backend_agg import FigureCanvasAgg if filename_cube: #self.cube_view.fig.canvas.print_png(filename_cube) canvas = self.cube_view.fig.canvas agg = canvas.switch_backends(FigureCanvasAgg) agg.print_png(filename_cube) agg = None self.cube_view.fig.set_canvas(canvas) if filename_dendro: #self.dendro_view.fig.canvas.print_png(filename_dendro) canvas = self.dendro_view.fig.canvas agg = canvas.switch_backends(FigureCanvasAgg) agg.print_png(filename_dendro) agg = None self.dendro_view.fig.set_canvas(canvas) # Now the draw() method must be called, or some of the dendrogram # plot artists will cache the PDF renderer and cause bugs, due to # the dendro_view's special handling of rendering self.dendro_view.fig.canvas.draw() def create_highlighter(self, color): return self._CombinedHighlighter(self.cube_view, self.dendro_view, color) class _CombinedHighlighter: """ A highlighter that highlights the data cube and the dendrogram Do not initialize directly, but get from create_highlighter() """ def __init__(self, cube_view, dendro_view, color): self.color = color self.cube_view = cube_view self.dendro_view = dendro_view self._highlighter_cube = cube_view.create_highlighter(color) self._highlighter_dend = dendro_view.dendro_plot.create_highlighter(color) if dendro_view.dendro_plot else None def highlight_coords(self, coords): if self.dendro_view.dendrogram: self.highlight_item(self.dendro_view.dendrogram.item_at(coords)) else: print("Cannot highlight until a dendrogram is plotted") def highlight_item(self, item): if not item: self._highlighter_cube.clear() if self._highlighter_dend: self._highlighter_dend.clear() return mapdata = np.zeros(self.cube_view.cube.data.shape) item.add_footprint(mapdata, 1) mapdata[mapdata>1] = 0.75 # Set the child items to be semi-transparent if not self._highlighter_dend: # There was no dendrogram plot when this combined highlighter was created if self.dendro_view.dendro_plot: # But one exists now: self._highlighter_dend = self.dendro_view.dendro_plot.create_highlighter(self.color) else: # And there still isn't, so we're done return elif self._highlighter_dend.plot != self.dendro_view.dendro_plot: # The dendrogram has changed (been re-plotted), so re-create the highlighter: self._highlighter_dend.clear() self._highlighter_dend = self.dendro_view.dendro_plot.create_highlighter(self.color) # Now highlight on the dendrogram plot: self._highlighter_cube.highlight(mapdata) self._highlighter_dend.highlight(item)