def __init__(self, parent): super(MplWidget, self).__init__(parent) # Create the mpl figure and subplot (white bg, 100 dots-per-inch). # Construct the canvas with the figure: self.plt_lim = [] # define variable for x,y plot limits if cmp_version("matplotlib", "2.2.0") >= 0: self.fig = Figure(constrained_layout=True) else: self.fig = Figure() self.canvas = FigureCanvas(self.fig) self.canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) # Needed for mouse modifiers (x,y, <CTRL>, ...): # Key press events in general are not processed unless you # "activate the focus of Qt onto your mpl canvas" # http://stackoverflow.com/questions/22043549/matplotlib-and-qt-mouse-press-event-key-is-always-none self.canvas.setFocusPolicy( QtCore.Qt.ClickFocus ) self.canvas.setFocus() self.canvas.updateGeometry() # Create a custom navigation toolbar, tied to the canvas and # initialize toolbar settings # self.mplToolbar = MplToolbar(self.canvas, self) self.mplToolbar.zoom_locked = False self.mplToolbar.cursor_enabled = False #self.mplToolbar.enable_plot(state = True) self.mplToolbar.sig_tx.connect(self.process_signals) layHToolbar = QHBoxLayout() layHToolbar.addWidget(self.mplToolbar, 1, QtCore.Qt.AlignLeft) layHToolbar.addStretch(1) #============================================= # Main plot widget layout #============================================= self.layVMainMpl = QVBoxLayout() self.layVMainMpl.addLayout(layHToolbar) self.layVMainMpl.addWidget(self.canvas) self.setLayout(self.layVMainMpl)
class MplWidget(QWidget): """ Construct a subwidget consisting of a Matplotlib canvas and a subclassed NavigationToolbar. """ def __init__(self, parent): super(MplWidget, self).__init__(parent) # Create the mpl figure and subplot (white bg, 100 dots-per-inch). # Construct the canvas with the figure: self.plt_lim = [] # define variable for x,y plot limits if cmp_version("matplotlib", "2.2.0") >= 0: self.fig = Figure(constrained_layout=True) else: self.fig = Figure() self.canvas = FigureCanvas(self.fig) self.canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) # Needed for mouse modifiers (x,y, <CTRL>, ...): # Key press events in general are not processed unless you # "activate the focus of Qt onto your mpl canvas" # http://stackoverflow.com/questions/22043549/matplotlib-and-qt-mouse-press-event-key-is-always-none self.canvas.setFocusPolicy( QtCore.Qt.ClickFocus ) self.canvas.setFocus() self.canvas.updateGeometry() # Create a custom navigation toolbar, tied to the canvas and # initialize toolbar settings # self.mplToolbar = MplToolbar(self.canvas, self) self.mplToolbar.zoom_locked = False self.mplToolbar.cursor_enabled = False #self.mplToolbar.enable_plot(state = True) self.mplToolbar.sig_tx.connect(self.process_signals) layHToolbar = QHBoxLayout() layHToolbar.addWidget(self.mplToolbar, 1, QtCore.Qt.AlignLeft) layHToolbar.addStretch(1) #============================================= # Main plot widget layout #============================================= self.layVMainMpl = QVBoxLayout() self.layVMainMpl.addLayout(layHToolbar) self.layVMainMpl.addWidget(self.canvas) self.setLayout(self.layVMainMpl) #------------------------------------------------------------------------------ @pyqtSlot(object) def process_signals(self, dict_sig): """ Process sig """ # if 'enabled' in dict_sig: # self.clear_disabled_figure(dict_sig['enabled']) # else: pass #------------------------------------------------------------------------------ def save_limits(self): """ Save x- and y-limits of all axes in self.limits when zoom is unlocked """ if not self.mplToolbar.zoom_locked: for ax in self.fig.axes: self.limits = ax.axis() # save old limits #------------------------------------------------------------------------------ def redraw(self): """ Redraw the figure with new properties (grid, linewidth) """ # only execute when at least one axis exists -> tight_layout crashes otherwise if self.fig.axes: self.mplToolbar.cycle_draw_grid(cycle=False, axes=self.fig.axes) for ax in self.fig.axes: if self.mplToolbar.zoom_locked: ax.axis(self.limits) # restore old limits else: self.limits = ax.axis() # save old limits # try: # # tight_layout() crashes with small figure sizes # self.fig.tight_layout(pad = 0.1) # except(ValueError, np.linalg.linalg.LinAlgError): # logger.debug("error in tight_layout") self.canvas.draw() # now (re-)draw the figure #------------------------------------------------------------------------------ # def clear_disabled_figure(self, enabled): # """ # Clear the figure when it is disabled in the mplToolbar # """ # if not enabled: # self.fig.clf() # self.pltCanv.draw() # else: # self.redraw() #------------------------------------------------------------------------------ def plt_full_view(self): """ Zoom to full extent of data if axes is set to "navigationable" by the navigation toolbar """ #Add current view limits to view history to enable "back to previous view" self.mplToolbar.push_current() for ax in self.fig.axes: if ax.get_navigate(): ax.autoscale() self.redraw() #------------------------------------------------------------------------------ def get_full_extent(self, ax, pad=0.0): """ Get the full extent of axes system `ax`, including axes labels, tick labels and titles. Needed for inset plot in H(f) """ #http://stackoverflow.com/questions/14712665/matplotlib-subplot-background-axes-face-labels-colour-or-figure-axes-coor # For text objects, we need to draw the figure first, otherwise the extents # are undefined. self.canvas.draw() items = ax.get_xticklabels() + ax.get_yticklabels() items += [ax, ax.title, ax.xaxis.label, ax.yaxis.label] bbox = Bbox.union([item.get_window_extent() for item in items]) return bbox.expanded(1.0 + pad, 1.0 + pad) #------------------------------------------------------------------------------ def toggle_cursor(self): """ Toggle the tracking cursor """ if MPL_CURS: self.mplToolbar.cursor_enabled = not self.mplToolbar.cursor_enabled if self.mplToolbar.cursor_enabled: if hasattr(self, "cursors"): # dangling references to old cursors? for i in range(len(self.cursors)): self.cursors[i].remove() # yes, remove them! self.cursors = [] for ax in self.fig.axes: if ax.__class__.__name__ in {"AxesSubplot", "Axes3DSubplot"}: self.cursors.append(mplcursors.cursor(ax, hover=True)) else: for i in range(len(self.cursors)): self.cursors[i].remove()