Beispiel #1
0
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
Beispiel #2
0
  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