diff options
Diffstat (limited to 'silx/gui/plot/ScatterMaskToolsWidget.py')
-rw-r--r-- | silx/gui/plot/ScatterMaskToolsWidget.py | 68 |
1 files changed, 56 insertions, 12 deletions
diff --git a/silx/gui/plot/ScatterMaskToolsWidget.py b/silx/gui/plot/ScatterMaskToolsWidget.py index a9c1073..2a10f6d 100644 --- a/silx/gui/plot/ScatterMaskToolsWidget.py +++ b/silx/gui/plot/ScatterMaskToolsWidget.py @@ -1,7 +1,7 @@ # coding: utf-8 # /*########################################################################## # -# Copyright (c) 2017 European Synchrotron Radiation Facility +# Copyright (c) 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 @@ -35,7 +35,7 @@ from __future__ import division __authors__ = ["P. Knobel"] __license__ = "MIT" -__date__ = "07/04/2017" +__date__ = "24/04/2018" import math @@ -45,10 +45,11 @@ import numpy import sys from .. import qt +from ...math.combo import min_max from ...image import shapes from ._BaseMaskToolsWidget import BaseMask, BaseMaskToolsWidget, BaseMaskToolsDockWidget -from .Colors import cursorColorForColormap, rgba +from ..colors import cursorColorForColormap, rgba _logger = logging.getLogger(__name__) @@ -186,13 +187,18 @@ class ScatterMaskToolsWidget(BaseMaskToolsWidget): self._z = 2 # Mask layer in plot self._data_scatter = None """plot Scatter item for data""" + + self._data_extent = None + """Maximum extent of the data i.e., max(xMax-xMin, yMax-yMin)""" + self._mask_scatter = None """plot Scatter item for representing the mask""" def setSelectionMask(self, mask, copy=True): """Set the mask to a new array. - :param numpy.ndarray mask: The array to use for the mask. + :param numpy.ndarray mask: + The array to use for the mask or None to reset the mask. :type mask: numpy.ndarray of uint8, C-contiguous. Array of other types are converted. :param bool copy: True (the default) to copy the array, @@ -201,6 +207,10 @@ class ScatterMaskToolsWidget(BaseMaskToolsWidget): The mask can be cropped or padded to fit active scatter, the returned shape is that of the scatter data. """ + if mask is None: + self.resetSelectionMask() + return self._data_scatter.getXData(copy=False).shape + mask = numpy.array(mask, copy=False, dtype=numpy.uint8) if self._data_scatter.getXData(copy=False).shape == (0,) \ @@ -216,7 +226,7 @@ class ScatterMaskToolsWidget(BaseMaskToolsWidget): def _updatePlotMask(self): """Update mask image in plot""" mask = self.getSelectionMask(copy=False) - if len(mask): + if mask is not None: self.plot.addScatter(self._data_scatter.getXData(), self._data_scatter.getYData(), mask, @@ -226,8 +236,7 @@ class ScatterMaskToolsWidget(BaseMaskToolsWidget): self._mask_scatter = self.plot._getItem(kind="scatter", legend=self._maskName) self._mask_scatter.setSymbolSize( - self._data_scatter.getSymbolSize() * 4.0 - ) + self._data_scatter.getSymbolSize() + 2.0) elif self.plot._getItem(kind="scatter", legend=self._maskName) is not None: self.plot.remove(self._maskName, kind='scatter') @@ -248,7 +257,7 @@ class ScatterMaskToolsWidget(BaseMaskToolsWidget): if not self.browseAction.isChecked(): self.browseAction.trigger() # Disable drawing tool - if len(self.getSelectionMask(copy=False)): + if self.getSelectionMask(copy=False) is not None: self.plot.sigActiveScatterChanged.connect( self._activeScatterChangedAfterCare) @@ -265,6 +274,9 @@ class ScatterMaskToolsWidget(BaseMaskToolsWidget): # No active scatter or active scatter is the mask... self.plot.sigActiveScatterChanged.disconnect( self._activeScatterChangedAfterCare) + self._data_extent = None + self._data_scatter = None + else: colormap = activeScatter.getColormap() self._defaultOverlayColor = rgba(cursorColorForColormap(colormap['name'])) @@ -274,13 +286,22 @@ class ScatterMaskToolsWidget(BaseMaskToolsWidget): self._z = activeScatter.getZValue() + 1 self._data_scatter = activeScatter - if self._data_scatter.getXData(copy=False).shape != self.getSelectionMask(copy=False).shape: + + # Adjust brush size to data range + xMin, xMax = min_max(self._data_scatter.getXData(copy=False)) + yMin, yMax = min_max(self._data_scatter.getYData(copy=False)) + self._data_extent = max(xMax - xMin, yMax - yMin) + + if self._data_scatter.getXData(copy=False).shape != self._mask.getMask(copy=False).shape: # scatter has not the same size, remove mask and stop listening if self.plot._getItem(kind="scatter", legend=self._maskName): self.plot.remove(self._maskName, kind='scatter') self.plot.sigActiveScatterChanged.disconnect( self._activeScatterChangedAfterCare) + self._data_extent = None + self._data_scatter = None + else: # Refresh in case z changed self._mask.setDataItem(self._data_scatter) @@ -295,6 +316,7 @@ class ScatterMaskToolsWidget(BaseMaskToolsWidget): self.setEnabled(False) self._data_scatter = None + self._data_extent = None self._mask.reset() self._mask.commit() @@ -309,8 +331,19 @@ class ScatterMaskToolsWidget(BaseMaskToolsWidget): self._z = activeScatter.getZValue() + 1 self._data_scatter = activeScatter + + # Adjust brush size to data range + xData = self._data_scatter.getXData(copy=False) + yData = self._data_scatter.getYData(copy=False) + if xData.size > 0 and yData.size > 0: + xMin, xMax = min_max(xData) + yMin, yMax = min_max(yData) + self._data_extent = max(xMax - xMin, yMax - yMin) + else: + self._data_extent = None + self._mask.setDataItem(self._data_scatter) - if self._data_scatter.getXData(copy=False).shape != self.getSelectionMask(copy=False).shape: + if self._data_scatter.getXData(copy=False).shape != self._mask.getMask(copy=False).shape: self._mask.reset(self._data_scatter.getXData(copy=False).shape) self._mask.commit() else: @@ -439,6 +472,16 @@ class ScatterMaskToolsWidget(BaseMaskToolsWidget): shape=self._data_scatter.getXData(copy=False).shape) self._mask.commit() + def _getPencilWidth(self): + """Returns the width of the pencil to use in data coordinates` + + :rtype: float + """ + width = super(ScatterMaskToolsWidget, self)._getPencilWidth() + if self._data_extent is not None: + width *= 0.01 * self._data_extent + return width + def _plotDrawEvent(self, event): """Handle draw events from the plot""" if (self._drawingMode is None or @@ -467,7 +510,7 @@ class ScatterMaskToolsWidget(BaseMaskToolsWidget): event['event'] == 'drawingFinished'): doMask = self._isMasking() vertices = event['points'] - vertices = vertices.astype(numpy.int)[:, (1, 0)] # (y, x) + vertices = vertices[:, (1, 0)] # (y, x) self._mask.updatePolygon(level, vertices, doMask) self._mask.commit() @@ -475,7 +518,8 @@ class ScatterMaskToolsWidget(BaseMaskToolsWidget): doMask = self._isMasking() # convert from plot to array coords x, y = event['points'][-1] - brushSize = self.pencilSpinBox.value() + + brushSize = self._getPencilWidth() if self._lastPencilPos != (y, x): if self._lastPencilPos is not None: |