diff options
Diffstat (limited to 'silx/gui/plot/PlotWindow.py')
-rw-r--r-- | silx/gui/plot/PlotWindow.py | 193 |
1 files changed, 126 insertions, 67 deletions
diff --git a/silx/gui/plot/PlotWindow.py b/silx/gui/plot/PlotWindow.py index ae25cfd..a23db04 100644 --- a/silx/gui/plot/PlotWindow.py +++ b/silx/gui/plot/PlotWindow.py @@ -25,26 +25,30 @@ """A :class:`.PlotWidget` with additional toolbars. The :class:`PlotWindow` is a subclass of :class:`.PlotWidget`. -It provides the plot API fully defined in :class:`.Plot`. """ __authors__ = ["V.A. Sole", "T. Vincent"] __license__ = "MIT" -__date__ = "27/04/2017" +__date__ = "17/08/2017" import collections import logging -from silx.utils.decorators import deprecated +from silx.utils.deprecation import deprecated from . import PlotWidget -from . import PlotActions +from . import actions +from . import items +from .actions import medfilt as actions_medfilt +from .actions import fit as actions_fit +from .actions import histogram as actions_histogram from . import PlotToolButtons from .PlotTools import PositionInfo from .Profile import ProfileToolBar from .LegendSelector import LegendsDockWidget from .CurvesROIWidget import CurvesROIDockWidget from .MaskToolsWidget import MaskToolsDockWidget +from .ColorBar import ColorBarWidget try: from ..console import IPythonDockWidget except ImportError: @@ -65,7 +69,7 @@ class PlotWindow(PlotWidget): :param parent: The parent of this widget or None. :param backend: The backend to use for the plot (default: matplotlib). - See :class:`.Plot` for the list of supported backend. + See :class:`.PlotWidget` for the list of supported backend. :type backend: str or :class:`BackendBase.BackendBase` :param bool resetzoom: Toggle visibility of reset zoom action. :param bool autoScale: Toggle visibility of axes autoscale actions. @@ -113,46 +117,54 @@ class PlotWindow(PlotWidget): self.group = qt.QActionGroup(self) self.group.setExclusive(False) - self.resetZoomAction = self.group.addAction(PlotActions.ResetZoomAction(self)) + 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) self.addAction(self.resetZoomAction) - self.zoomInAction = PlotActions.ZoomInAction(self) + self.zoomInAction = actions.control.ZoomInAction(self) self.addAction(self.zoomInAction) - self.zoomOutAction = PlotActions.ZoomOutAction(self) + self.zoomOutAction = actions.control.ZoomOutAction(self) self.addAction(self.zoomOutAction) self.xAxisAutoScaleAction = self.group.addAction( - PlotActions.XAxisAutoScaleAction(self)) + actions.control.XAxisAutoScaleAction(self)) self.xAxisAutoScaleAction.setVisible(autoScale) self.addAction(self.xAxisAutoScaleAction) self.yAxisAutoScaleAction = self.group.addAction( - PlotActions.YAxisAutoScaleAction(self)) + actions.control.YAxisAutoScaleAction(self)) self.yAxisAutoScaleAction.setVisible(autoScale) self.addAction(self.yAxisAutoScaleAction) self.xAxisLogarithmicAction = self.group.addAction( - PlotActions.XAxisLogarithmicAction(self)) + actions.control.XAxisLogarithmicAction(self)) self.xAxisLogarithmicAction.setVisible(logScale) self.addAction(self.xAxisLogarithmicAction) self.yAxisLogarithmicAction = self.group.addAction( - PlotActions.YAxisLogarithmicAction(self)) + actions.control.YAxisLogarithmicAction(self)) self.yAxisLogarithmicAction.setVisible(logScale) self.addAction(self.yAxisLogarithmicAction) self.gridAction = self.group.addAction( - PlotActions.GridAction(self, gridMode='both')) + actions.control.GridAction(self, gridMode='both')) self.gridAction.setVisible(grid) self.addAction(self.gridAction) - self.curveStyleAction = self.group.addAction(PlotActions.CurveStyleAction(self)) + self.curveStyleAction = self.group.addAction( + actions.control.CurveStyleAction(self)) self.curveStyleAction.setVisible(curveStyle) self.addAction(self.curveStyleAction) - self.colormapAction = self.group.addAction(PlotActions.ColormapAction(self)) + self.colormapAction = self.group.addAction( + actions.control.ColormapAction(self)) self.colormapAction.setVisible(colormap) self.addAction(self.colormapAction) @@ -171,34 +183,34 @@ class PlotWindow(PlotWidget): self.getMaskAction().setVisible(mask) self._intensityHistoAction = self.group.addAction( - PlotActions.PixelIntensitiesHistoAction(self)) + actions_histogram.PixelIntensitiesHistoAction(self)) self._intensityHistoAction.setVisible(False) self._medianFilter2DAction = self.group.addAction( - PlotActions.MedianFilter2DAction(self)) + actions_medfilt.MedianFilter2DAction(self)) self._medianFilter2DAction.setVisible(False) self._medianFilter1DAction = self.group.addAction( - PlotActions.MedianFilter1DAction(self)) + 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(PlotActions.CopyAction(self)) + self.copyAction = self.group.addAction(actions.io.CopyAction(self)) self.copyAction.setVisible(copy) self.addAction(self.copyAction) - self.saveAction = self.group.addAction(PlotActions.SaveAction(self)) + self.saveAction = self.group.addAction(actions.io.SaveAction(self)) self.saveAction.setVisible(save) self.addAction(self.saveAction) - self.printAction = self.group.addAction(PlotActions.PrintAction(self)) + self.printAction = self.group.addAction(actions.io.PrintAction(self)) self.printAction.setVisible(print_) self.addAction(self.printAction) - self.fitAction = self.group.addAction(PlotActions.FitAction(self)) + self.fitAction = self.group.addAction(actions_fit.FitAction(self)) self.fitAction.setVisible(fit) self.addAction(self.fitAction) @@ -207,6 +219,28 @@ class PlotWindow(PlotWidget): self._panWithArrowKeysAction = None self._crosshairAction = None + # Create color bar, hidden by default for backward compatibility + self._colorbar = ColorBarWidget(parent=self, plot=self) + self._colorbar.setVisible(False) + + # Make colorbar background white + self._colorbar.setAutoFillBackground(True) + palette = self._colorbar.palette() + palette.setColor(qt.QPalette.Background, qt.Qt.white) + palette.setColor(qt.QPalette.Window, qt.Qt.white) + self._colorbar.setPalette(palette) + + gridLayout = qt.QGridLayout() + gridLayout.setSpacing(0) + gridLayout.setContentsMargins(0, 0, 0, 0) + gridLayout.addWidget(self.getWidgetHandle(), 0, 0) + gridLayout.addWidget(self._colorbar, 0, 1) + gridLayout.setRowStretch(0, 1) + gridLayout.setColumnStretch(0, 1) + centralWidget = qt.QWidget() + centralWidget.setLayout(gridLayout) + self.setCentralWidget(centralWidget) + if control or position: hbox = qt.QHBoxLayout() hbox.setContentsMargins(0, 0, 0, 0) @@ -239,16 +273,7 @@ class PlotWindow(PlotWidget): bottomBar = qt.QWidget() bottomBar.setLayout(hbox) - layout = qt.QVBoxLayout() - layout.setSpacing(0) - layout.setContentsMargins(0, 0, 0, 0) - layout.addWidget(self.getWidgetHandle()) - layout.addWidget(bottomBar) - layout.setStretch(0, 1) - - centralWidget = qt.QWidget() - centralWidget.setLayout(layout) - self.setCentralWidget(centralWidget) + gridLayout.addWidget(bottomBar, 1, 0, 1, -1) # Creating the toolbar also create actions for toolbuttons self._toolbar = self._createToolBar(title='Plot', parent=None) @@ -322,6 +347,8 @@ class PlotWindow(PlotWidget): self.yAxisInvertedAction = toolbar.addWidget(obj) else: raise RuntimeError() + if obj is self.panModeAction: + toolbar.addSeparator() return toolbar def toolBar(self): @@ -378,6 +405,13 @@ class PlotWindow(PlotWidget): self.tabifyDockWidget(self._dockWidgets[0], dock_widget) + def getColorBarWidget(self): + """Returns the embedded :class:`ColorBarWidget` widget. + + :rtype: ColorBarWidget + """ + return self._colorbar + # getters for dock widgets @property @deprecated(replacement="getLegendsDockWidget()", since_version="0.4.0") @@ -464,10 +498,10 @@ class PlotWindow(PlotWidget): def getCrosshairAction(self): """Action toggling crosshair cursor mode. - :rtype: PlotActions.PlotAction + :rtype: actions.PlotAction """ if self._crosshairAction is None: - self._crosshairAction = PlotActions.CrosshairAction(self, color='red') + self._crosshairAction = actions.control.CrosshairAction(self, color='red') return self._crosshairAction @property @@ -491,10 +525,10 @@ class PlotWindow(PlotWidget): def getPanWithArrowKeysAction(self): """Action toggling pan with arrow keys. - :rtype: PlotActions.PlotAction + :rtype: actions.PlotAction """ if self._panWithArrowKeysAction is None: - self._panWithArrowKeysAction = PlotActions.PanWithArrowKeysAction(self) + self._panWithArrowKeysAction = actions.control.PanWithArrowKeysAction(self) return self._panWithArrowKeysAction @property @@ -512,63 +546,63 @@ class PlotWindow(PlotWidget): def getResetZoomAction(self): """Action resetting the zoom - :rtype: PlotActions.PlotAction + :rtype: actions.PlotAction """ return self.resetZoomAction def getZoomInAction(self): """Action to zoom in - :rtype: PlotActions.PlotAction + :rtype: actions.PlotAction """ return self.zoomInAction def getZoomOutAction(self): """Action to zoom out - :rtype: PlotActions.PlotAction + :rtype: actions.PlotAction """ return self.zoomOutAction def getXAxisAutoScaleAction(self): """Action to toggle the X axis autoscale on zoom reset - :rtype: PlotActions.PlotAction + :rtype: actions.PlotAction """ return self.xAxisAutoScaleAction def getYAxisAutoScaleAction(self): """Action to toggle the Y axis autoscale on zoom reset - :rtype: PlotActions.PlotAction + :rtype: actions.PlotAction """ return self.yAxisAutoScaleAction def getXAxisLogarithmicAction(self): """Action to toggle logarithmic X axis - :rtype: PlotActions.PlotAction + :rtype: actions.PlotAction """ return self.xAxisLogarithmicAction def getYAxisLogarithmicAction(self): """Action to toggle logarithmic Y axis - :rtype: PlotActions.PlotAction + :rtype: actions.PlotAction """ return self.yAxisLogarithmicAction def getGridAction(self): """Action to toggle the grid visibility in the plot - :rtype: PlotActions.PlotAction + :rtype: actions.PlotAction """ return self.gridAction def getCurveStyleAction(self): """Action to change curve line and markers styles - :rtype: PlotActions.PlotAction + :rtype: actions.PlotAction """ return self.curveStyleAction @@ -576,7 +610,7 @@ class PlotWindow(PlotWidget): """Action open a colormap dialog to change active image and default colormap. - :rtype: PlotActions.PlotAction + :rtype: actions.PlotAction """ return self.colormapAction @@ -592,7 +626,7 @@ class PlotWindow(PlotWidget): Use this to change the visibility of keepDataAspectRatioButton in the toolbar (See :meth:`QToolBar.addWidget` documentation). - :rtype: PlotActions.PlotAction + :rtype: actions.PlotAction """ return self.keepDataAspectRatioButton @@ -608,56 +642,56 @@ class PlotWindow(PlotWidget): Use this to change the visibility yAxisInvertedButton in the toolbar. (See :meth:`QToolBar.addWidget` documentation). - :rtype: PlotActions.PlotAction + :rtype: actions.PlotAction """ return self.yAxisInvertedAction def getIntensityHistogramAction(self): """Action toggling the histogram intensity Plot widget - :rtype: PlotActions.PlotAction + :rtype: actions.PlotAction """ return self._intensityHistoAction def getCopyAction(self): """Action to copy plot snapshot to clipboard - :rtype: PlotActions.PlotAction + :rtype: actions.PlotAction """ return self.copyAction def getSaveAction(self): """Action to save plot - :rtype: PlotActions.PlotAction + :rtype: actions.PlotAction """ return self.saveAction def getPrintAction(self): """Action to print plot - :rtype: PlotActions.PlotAction + :rtype: actions.PlotAction """ return self.printAction def getFitAction(self): """Action to fit selected curve - :rtype: PlotActions.PlotAction + :rtype: actions.PlotAction """ return self.fitAction def getMedianFilter1DAction(self): """Action toggling the 1D median filter - :rtype: PlotActions.PlotAction + :rtype: actions.PlotAction """ return self._medianFilter1DAction def getMedianFilter2DAction(self): """Action toggling the 2D median filter - :rtype: PlotActions.PlotAction + :rtype: actions.PlotAction """ return self._medianFilter2DAction @@ -669,7 +703,7 @@ class Plot1D(PlotWindow): :param parent: The parent of this widget :param backend: The backend to use for the plot (default: matplotlib). - See :class:`.Plot` for the list of supported backend. + See :class:`.PlotWidget` for the list of supported backend. :type backend: str or :class:`BackendBase.BackendBase` """ @@ -684,8 +718,8 @@ class Plot1D(PlotWindow): roi=True, mask=False, fit=True) if parent is None: self.setWindowTitle('Plot1D') - self.setGraphXLabel('X') - self.setGraphYLabel('Y') + self.getXAxis().setLabel('X') + self.getYAxis().setLabel('Y') class Plot2D(PlotWindow): @@ -695,7 +729,7 @@ class Plot2D(PlotWindow): :param parent: The parent of this widget :param backend: The backend to use for the plot (default: matplotlib). - See :class:`.Plot` for the list of supported backend. + See :class:`.PlotWidget` for the list of supported backend. :type backend: str or :class:`BackendBase.BackendBase` """ @@ -716,26 +750,44 @@ class Plot2D(PlotWindow): roi=False, mask=True) if parent is None: self.setWindowTitle('Plot2D') - self.setGraphXLabel('Columns') - self.setGraphYLabel('Rows') + self.getXAxis().setLabel('Columns') + self.getYAxis().setLabel('Rows') self.profile = ProfileToolBar(plot=self) - self.addToolBar(self.profile) + self.getColorBarWidget().setVisible(True) + + # Put colorbar action after colormap action + actions = self.toolBar().actions() + for index, action in enumerate(actions): + if action is self.getColormapAction(): + break + self.toolBar().insertAction( + actions[index + 1], + self.getColorBarWidget().getToggleViewAction()) + def _getImageValue(self, x, y): - """Get value of top most image at position (x, y) + """Get status bar value of top most image at position (x, y) :param float x: X position in plot coordinates :param float y: Y position in plot coordinates :return: The value at that point or '-' """ value = '-' - valueZ = - float('inf') + valueZ = -float('inf') + mask = 0 + maskZ = -float('inf') for image in self.getAllImages(): data = image.getData(copy=False) - if image.getZValue() >= valueZ: # This image is over the previous one + isMask = isinstance(image, items.MaskImageData) + if isMask: + zIndex = maskZ + else: + zIndex = valueZ + if image.getZValue() >= zIndex: + # This image is over the previous one ox, oy = image.getOrigin() sx, sy = image.getScale() row, col = (y - oy) / sy, (x - ox) / sx @@ -743,8 +795,15 @@ class Plot2D(PlotWindow): # Test positive before cast otherwise issue with int(-0.5) = 0 row, col = int(row), int(col) if (row < data.shape[0] and col < data.shape[1]): - value = data[row, col] - valueZ = image.getZValue() + v, z = data[row, col], image.getZValue() + if not isMask: + value = v + valueZ = z + else: + mask = v + maskZ = z + if maskZ > valueZ and mask > 0: + return value, "Masked" return value def getProfileToolbar(self): |