diff options
Diffstat (limited to 'src/silx/gui/plot/actions/control.py')
-rwxr-xr-x | src/silx/gui/plot/actions/control.py | 324 |
1 files changed, 195 insertions, 129 deletions
diff --git a/src/silx/gui/plot/actions/control.py b/src/silx/gui/plot/actions/control.py index 439985e..c21d235 100755 --- a/src/silx/gui/plot/actions/control.py +++ b/src/silx/gui/plot/actions/control.py @@ -1,7 +1,6 @@ -# coding: utf-8 # /*########################################################################## # -# Copyright (c) 2004-2019 European Synchrotron Radiation Facility +# Copyright (c) 2004-2023 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 @@ -46,8 +45,6 @@ The following QAction are available: - :class:`ZoomOutAction` """ -from __future__ import division - __authors__ = ["V.A. Sole", "T. Vincent", "P. Knobel"] __license__ = "MIT" __date__ = "27/11/2020" @@ -58,6 +55,7 @@ from silx.gui.plot import items from silx.gui.plot._utils import applyZoomToPlot as _applyZoomToPlot from silx.gui import qt from silx.gui import icons +from silx.utils.deprecation import deprecated _logger = logging.getLogger(__name__) @@ -71,10 +69,14 @@ class ResetZoomAction(PlotAction): def __init__(self, plot, parent=None): super(ResetZoomAction, self).__init__( - plot, icon='zoom-original', text='Reset Zoom', - tooltip='Auto-scale the graph', + plot, + icon="zoom-original", + text="Reset Zoom", + tooltip="Auto-scale the graph", triggered=self._actionTriggered, - checkable=False, parent=parent) + checkable=False, + parent=parent, + ) self._autoscaleChanged(True) plot.getXAxis().sigAutoScaleChanged.connect(self._autoscaleChanged) plot.getYAxis().sigAutoScaleChanged.connect(self._autoscaleChanged) @@ -85,13 +87,13 @@ class ResetZoomAction(PlotAction): self.setEnabled(xAxis.isAutoScale() or yAxis.isAutoScale()) if xAxis.isAutoScale() and yAxis.isAutoScale(): - tooltip = 'Auto-scale the graph' + tooltip = "Auto-scale the graph" elif xAxis.isAutoScale(): # And not Y axis - tooltip = 'Auto-scale the x-axis of the graph only' + tooltip = "Auto-scale the x-axis of the graph only" elif yAxis.isAutoScale(): # And not X axis - tooltip = 'Auto-scale the y-axis of the graph only' + tooltip = "Auto-scale the y-axis of the graph only" else: # no axis in autoscale - tooltip = 'Auto-scale the graph' + tooltip = "Auto-scale the graph" self.setToolTip(tooltip) def _actionTriggered(self, checked=False): @@ -107,10 +109,14 @@ class ZoomBackAction(PlotAction): def __init__(self, plot, parent=None): super(ZoomBackAction, self).__init__( - plot, icon='zoom-back', text='Zoom Back', - tooltip='Zoom back the plot', + plot, + icon="zoom-back", + text="Zoom Back", + tooltip="Zoom back the plot", triggered=self._actionTriggered, - checkable=False, parent=parent) + checkable=False, + parent=parent, + ) self.setShortcutContext(qt.Qt.WidgetShortcut) def _actionTriggered(self, checked=False): @@ -126,10 +132,14 @@ class ZoomInAction(PlotAction): def __init__(self, plot, parent=None): super(ZoomInAction, self).__init__( - plot, icon='zoom-in', text='Zoom In', - tooltip='Zoom in the plot', + plot, + icon="zoom-in", + text="Zoom In", + tooltip="Zoom in the plot", triggered=self._actionTriggered, - checkable=False, parent=parent) + checkable=False, + parent=parent, + ) self.setShortcut(qt.QKeySequence.ZoomIn) self.setShortcutContext(qt.Qt.WidgetShortcut) @@ -146,15 +156,19 @@ class ZoomOutAction(PlotAction): def __init__(self, plot, parent=None): super(ZoomOutAction, self).__init__( - plot, icon='zoom-out', text='Zoom Out', - tooltip='Zoom out the plot', + plot, + icon="zoom-out", + text="Zoom Out", + tooltip="Zoom out the plot", triggered=self._actionTriggered, - checkable=False, parent=parent) + checkable=False, + parent=parent, + ) self.setShortcut(qt.QKeySequence.ZoomOut) self.setShortcutContext(qt.Qt.WidgetShortcut) def _actionTriggered(self, checked=False): - _applyZoomToPlot(self.plot, 1. / 1.1) + _applyZoomToPlot(self.plot, 1.0 / 1.1) class XAxisAutoScaleAction(PlotAction): @@ -166,11 +180,15 @@ class XAxisAutoScaleAction(PlotAction): def __init__(self, plot, parent=None): super(XAxisAutoScaleAction, self).__init__( - plot, icon='plot-xauto', text='X Autoscale', - tooltip='Enable x-axis auto-scale when checked.\n' - 'If unchecked, x-axis does not change when reseting zoom.', + plot, + icon="plot-xauto", + text="X Autoscale", + tooltip="Enable x-axis auto-scale when checked.\n" + "If unchecked, x-axis does not change when reseting zoom.", triggered=self._actionTriggered, - checkable=True, parent=parent) + checkable=True, + parent=parent, + ) self.setChecked(plot.getXAxis().isAutoScale()) plot.getXAxis().sigAutoScaleChanged.connect(self.setChecked) @@ -189,11 +207,15 @@ class YAxisAutoScaleAction(PlotAction): def __init__(self, plot, parent=None): super(YAxisAutoScaleAction, self).__init__( - plot, icon='plot-yauto', text='Y Autoscale', - tooltip='Enable y-axis auto-scale when checked.\n' - 'If unchecked, y-axis does not change when reseting zoom.', + plot, + icon="plot-yauto", + text="Y Autoscale", + tooltip="Enable y-axis auto-scale when checked.\n" + "If unchecked, y-axis does not change when reseting zoom.", triggered=self._actionTriggered, - checkable=True, parent=parent) + checkable=True, + parent=parent, + ) self.setChecked(plot.getYAxis().isAutoScale()) plot.getYAxis().sigAutoScaleChanged.connect(self.setChecked) @@ -212,10 +234,14 @@ class XAxisLogarithmicAction(PlotAction): def __init__(self, plot, parent=None): super(XAxisLogarithmicAction, self).__init__( - plot, icon='plot-xlog', text='X Log. scale', - tooltip='Logarithmic x-axis when checked', + plot, + icon="plot-xlog", + text="X Log. scale", + tooltip="Logarithmic x-axis when checked", triggered=self._actionTriggered, - checkable=True, parent=parent) + checkable=True, + parent=parent, + ) self.axis = plot.getXAxis() self.setChecked(self.axis.getScale() == self.axis.LOGARITHMIC) self.axis.sigScaleChanged.connect(self._setCheckedIfLogScale) @@ -237,10 +263,14 @@ class YAxisLogarithmicAction(PlotAction): def __init__(self, plot, parent=None): super(YAxisLogarithmicAction, self).__init__( - plot, icon='plot-ylog', text='Y Log. scale', - tooltip='Logarithmic y-axis when checked', + plot, + icon="plot-ylog", + text="Y Log. scale", + tooltip="Logarithmic y-axis when checked", triggered=self._actionTriggered, - checkable=True, parent=parent) + checkable=True, + parent=parent, + ) self.axis = plot.getYAxis() self.setChecked(self.axis.getScale() == self.axis.LOGARITHMIC) self.axis.sigScaleChanged.connect(self._setCheckedIfLogScale) @@ -262,21 +292,25 @@ class GridAction(PlotAction): :param parent: See :class:`QAction` """ - def __init__(self, plot, gridMode='both', parent=None): - assert gridMode in ('both', 'major') + def __init__(self, plot, gridMode="both", parent=None): + assert gridMode in ("both", "major") self._gridMode = gridMode super(GridAction, self).__init__( - plot, icon='plot-grid', text='Grid', - tooltip='Toggle grid (on/off)', + plot, + icon="plot-grid", + text="Grid", + tooltip="Toggle grid (on/off)", triggered=self._actionTriggered, - checkable=True, parent=parent) + checkable=True, + parent=parent, + ) self.setChecked(plot.getGraphGrid() is not None) plot.sigSetGraphGrid.connect(self._gridChanged) def _gridChanged(self, which): """Slot listening for PlotWidget grid mode change.""" - self.setChecked(which != 'None') + self.setChecked(which != "None") def _actionTriggered(self, checked=False): self.plot.setGraphGrid(self._gridMode if checked else None) @@ -294,14 +328,17 @@ class CurveStyleAction(PlotAction): def __init__(self, plot, parent=None): super(CurveStyleAction, self).__init__( - plot, icon='plot-toggle-points', text='Curve style', - tooltip='Change curve line and markers style', + plot, + icon="plot-toggle-points", + text="Curve style", + tooltip="Change curve line and markers style", triggered=self._actionTriggered, - checkable=False, parent=parent) + checkable=False, + parent=parent, + ) def _actionTriggered(self, checked=False): - currentState = (self.plot.isDefaultPlotLines(), - self.plot.isDefaultPlotPoints()) + currentState = (self.plot.isDefaultPlotLines(), self.plot.isDefaultPlotPoints()) if currentState == (False, False): newState = True, False @@ -326,21 +363,39 @@ class ColormapAction(PlotAction): def __init__(self, plot, parent=None): self._dialog = None # To store an instance of ColormapDialog super(ColormapAction, self).__init__( - plot, icon='colormap', text='Colormap', + plot, + icon="colormap", + text="Colormap", tooltip="Change colormap", triggered=self._actionTriggered, - checkable=True, parent=parent) + checkable=True, + parent=parent, + ) self.plot.sigActiveImageChanged.connect(self._updateColormap) self.plot.sigActiveScatterChanged.connect(self._updateColormap) - def setColorDialog(self, colorDialog): - """Set a specific color dialog instead of using the default dialog.""" - assert(colorDialog is not None) - assert(self._dialog is None) - self._dialog = colorDialog - self._dialog.visibleChanged.connect(self._dialogVisibleChanged) + def setColormapDialog(self, dialog): + """Set a specific colormap dialog instead of using the default one.""" + assert dialog is not None + if self._dialog is not None: + self._dialog.visibleChanged.disconnect(self._dialogVisibleChanged) + + self._dialog = dialog + self._dialog.visibleChanged.connect( + self._dialogVisibleChanged, qt.Qt.UniqueConnection + ) self.setChecked(self._dialog.isVisible()) + @deprecated(replacement="setColormapDialog", since_version="2.0") + def setColorDialog(self, colorDialog): + self.setColormapDialog(colorDialog) + + def getColormapDialog(self): + if self._dialog is None: + self._dialog = self._createDialog(self.plot) + self._dialog.visibleChanged.connect(self._dialogVisibleChanged) + return self._dialog + @staticmethod def _createDialog(parent): """Create the dialog if not already existing @@ -349,22 +404,20 @@ class ColormapAction(PlotAction): :rtype: ColormapDialog """ from silx.gui.dialog.ColormapDialog import ColormapDialog + dialog = ColormapDialog(parent=parent) dialog.setModal(False) return dialog def _actionTriggered(self, checked=False): """Create a cmap dialog and update active image and default cmap.""" - if self._dialog is None: - self._dialog = self._createDialog(self.plot) - self._dialog.visibleChanged.connect(self._dialogVisibleChanged) - + dialog = self.getColormapDialog() # Run the dialog listening to colormap change if checked is True: self._updateColormap() - self._dialog.show() + dialog.show() else: - self._dialog.hide() + dialog.hide() def _dialogVisibleChanged(self, isVisible): self.setChecked(isVisible) @@ -383,7 +436,7 @@ class ColormapAction(PlotAction): else: # No active image or active image is RGBA, # Check for active scatter plot - scatter = self.plot._getActiveItem(kind='scatter') + scatter = self.plot.getActiveScatter() if scatter is not None: colormap = scatter.getColormap() self._dialog.setItem(scatter) @@ -408,10 +461,14 @@ class ColorBarAction(PlotAction): def __init__(self, plot, parent=None): self._dialog = None # To store an instance of ColorBar super(ColorBarAction, self).__init__( - plot, icon='colorbar', text='Colorbar', + plot, + icon="colorbar", + text="Colorbar", tooltip="Show/Hide the colorbar", triggered=self._actionTriggered, - checkable=True, parent=parent) + checkable=True, + parent=parent, + ) colorBarWidget = self.plot.getColorBarWidget() old = self.blockSignals(True) self.setChecked(colorBarWidget.isVisibleTo(self.plot)) @@ -442,23 +499,24 @@ class KeepAspectRatioAction(PlotAction): def __init__(self, plot, parent=None): # Uses two images for checked/unchecked states self._states = { - False: (icons.getQIcon('shape-circle-solid'), - "Keep data aspect ratio"), - True: (icons.getQIcon('shape-ellipse-solid'), - "Do no keep data aspect ratio") + False: (icons.getQIcon("shape-circle-solid"), "Keep data aspect ratio"), + True: ( + icons.getQIcon("shape-ellipse-solid"), + "Do no keep data aspect ratio", + ), } icon, tooltip = self._states[plot.isKeepDataAspectRatio()] super(KeepAspectRatioAction, self).__init__( plot, icon=icon, - text='Toggle keep aspect ratio', + text="Toggle keep aspect ratio", tooltip=tooltip, triggered=self._actionTriggered, checkable=False, - parent=parent) - plot.sigSetKeepDataAspectRatio.connect( - self._keepDataAspectRatioChanged) + parent=parent, + ) + plot.sigSetKeepDataAspectRatio.connect(self._keepDataAspectRatioChanged) def _keepDataAspectRatioChanged(self, aspectRatio): """Handle Plot set keep aspect ratio signal""" @@ -481,21 +539,20 @@ class YAxisInvertedAction(PlotAction): def __init__(self, plot, parent=None): # Uses two images for checked/unchecked states self._states = { - False: (icons.getQIcon('plot-ydown'), - "Orient Y axis downward"), - True: (icons.getQIcon('plot-yup'), - "Orient Y axis upward"), + False: (icons.getQIcon("plot-ydown"), "Orient Y axis downward"), + True: (icons.getQIcon("plot-yup"), "Orient Y axis upward"), } icon, tooltip = self._states[plot.getYAxis().isInverted()] super(YAxisInvertedAction, self).__init__( plot, icon=icon, - text='Invert Y Axis', + text="Invert Y Axis", tooltip=tooltip, triggered=self._actionTriggered, checkable=False, - parent=parent) + parent=parent, + ) plot.getYAxis().sigInvertedChanged.connect(self._yAxisInvertedChanged) def _yAxisInvertedChanged(self, inverted): @@ -520,8 +577,7 @@ class CrosshairAction(PlotAction): :param parent: See :class:`QAction` """ - def __init__(self, plot, color='black', linewidth=1, linestyle='-', - parent=None): + def __init__(self, plot, color="black", linewidth=1, linestyle="-", parent=None): self.color = color """Color used to draw the crosshair (str).""" @@ -532,18 +588,24 @@ class CrosshairAction(PlotAction): """Style of line of the cursor (str).""" super(CrosshairAction, self).__init__( - plot, icon='crosshair', text='Crosshair Cursor', - tooltip='Enable crosshair cursor when checked', + plot, + icon="crosshair", + text="Crosshair Cursor", + tooltip="Enable crosshair cursor when checked", triggered=self._actionTriggered, - checkable=True, parent=parent) + checkable=True, + parent=parent, + ) self.setChecked(plot.getGraphCursor() is not None) plot.sigSetGraphCursor.connect(self.setChecked) def _actionTriggered(self, checked=False): - self.plot.setGraphCursor(checked, - color=self.color, - linestyle=self.linestyle, - linewidth=self.linewidth) + self.plot.setGraphCursor( + checked, + color=self.color, + linestyle=self.linestyle, + linewidth=self.linewidth, + ) class PanWithArrowKeysAction(PlotAction): @@ -554,12 +616,15 @@ class PanWithArrowKeysAction(PlotAction): """ def __init__(self, plot, parent=None): - super(PanWithArrowKeysAction, self).__init__( - plot, icon='arrow-keys', text='Pan with arrow keys', - tooltip='Enable pan with arrow keys when checked', + plot, + icon="arrow-keys", + text="Pan with arrow keys", + tooltip="Enable pan with arrow keys when checked", triggered=self._actionTriggered, - checkable=True, parent=parent) + checkable=True, + parent=parent, + ) self.setChecked(plot.isPanWithArrowKeys()) plot.sigSetPanWithArrowKeys.connect(self.setChecked) @@ -575,15 +640,17 @@ class ShowAxisAction(PlotAction): """ def __init__(self, plot, parent=None): - tooltip = 'Show plot axis when checked, otherwise hide them' - PlotAction.__init__(self, - plot, - icon='axis', - text='show axis', - tooltip=tooltip, - triggered=self._actionTriggered, - checkable=True, - parent=parent) + tooltip = "Show plot axis when checked, otherwise hide them" + PlotAction.__init__( + self, + plot, + icon="axis", + text="show axis", + tooltip=tooltip, + triggered=self._actionTriggered, + checkable=True, + parent=parent, + ) self.setChecked(self.plot.isAxesDisplayed()) plot._sigAxesVisibilityChanged.connect(self.setChecked) @@ -600,15 +667,17 @@ class ClosePolygonInteractionAction(PlotAction): """ def __init__(self, plot, parent=None): - tooltip = 'Close the current polygon drawn' - PlotAction.__init__(self, - plot, - icon='add-shape-polygon', - text='Close the polygon', - tooltip=tooltip, - triggered=self._actionTriggered, - checkable=True, - parent=parent) + tooltip = "Close the current polygon drawn" + PlotAction.__init__( + self, + plot, + icon="add-shape-polygon", + text="Close the polygon", + tooltip=tooltip, + triggered=self._actionTriggered, + checkable=True, + parent=parent, + ) self.plot.sigInteractiveModeChanged.connect(self._modeChanged) self._modeChanged(None) @@ -618,7 +687,7 @@ class ClosePolygonInteractionAction(PlotAction): self.setEnabled(enabled) def _actionTriggered(self, checked=False): - self.plot._eventHandler.validate() + self.plot.interaction()._validate() class OpenGLAction(PlotAction): @@ -633,29 +702,32 @@ class OpenGLAction(PlotAction): def __init__(self, plot, parent=None): # Uses two images for checked/unchecked states self._states = { - "opengl": (icons.getQIcon('backend-opengl'), - "OpenGL rendering (fast)\nClick to disable OpenGL"), - "matplotlib": (icons.getQIcon('backend-opengl'), - "Matplotlib rendering (safe)\nClick to enable OpenGL"), - "unknown": (icons.getQIcon('backend-opengl'), - "Custom rendering") + "opengl": ( + icons.getQIcon("backend-opengl"), + "OpenGL rendering (fast)\nClick to disable OpenGL", + ), + "matplotlib": ( + icons.getQIcon("backend-opengl"), + "Matplotlib rendering (safe)\nClick to enable OpenGL", + ), + "unknown": (icons.getQIcon("backend-opengl"), "Custom rendering"), } name = self._getBackendName(plot) - self.__state = name icon, tooltip = self._states[name] super(OpenGLAction, self).__init__( plot, icon=icon, - text='Enable/disable OpenGL rendering', + text="Enable/disable OpenGL rendering", tooltip=tooltip, triggered=self._actionTriggered, checkable=True, - parent=parent) + parent=parent, + ) + plot.sigBackendChanged.connect(self._backendUpdated) def _backendUpdated(self): name = self._getBackendName(self.plot) - self.__state = name icon, tooltip = self._states[name] self.setIcon(icon) self.setToolTip(tooltip) @@ -674,21 +746,15 @@ class OpenGLAction(PlotAction): def _actionTriggered(self, checked=False): plot = self.plot name = self._getBackendName(self.plot) - if self.__state != name: - # THere is no event to know the backend was updated - # So here we check if there is a mismatch between the displayed state - # and the real state of the widget - self._backendUpdated() - return if name != "opengl": from silx.gui.utils import glutils + result = glutils.isOpenGLAvailable() if not result: - qt.QMessageBox.critical(plot, "OpenGL rendering not available", result.error) - # Uncheck if needed - self._backendUpdated() + qt.QMessageBox.critical( + plot, "OpenGL rendering is not available", result.error + ) return plot.setBackend("opengl") else: plot.setBackend("matplotlib") - self._backendUpdated() |