summaryrefslogtreecommitdiff
path: root/silx/gui/plot/PlotWidget.py
diff options
context:
space:
mode:
Diffstat (limited to 'silx/gui/plot/PlotWidget.py')
-rw-r--r--silx/gui/plot/PlotWidget.py110
1 files changed, 83 insertions, 27 deletions
diff --git a/silx/gui/plot/PlotWidget.py b/silx/gui/plot/PlotWidget.py
index 3641b8c..2f7132c 100644
--- a/silx/gui/plot/PlotWidget.py
+++ b/silx/gui/plot/PlotWidget.py
@@ -31,37 +31,43 @@ from __future__ import division
__authors__ = ["V.A. Sole", "T. Vincent"]
__license__ = "MIT"
-__date__ = "18/10/2017"
+__date__ = "14/06/2018"
from collections import OrderedDict, namedtuple
from contextlib import contextmanager
+import datetime as dt
import itertools
import logging
import numpy
+import silx
+from silx.utils.weakref import WeakMethodProxy
+from silx.utils import deprecation
+from silx.utils.property import classproperty
from silx.utils.deprecation import deprecated
# Import matplotlib backend here to init matplotlib our way
from .backends.BackendMatplotlib import BackendMatplotlibQt
-from .Colormap import Colormap
-from . import Colors
+from ..colors import Colormap
+from .. import colors
from . import PlotInteraction
from . import PlotEvents
from .LimitsHistory import LimitsHistory
from . import _utils
from . import items
+from .items.axis import TickMode
from .. import qt
from ._utils.panzoom import ViewConstraints
-
+from ...gui.plot._utils.dtime_ticklayout import timestamp
_logger = logging.getLogger(__name__)
-_COLORDICT = Colors.COLORDICT
+_COLORDICT = colors.COLORDICT
_COLORLIST = [_COLORDICT['black'],
_COLORDICT['blue'],
_COLORDICT['red'],
@@ -110,8 +116,12 @@ class PlotWidget(qt.QMainWindow):
:type backend: str or :class:`BackendBase.BackendBase`
"""
- DEFAULT_BACKEND = 'matplotlib'
- """Class attribute setting the default backend for all instances."""
+ # TODO: Can be removed for silx 0.10
+ @classproperty
+ @deprecation.deprecated(replacement="silx.config.DEFAULT_PLOT_BACKEND", since_version="0.8", skip_backtrace_count=2)
+ def DEFAULT_BACKEND(self):
+ """Class attribute setting the default backend for all instances."""
+ return silx.config.DEFAULT_PLOT_BACKEND
colorList = _COLORLIST
colorDict = _COLORDICT
@@ -209,7 +219,7 @@ class PlotWidget(qt.QMainWindow):
self.setWindowTitle('PlotWidget')
if backend is None:
- backend = self.DEFAULT_BACKEND
+ backend = silx.config.DEFAULT_PLOT_BACKEND
if hasattr(backend, "__call__"):
self._backend = backend(self, parent)
@@ -296,7 +306,9 @@ class PlotWidget(qt.QMainWindow):
self.setGraphYLimits(0., 100., axis='right')
self.setGraphYLimits(0., 100., axis='left')
+ # TODO: Can be removed for silx 0.10
@staticmethod
+ @deprecation.deprecated(replacement="silx.config.DEFAULT_PLOT_BACKEND", since_version="0.8", skip_backtrace_count=2)
def setDefaultBackend(backend):
"""Set system wide default plot backend.
@@ -306,7 +318,7 @@ class PlotWidget(qt.QMainWindow):
'matplotlib' (default), 'mpl', 'opengl', 'gl', 'none'
or a :class:`BackendBase.BackendBase` class
"""
- PlotWidget.DEFAULT_BACKEND = backend
+ silx.config.DEFAULT_PLOT_BACKEND = backend
def _getDirtyPlot(self):
"""Return the plot dirty flag.
@@ -525,7 +537,9 @@ class PlotWidget(qt.QMainWindow):
:param numpy.ndarray x: The data corresponding to the x coordinates.
If you attempt to plot an histogram you can set edges values in x.
- In this case len(x) = len(y) + 1
+ In this case len(x) = len(y) + 1.
+ If x contains datetime objects the XAxis tickMode is set to
+ TickMode.TIME_SERIES.
:param numpy.ndarray y: The data corresponding to the y coordinates
:param str legend: The legend to be associated to the curve (or None)
:param info: User-defined information associated to the curve
@@ -533,7 +547,7 @@ class PlotWidget(qt.QMainWindow):
curves
:param color: color(s) to be used
:type color: str ("#RRGGBB") or (npoints, 4) unsigned byte array or
- one of the predefined color names defined in Colors.py
+ one of the predefined color names defined in colors.py
:param str symbol: Symbol to be drawn at each (x, y) position::
- 'o' circle
@@ -686,6 +700,13 @@ class PlotWidget(qt.QMainWindow):
if yerror is None:
yerror = curve.getYErrorData(copy=False)
+ # Convert x to timestamps so that the internal representation
+ # remains floating points. The user is expected to set the axis'
+ # tickMode to TickMode.TIME_SERIES and, if necessary, set the axis
+ # to the correct time zone.
+ if len(x) > 0 and isinstance(x[0], dt.datetime):
+ x = [timestamp(d) for d in x]
+
curve.setData(x, y, xerror, yerror, copy=copy)
if replace: # Then remove all other curves
@@ -739,7 +760,7 @@ class PlotWidget(qt.QMainWindow):
The legend to be associated to the histogram (or None)
:param color: color to be used
:type color: str ("#RRGGBB") or RGB unsigned byte array or
- one of the predefined color names defined in Colors.py
+ one of the predefined color names defined in colors.py
:param bool fill: True to fill the curve, False otherwise (default).
:param str align:
In case histogram values and edges have the same length N,
@@ -785,7 +806,7 @@ class PlotWidget(qt.QMainWindow):
return legend
def addImage(self, data, legend=None, info=None,
- replace=True, replot=None,
+ replace=False, replot=None,
xScale=None, yScale=None, z=None,
selectable=None, draggable=None,
colormap=None, pixmap=None,
@@ -811,7 +832,8 @@ class PlotWidget(qt.QMainWindow):
Note: boolean values are converted to int8.
:param str legend: The legend to be associated to the image (or None)
:param info: User-defined information associated to the image
- :param bool replace: True (default) to delete already existing images
+ :param bool replace:
+ True to delete already existing images (Default: False).
:param int z: Layer on which to draw the image (default: 0)
This allows to control the overlay.
:param bool selectable: Indicate if the image can be selected.
@@ -821,7 +843,7 @@ class PlotWidget(qt.QMainWindow):
:param colormap: Description of the :class:`.Colormap` to use
(or None).
This is ignored if data is a RGB(A) image.
- :type colormap: Union[silx.gui.plot.Colormap.Colormap, dict]
+ :type colormap: Union[silx.gui.colors.Colormap, dict]
:param pixmap: Pixmap representation of the data (if any)
:type pixmap: (nrows, ncolumns, RGBA) ubyte array or None (default)
:param str xlabel: X axis label to show when this curve is active,
@@ -964,7 +986,7 @@ class PlotWidget(qt.QMainWindow):
:param numpy.ndarray y: The data corresponding to the y coordinates
:param numpy.ndarray value: The data value associated with each point
:param str legend: The legend to be associated to the scatter (or None)
- :param silx.gui.plot.Colormap.Colormap colormap:
+ :param silx.gui.colors.Colormap colormap:
The :class:`.Colormap`. to be used for the scatter (or None)
:param info: User-defined information associated to the curve
:param str symbol: Symbol to be drawn at each (x, y) position::
@@ -1477,7 +1499,7 @@ class PlotWidget(qt.QMainWindow):
:param bool flag: Toggle the display of a crosshair cursor.
The crosshair cursor is hidden by default.
:param color: The color to use for the crosshair.
- :type color: A string (either a predefined color name in Colors.py
+ :type color: A string (either a predefined color name in colors.py
or "#RRGGBB")) or a 4 columns unsigned byte array
(Default: black).
:param int linewidth: The width of the lines of the crosshair
@@ -2264,13 +2286,13 @@ class PlotWidget(qt.QMainWindow):
It only affects future calls to :meth:`addImage` without the colormap
parameter.
- :param silx.gui.plot.Colormap.Colormap colormap:
+ :param silx.gui.colors.Colormap colormap:
The description of the default colormap, or
None to set the :class:`.Colormap` to a linear
autoscale gray colormap.
"""
if colormap is None:
- colormap = Colormap(name='gray',
+ colormap = Colormap(name=silx.config.DEFAULT_COLORMAP_NAME,
normalization='linear',
vmin=None,
vmax=None)
@@ -2370,10 +2392,10 @@ class PlotWidget(qt.QMainWindow):
to handle the graph events
If None (default), use a default listener.
"""
- # TODO allow multiple listeners, keep a weakref on it
+ # TODO allow multiple listeners
# allow register listener by event type
if callbackFunction is None:
- callbackFunction = self.graphCallback
+ callbackFunction = WeakMethodProxy(self.graphCallback)
self._callback = callbackFunction
def graphCallback(self, ddict=None):
@@ -2392,6 +2414,8 @@ class PlotWidget(qt.QMainWindow):
if ddict['button'] == "left":
self.setActiveCurve(ddict['label'])
qt.QToolTip.showText(self.cursor().pos(), ddict['label'])
+ elif ddict['event'] == 'mouseClicked' and ddict['button'] == 'left':
+ self.setActiveCurve(None)
def saveGraph(self, filename, fileFormat=None, dpi=None, **kw):
"""Save a snapshot of the plot.
@@ -2519,9 +2543,8 @@ class PlotWidget(qt.QMainWindow):
# Compute bbox wth figure aspect ratio
plotWidth, plotHeight = self.getPlotBoundsInPixels()[2:]
- plotRatio = plotHeight / plotWidth
-
- if plotRatio > 0.:
+ if plotWidth > 0 and plotHeight > 0:
+ plotRatio = plotHeight / plotWidth
dataRatio = (ymax - ymin) / (xmax - xmin)
if dataRatio < plotRatio:
# Increase y range
@@ -2741,6 +2764,39 @@ class PlotWidget(qt.QMainWindow):
return None
+ def _pick(self, x, y):
+ """Pick items in the plot at given position.
+
+ :param float x: X position in pixels
+ :param float y: Y position in pixels
+ :return: Iterable of (plot item, indices) at picked position.
+ Items are ordered from back to front.
+ """
+ items = []
+
+ # Convert backend result to plot items
+ for itemInfo in self._backend.pickItems(
+ x, y, kinds=('marker', 'curve', 'image')):
+ kind, legend = itemInfo['kind'], itemInfo['legend']
+
+ if kind in ('marker', 'image'):
+ item = self._getItem(kind=kind, legend=legend)
+ indices = None # TODO compute indices for images
+
+ else: # backend kind == 'curve'
+ for kind in ('curve', 'histogram', 'scatter'):
+ item = self._getItem(kind=kind, legend=legend)
+ if item is not None:
+ indices = itemInfo['indices']
+ break
+ else:
+ _logger.error(
+ 'Cannot find corresponding picked item')
+ continue
+ items.append((item, indices))
+
+ return tuple(items)
+
# User event handling #
def _isPositionInPlotArea(self, x, y):
@@ -2846,7 +2902,7 @@ class PlotWidget(qt.QMainWindow):
"""Switch the interactive mode.
:param str mode: The name of the interactive mode.
- In 'draw', 'pan', 'select', 'zoom'.
+ In 'draw', 'pan', 'select', 'select-draw', 'zoom'.
:param color: Only for 'draw' and 'zoom' modes.
Color to use for drawing selection area. Default black.
:type color: Color description: The name as a str or
@@ -2959,7 +3015,7 @@ class PlotWidget(qt.QMainWindow):
:param str label: Associated text for identifying draw signals
:param color: The color to use to draw the selection area
:type color: string ("#RRGGBB") or 4 column unsigned byte array or
- one of the predefined color names defined in Colors.py
+ one of the predefined color names defined in colors.py
"""
_logger.warning(
'setDrawModeEnabled deprecated, use setInteractiveMode instead')
@@ -3011,7 +3067,7 @@ class PlotWidget(qt.QMainWindow):
(Default: 'black')
:param color: The color to use to draw the selection area
:type color: string ("#RRGGBB") or 4 column unsigned byte array or
- one of the predefined color names defined in Colors.py
+ one of the predefined color names defined in colors.py
"""
_logger.warning(
'setZoomModeEnabled deprecated, use setInteractiveMode instead')