def wrap_plot(plot): # helper function, to wrap MatPlotLib figure and PyQtGraph PlotItem/ViewBox/etc in a Qt widget if type(plot).__name__ == 'Figure': widget = FigureCanvas(plot) else: widget = pg.GraphicsLayoutWidget() widget.addItem(plot) return widget
def on_visualization_ready(self, panel_name, data, source_code, base_folder): """Called when an updated visualization (possibly new) has been loaded for the current experiment""" # ignore it if it's not the right base folder (happens when the user does not # wait for loading to finish and selects another experiment) if base_folder != self.folder: return # render the MatPlotLib/PyQtGraph figures new_plots = self.render_visualization(panel_name, data, source_code) # assign each plot to a new or reused panel. # NOTE: most of this complicated logic is to deal with a specific MatPlotLib/ # FigureCanvas bug. we cannot delete a FigureCanvas and assign a new one to the # same figure, or there are many graphical glitches (especially related to DPI). # to avoid this, we reuse the same widget (actually the parent panel widget) for # the same MatPlotLib figure every time (stored as overboard_panel attribute). new_panels = [] old_panels = self.panels.get(panel_name, []) old_panels_pg = [p for p in old_panels if p.plot_type == 'PlotItem'] old_panels_gl = [p for p in old_panels if p.plot_type == 'GLViewWidget'] for (name, plot) in new_plots.items(): plot_type = self.get_plot_type(plot) if plot_type == 'Figure': # MatPlotLib Figure if hasattr(plot, 'overboard_panel'): # always reuse a previous panel panel = self.window.add_panel(plot.overboard_panel, name, reuse=True) panel.plot_widget.draw() # ensure the figure is redrawn else: # it's new widget = FigureCanvas(plot) panel = self.window.add_panel(widget, name) plot.overboard_panel = panel # always associate the same panel with this figure elif plot_type == 'PlotItem': # PyQtGraph PlotItem if old_panels_pg: # we can reuse an old panel and the pg.GraphicsLayoutWidget that it contains panel = old_panels_pg.pop() panel.plot_widget.clear() panel.plot_widget.addItem(plot) panel = self.window.add_panel(panel, name, reuse=True) else: # it's new widget = pg.GraphicsLayoutWidget() widget.addItem(plot) panel = self.window.add_panel(widget, name) elif plot_type in ('GLViewWidget', 'PlotWidget'): # PyQtGraph GLViewWidget/PlotWidget widget = plot if old_panels_gl: # we can reuse an old panel, but assign the new GLViewWidget to it panel = old_panels_gl.pop() # remove the old one panel.plot_widget.setParent(None) panel.layout().removeWidget(panel.plot_widget) if panel.plot_widget is not widget: # don't delete if the same widget was returned by the user's custom function panel.plot_widget.deleteLater() # insert the new panel.plot_widget = widget panel.layout().addWidget(widget, stretch=1) panel = self.window.add_panel(panel, name, reuse=True) else: # it's new panel = self.window.add_panel(widget, name) plot.show() # ensure the OpenGL plot is updated panel.plot_type = plot_type # remember the plot type (regardless of nested widgets) new_panels.append(panel) panel.title_widget.setText(name) # ensure title is correct # remove any panels we did not reuse from the layout self.delete_vis_panels(list(set(old_panels) - set(new_panels))) self.panels[panel_name] = new_panels