diff options
author | Picca Frédéric-Emmanuel <picca@synchrotron-soleil.fr> | 2018-07-31 16:22:25 +0200 |
---|---|---|
committer | Picca Frédéric-Emmanuel <picca@synchrotron-soleil.fr> | 2018-07-31 16:22:25 +0200 |
commit | 159ef14fb9e198bb0066ea14e6b980f065de63dd (patch) | |
tree | bc37c7d4ba09ee59deb708897fa0571709aec293 /silx/gui/plot/PlotWindow.py | |
parent | 270d5ddc31c26b62379e3caa9044dd75ccc71847 (diff) |
New upstream version 0.8.0+dfsg
Diffstat (limited to 'silx/gui/plot/PlotWindow.py')
-rw-r--r-- | silx/gui/plot/PlotWindow.py | 181 |
1 files changed, 143 insertions, 38 deletions
diff --git a/silx/gui/plot/PlotWindow.py b/silx/gui/plot/PlotWindow.py index 5c7e661..459ffdc 100644 --- a/silx/gui/plot/PlotWindow.py +++ b/silx/gui/plot/PlotWindow.py @@ -1,7 +1,7 @@ # coding: utf-8 # /*########################################################################## # -# Copyright (c) 2004-2017 European Synchrotron Radiation Facility +# Copyright (c) 2004-2018 European Synchrotron Radiation Facility # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -29,11 +29,14 @@ The :class:`PlotWindow` is a subclass of :class:`.PlotWidget`. __authors__ = ["V.A. Sole", "T. Vincent"] __license__ = "MIT" -__date__ = "15/02/2018" +__date__ = "05/06/2018" import collections import logging +import weakref +import silx +from silx.utils.weakref import WeakMethodProxy from silx.utils.deprecation import deprecated from . import PlotWidget @@ -44,11 +47,12 @@ from .actions import fit as actions_fit from .actions import control as actions_control from .actions import histogram as actions_histogram from . import PlotToolButtons -from .PlotTools import PositionInfo +from . import tools from .Profile import ProfileToolBar from .LegendSelector import LegendsDockWidget from .CurvesROIWidget import CurvesROIDockWidget from .MaskToolsWidget import MaskToolsDockWidget +from .StatsWidget import BasicStatsWidget from .ColorBar import ColorBarWidget try: from ..console import IPythonDockWidget @@ -90,7 +94,7 @@ class PlotWindow(PlotWidget): (Default: False). It also supports a list of (name, funct(x, y)->value) to customize the displayed values. - See :class:`silx.gui.plot.PlotTools.PositionInfo`. + See :class:`~silx.gui.plot.tools.PositionInfo`. :param bool roi: Toggle visibilty of ROI action. :param bool mask: Toggle visibilty of mask action. :param bool fit: Toggle visibilty of fit action. @@ -114,6 +118,7 @@ class PlotWindow(PlotWidget): self._curvesROIDockWidget = None self._maskToolsDockWidget = None self._consoleDockWidget = None + self._statsWidget = None # Create color bar, hidden by default for backward compatibility self._colorbar = ColorBarWidget(parent=self, plot=self) @@ -122,11 +127,6 @@ class PlotWindow(PlotWidget): self.group = qt.QActionGroup(self) self.group.setExclusive(False) - self.zoomModeAction = self.group.addAction( - actions.mode.ZoomModeAction(self)) - self.panModeAction = self.group.addAction( - actions.mode.PanModeAction(self)) - self.resetZoomAction = self.group.addAction( actions.control.ResetZoomAction(self)) self.resetZoomAction.setVisible(resetzoom) @@ -205,28 +205,13 @@ class PlotWindow(PlotWidget): actions_medfilt.MedianFilter1DAction(self)) self._medianFilter1DAction.setVisible(False) - self._separator = qt.QAction('separator', self) - self._separator.setSeparator(True) - self.group.addAction(self._separator) - - self.copyAction = self.group.addAction(actions.io.CopyAction(self)) - self.copyAction.setVisible(copy) - self.addAction(self.copyAction) - - self.saveAction = self.group.addAction(actions.io.SaveAction(self)) - self.saveAction.setVisible(save) - self.addAction(self.saveAction) - - self.printAction = self.group.addAction(actions.io.PrintAction(self)) - self.printAction.setVisible(print_) - self.addAction(self.printAction) - self.fitAction = self.group.addAction(actions_fit.FitAction(self)) self.fitAction.setVisible(fit) self.addAction(self.fitAction) # lazy loaded actions needed by the controlButton menu self._consoleAction = None + self._statsAction = None self._panWithArrowKeysAction = None self._crosshairAction = None @@ -244,10 +229,12 @@ class PlotWindow(PlotWidget): gridLayout.addWidget(self._colorbar, 0, 1) gridLayout.setRowStretch(0, 1) gridLayout.setColumnStretch(0, 1) - centralWidget = qt.QWidget() + centralWidget = qt.QWidget(self) centralWidget.setLayout(gridLayout) self.setCentralWidget(centralWidget) + self._positionWidget = None + if control or position: hbox = qt.QHBoxLayout() hbox.setContentsMargins(0, 0, 0, 0) @@ -270,22 +257,69 @@ class PlotWindow(PlotWidget): converters = position else: converters = None - self.positionWidget = PositionInfo( + self._positionWidget = tools.PositionInfo( plot=self, converters=converters) - self.positionWidget.autoSnapToActiveCurve = True + # Set a snapping mode that is consistent with legacy one + self._positionWidget.setSnappingMode( + tools.PositionInfo.SNAPPING_CROSSHAIR | + tools.PositionInfo.SNAPPING_ACTIVE_ONLY | + tools.PositionInfo.SNAPPING_SYMBOLS_ONLY | + tools.PositionInfo.SNAPPING_CURVE | + tools.PositionInfo.SNAPPING_SCATTER) - hbox.addWidget(self.positionWidget) + hbox.addWidget(self._positionWidget) hbox.addStretch(1) - bottomBar = qt.QWidget() + bottomBar = qt.QWidget(centralWidget) bottomBar.setLayout(hbox) gridLayout.addWidget(bottomBar, 1, 0, 1, -1) # Creating the toolbar also create actions for toolbuttons + self._interactiveModeToolBar = tools.InteractiveModeToolBar( + parent=self, plot=self) + self.addToolBar(self._interactiveModeToolBar) + self._toolbar = self._createToolBar(title='Plot', parent=None) self.addToolBar(self._toolbar) + self._outputToolBar = tools.OutputToolBar(parent=self, plot=self) + self._outputToolBar.getCopyAction().setVisible(copy) + self._outputToolBar.getSaveAction().setVisible(save) + self._outputToolBar.getPrintAction().setVisible(print_) + self.addToolBar(self._outputToolBar) + + # Activate shortcuts in PlotWindow widget: + for toolbar in (self._interactiveModeToolBar, self._outputToolBar): + for action in toolbar.actions(): + self.addAction(action) + + def getInteractiveModeToolBar(self): + """Returns QToolBar controlling interactive mode. + + :rtype: QToolBar + """ + return self._interactiveModeToolBar + + def getOutputToolBar(self): + """Returns QToolBar containing save, copy and print actions + + :rtype: QToolBar + """ + return self._outputToolBar + + @property + @deprecated(replacement="getPositionInfoWidget()", since_version="0.8.0") + def positionWidget(self): + return self.getPositionInfoWidget() + + def getPositionInfoWidget(self): + """Returns the widget displaying current cursor position information + + :rtype: ~silx.gui.plot.tools.PositionInfo + """ + return self._positionWidget + def getSelectionMask(self): """Return the current mask handled by :attr:`maskToolsDockWidget`. @@ -313,7 +347,7 @@ class PlotWindow(PlotWidget): show it or hide it.""" # create widget if needed (first call) if self._consoleDockWidget is None: - available_vars = {"plt": self} + available_vars = {"plt": weakref.proxy(self)} banner = "The variable 'plt' is available. Use the 'whos' " banner += "and 'help(plt)' commands for more information.\n\n" self._consoleDockWidget = IPythonDockWidget( @@ -327,6 +361,9 @@ class PlotWindow(PlotWidget): self._consoleDockWidget.setVisible(isChecked) + def _toggleStatsVisibility(self, isChecked=False): + self.getStatsWidget().parent().setVisible(isChecked) + def _createToolBar(self, title, parent): """Create a QToolBar from the QAction of the PlotWindow. @@ -355,8 +392,6 @@ class PlotWindow(PlotWidget): self.yAxisInvertedAction = toolbar.addWidget(obj) else: raise RuntimeError() - if obj is self.panModeAction: - toolbar.addSeparator() return toolbar def toolBar(self): @@ -381,6 +416,7 @@ class PlotWindow(PlotWidget): controlMenu.clear() controlMenu.addAction(self.getLegendsDockWidget().toggleViewAction()) controlMenu.addAction(self.getRoiAction()) + controlMenu.addAction(self.getStatsAction()) controlMenu.addAction(self.getMaskAction()) controlMenu.addAction(self.getConsoleAction()) @@ -474,8 +510,35 @@ class PlotWindow(PlotWidget): self.addTabbedDockWidget(self._maskToolsDockWidget) return self._maskToolsDockWidget + def getStatsWidget(self): + """Returns a BasicStatsWidget connected to this plot + + :rtype: BasicStatsWidget + """ + if self._statsWidget is None: + dockWidget = qt.QDockWidget(parent=self) + dockWidget.setWindowTitle("Curves stats") + dockWidget.layout().setContentsMargins(0, 0, 0, 0) + self._statsWidget = BasicStatsWidget(parent=self, plot=self) + dockWidget.setWidget(self._statsWidget) + dockWidget.hide() + self.addTabbedDockWidget(dockWidget) + return self._statsWidget + # getters for actions @property + @deprecated(replacement="getInteractiveModeToolBar().getZoomModeAction()", + since_version="0.8.0") + def zoomModeAction(self): + return self.getInteractiveModeToolBar().getZoomModeAction() + + @property + @deprecated(replacement="getInteractiveModeToolBar().getPanModeAction()", + since_version="0.8.0") + def panModeAction(self): + return self.getInteractiveModeToolBar().getPanModeAction() + + @property @deprecated(replacement="getConsoleAction()", since_version="0.4.0") def consoleAction(self): return self.getConsoleAction() @@ -545,6 +608,14 @@ class PlotWindow(PlotWidget): def roiAction(self): return self.getRoiAction() + def getStatsAction(self): + if self._statsAction is None: + self._statsAction = qt.QAction('Curves stats', self) + self._statsAction.setCheckable(True) + self._statsAction.setChecked(self.getStatsWidget().parent().isVisible()) + self._statsAction.toggled.connect(self._toggleStatsVisibility) + return self._statsAction + def getRoiAction(self): """QAction toggling curve ROI dock widget @@ -667,21 +738,21 @@ class PlotWindow(PlotWidget): :rtype: actions.PlotAction """ - return self.copyAction + return self.getOutputToolBar().getCopyAction() def getSaveAction(self): """Action to save plot :rtype: actions.PlotAction """ - return self.saveAction + return self.getOutputToolBar().getSaveAction() def getPrintAction(self): """Action to print plot :rtype: actions.PlotAction """ - return self.printAction + return self.getOutputToolBar().getPrintAction() def getFitAction(self): """Action to fit selected curve @@ -757,7 +828,7 @@ class Plot2D(PlotWindow): posInfo = [ ('X', lambda x, y: x), ('Y', lambda x, y: y), - ('Data', self._getImageValue)] + ('Data', WeakMethodProxy(self._getImageValue))] super(Plot2D, self).__init__(parent=parent, backend=backend, resetzoom=True, autoScale=False, @@ -772,6 +843,9 @@ class Plot2D(PlotWindow): self.getXAxis().setLabel('Columns') self.getYAxis().setLabel('Rows') + if silx.config.DEFAULT_PLOT_IMAGE_Y_AXIS_ORIENTATION == 'downward': + self.getYAxis().setInverted(True) + self.profile = ProfileToolBar(plot=self) self.addToolBar(self.profile) @@ -780,10 +854,41 @@ class Plot2D(PlotWindow): # Put colorbar action after colormap action actions = self.toolBar().actions() - for index, action in enumerate(actions): + for action in actions: if action is self.getColormapAction(): break + self.sigActiveImageChanged.connect(self.__activeImageChanged) + + def __activeImageChanged(self, previous, legend): + """Handle change of active image + + :param Union[str,None] previous: Legend of previous active image + :param Union[str,None] legend: Legend of current active image + """ + if previous is not None: + item = self.getImage(previous) + if item is not None: + item.sigItemChanged.disconnect(self.__imageChanged) + + if legend is not None: + item = self.getImage(legend) + item.sigItemChanged.connect(self.__imageChanged) + + positionInfo = self.getPositionInfoWidget() + if positionInfo is not None: + positionInfo.updateInfo() + + def __imageChanged(self, event): + """Handle update of active image item + + :param event: Type of changed event + """ + if event == items.ItemChangedType.DATA: + positionInfo = self.getPositionInfoWidget() + if positionInfo is not None: + positionInfo.updateInfo() + def _getImageValue(self, x, y): """Get status bar value of top most image at position (x, y) |