summaryrefslogtreecommitdiff
path: root/silx/gui/plot/PlotWindow.py
diff options
context:
space:
mode:
Diffstat (limited to 'silx/gui/plot/PlotWindow.py')
-rw-r--r--silx/gui/plot/PlotWindow.py181
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)