diff options
Diffstat (limited to 'silx/gui/plot/_BaseMaskToolsWidget.py')
-rw-r--r-- | silx/gui/plot/_BaseMaskToolsWidget.py | 157 |
1 files changed, 92 insertions, 65 deletions
diff --git a/silx/gui/plot/_BaseMaskToolsWidget.py b/silx/gui/plot/_BaseMaskToolsWidget.py index e087354..0d11f17 100644 --- a/silx/gui/plot/_BaseMaskToolsWidget.py +++ b/silx/gui/plot/_BaseMaskToolsWidget.py @@ -29,7 +29,7 @@ from __future__ import division __authors__ = ["T. Vincent", "P. Knobel"] __license__ = "MIT" -__date__ = "29/08/2018" +__date__ = "15/02/2019" import os import weakref @@ -141,7 +141,7 @@ class BaseMask(qt.QObject): def commit(self): """Append the current mask to history if changed""" if (not self._history or self._redo or - not numpy.all(numpy.equal(self._mask, self._history[-1]))): + not numpy.array_equal(self._mask, self._history[-1])): if self._redo: self._redo = [] # Reset redo as a new action as been performed self.sigRedoable[bool].emit(False) @@ -325,7 +325,7 @@ class BaseMask(qt.QObject): raise NotImplementedError("To be implemented in subclass") def updateDisk(self, level, crow, ccol, radius, mask=True): - """Mask/Unmask data located inside a disk of the given mask level. + """Mask/Unmask data located inside a dick of the given mask level. :param int level: Mask level to update. :param crow: Disk center row/ordinate (y). @@ -335,6 +335,18 @@ class BaseMask(qt.QObject): """ raise NotImplementedError("To be implemented in subclass") + def updateEllipse(self, level, crow, ccol, radius_r, radius_c, mask=True): + """Mask/Unmask a disk of the given mask level. + + :param int level: Mask level to update. + :param int crow: Row of the center of the ellipse + :param int ccol: Column of the center of the ellipse + :param float radius_r: Radius of the ellipse in the row + :param float radius_c: Radius of the ellipse in the column + :param bool mask: True to mask (default), False to unmask. + """ + raise NotImplementedError("To be implemented in subclass") + def updateLine(self, level, row0, col0, row1, col1, width, mask=True): """Mask/Unmask a line of the given mask level. @@ -376,13 +388,11 @@ class BaseMaskToolsWidget(qt.QWidget): self._plotRef = weakref.ref(plot) self._maskName = '__MASK_TOOLS_%d' % id(self) # Legend of the mask - self._colormap = Colormap(name="", - normalization='linear', + self._colormap = Colormap(normalization='linear', vmin=0, - vmax=self._maxLevelNumber, - colors=None) + vmax=self._maxLevelNumber) self._defaultOverlayColor = rgba('gray') # Color of the mask - self._setMaskColors(1, 0.5) + self._setMaskColors(1, 0.5) # Set the colormap LUT if not isinstance(mask, BaseMask): raise TypeError("mask is not an instance of BaseMask") @@ -482,6 +492,7 @@ class BaseMaskToolsWidget(qt.QWidget): layout.addWidget(self._initMaskGroupBox()) layout.addWidget(self._initDrawGroupBox()) layout.addWidget(self._initThresholdGroupBox()) + layout.addWidget(self._initOtherToolsGroupBox()) layout.addStretch(1) self.setLayout(layout) @@ -617,6 +628,15 @@ class BaseMaskToolsWidget(qt.QWidget): self.rectAction.triggered.connect(self._activeRectMode) self.addAction(self.rectAction) + self.ellipseAction = qt.QAction( + icons.getQIcon('shape-ellipse'), 'Circle selection', None) + self.ellipseAction.setToolTip( + 'Rectangle selection tool: (Un)Mask a circle region <b>R</b>') + self.ellipseAction.setShortcut(qt.QKeySequence(qt.Qt.Key_R)) + self.ellipseAction.setCheckable(True) + self.ellipseAction.triggered.connect(self._activeEllipseMode) + self.addAction(self.ellipseAction) + self.polygonAction = qt.QAction( icons.getQIcon('shape-polygon'), 'Polygon selection', None) self.polygonAction.setShortcut(qt.QKeySequence(qt.Qt.Key_S)) @@ -640,10 +660,11 @@ class BaseMaskToolsWidget(qt.QWidget): self.drawActionGroup = qt.QActionGroup(self) self.drawActionGroup.setExclusive(True) self.drawActionGroup.addAction(self.rectAction) + self.drawActionGroup.addAction(self.ellipseAction) self.drawActionGroup.addAction(self.polygonAction) self.drawActionGroup.addAction(self.pencilAction) - actions = (self.browseAction, self.rectAction, + actions = (self.browseAction, self.rectAction, self.ellipseAction, self.polygonAction, self.pencilAction) drawButtons = [] for action in actions: @@ -711,36 +732,28 @@ class BaseMaskToolsWidget(qt.QWidget): def _initThresholdGroupBox(self): """Init thresholding widgets""" - layout = qt.QVBoxLayout() - - # Thresholing self.belowThresholdAction = qt.QAction( icons.getQIcon('plot-roi-below'), 'Mask below threshold', None) self.belowThresholdAction.setToolTip( 'Mask image where values are below given threshold') self.belowThresholdAction.setCheckable(True) - self.belowThresholdAction.triggered[bool].connect( - self._belowThresholdActionTriggered) + self.belowThresholdAction.setChecked(True) self.betweenThresholdAction = qt.QAction( icons.getQIcon('plot-roi-between'), 'Mask within range', None) self.betweenThresholdAction.setToolTip( 'Mask image where values are within given range') self.betweenThresholdAction.setCheckable(True) - self.betweenThresholdAction.triggered[bool].connect( - self._betweenThresholdActionTriggered) self.aboveThresholdAction = qt.QAction( icons.getQIcon('plot-roi-above'), 'Mask above threshold', None) self.aboveThresholdAction.setToolTip( 'Mask image where values are above given threshold') self.aboveThresholdAction.setCheckable(True) - self.aboveThresholdAction.triggered[bool].connect( - self._aboveThresholdActionTriggered) self.thresholdActionGroup = qt.QActionGroup(self) - self.thresholdActionGroup.setExclusive(False) + self.thresholdActionGroup.setExclusive(True) self.thresholdActionGroup.addAction(self.belowThresholdAction) self.thresholdActionGroup.addAction(self.betweenThresholdAction) self.thresholdActionGroup.addAction(self.aboveThresholdAction) @@ -770,41 +783,50 @@ class BaseMaskToolsWidget(qt.QWidget): loadColormapRangeBtn.setDefaultAction(self.loadColormapRangeAction) widgets.append(loadColormapRangeBtn) - container = self._hboxWidget(*widgets, stretch=False) - layout.addWidget(container) + toolBar = self._hboxWidget(*widgets, stretch=False) - form = qt.QFormLayout() + config = qt.QGridLayout() + config.setContentsMargins(0, 0, 0, 0) + self.minLineLabel = qt.QLabel("Min:", self) self.minLineEdit = FloatEdit(self, value=0) - self.minLineEdit.setEnabled(False) - form.addRow('Min:', self.minLineEdit) + config.addWidget(self.minLineLabel, 0, 0) + config.addWidget(self.minLineEdit, 0, 1) + self.maxLineLabel = qt.QLabel("Max:", self) self.maxLineEdit = FloatEdit(self, value=0) - self.maxLineEdit.setEnabled(False) - form.addRow('Max:', self.maxLineEdit) + config.addWidget(self.maxLineLabel, 1, 0) + config.addWidget(self.maxLineEdit, 1, 1) self.applyMaskBtn = qt.QPushButton('Apply mask') self.applyMaskBtn.clicked.connect(self._maskBtnClicked) - self.applyMaskBtn.setEnabled(False) - form.addRow(self.applyMaskBtn) - - self.maskNanBtn = qt.QPushButton('Mask not finite values') - self.maskNanBtn.setToolTip('Mask Not a Number and infinite values') - self.maskNanBtn.clicked.connect(self._maskNotFiniteBtnClicked) - form.addRow(self.maskNanBtn) - thresholdWidget = qt.QWidget() - thresholdWidget.setLayout(form) - layout.addWidget(thresholdWidget) - - layout.addStretch(1) + layout = qt.QVBoxLayout() + layout.addWidget(toolBar) + layout.addLayout(config) + layout.addWidget(self.applyMaskBtn) self.thresholdGroup = qt.QGroupBox('Threshold') self.thresholdGroup.setLayout(layout) + + # Init widget state + self._thresholdActionGroupTriggered(self.belowThresholdAction) return self.thresholdGroup # track widget visibility and plot active image changes + def _initOtherToolsGroupBox(self): + layout = qt.QVBoxLayout() + + self.maskNanBtn = qt.QPushButton('Mask not finite values') + self.maskNanBtn.setToolTip('Mask Not a Number and infinite values') + self.maskNanBtn.clicked.connect(self._maskNotFiniteBtnClicked) + layout.addWidget(self.maskNanBtn) + + self.otherToolGroup = qt.QGroupBox('Other tools') + self.otherToolGroup.setLayout(layout) + return self.otherToolGroup + def changeEvent(self, event): """Reset drawing action when disabling widget""" if (event.type() == qt.QEvent.EnabledChange and @@ -883,6 +905,7 @@ class BaseMaskToolsWidget(qt.QWidget): The index of the mask for which we want to change the color. If none set this color for all the masks """ + rgb = rgba(rgb)[0:3] if level is None: self._overlayColors[:] = rgb self._defaultColors[:] = False @@ -925,6 +948,8 @@ class BaseMaskToolsWidget(qt.QWidget): """ if self._drawingMode == 'rectangle': self._activeRectMode() + elif self._drawingMode == 'ellipse': + self._activeEllipseMode() elif self._drawingMode == 'polygon': self._activePolygonMode() elif self._drawingMode == 'pencil': @@ -971,6 +996,16 @@ class BaseMaskToolsWidget(qt.QWidget): 'draw', shape='rectangle', source=self, color=color) self._updateDrawingModeWidgets() + def _activeEllipseMode(self): + """Handle circle action mode triggering""" + self._releaseDrawingMode() + self._drawingMode = 'ellipse' + self.plot.sigPlotSignal.connect(self._plotDrawEvent) + color = self.getCurrentMaskColor() + self.plot.setInteractiveMode( + 'draw', shape='ellipse', source=self, color=color) + self._updateDrawingModeWidgets() + def _activePolygonMode(self): """Handle polygon action mode triggering""" self._releaseDrawingMode() @@ -1016,36 +1051,28 @@ class BaseMaskToolsWidget(qt.QWidget): return doMask # Handle threshold UI events - def _belowThresholdActionTriggered(self, triggered): - if triggered: - self.minLineEdit.setEnabled(True) - self.maxLineEdit.setEnabled(False) - self.applyMaskBtn.setEnabled(True) - - def _betweenThresholdActionTriggered(self, triggered): - if triggered: - self.minLineEdit.setEnabled(True) - self.maxLineEdit.setEnabled(True) - self.applyMaskBtn.setEnabled(True) - - def _aboveThresholdActionTriggered(self, triggered): - if triggered: - self.minLineEdit.setEnabled(False) - self.maxLineEdit.setEnabled(True) - self.applyMaskBtn.setEnabled(True) def _thresholdActionGroupTriggered(self, triggeredAction): """Threshold action group listener.""" - if triggeredAction.isChecked(): - # Uncheck other actions - for action in self.thresholdActionGroup.actions(): - if action is not triggeredAction and action.isChecked(): - action.setChecked(False) - else: - # Disable min/max edit - self.minLineEdit.setEnabled(False) - self.maxLineEdit.setEnabled(False) - self.applyMaskBtn.setEnabled(False) + if triggeredAction is self.belowThresholdAction: + self.minLineLabel.setVisible(True) + self.maxLineLabel.setVisible(False) + self.minLineEdit.setVisible(True) + self.maxLineEdit.setVisible(False) + self.applyMaskBtn.setText("Mask bellow") + elif triggeredAction is self.betweenThresholdAction: + self.minLineLabel.setVisible(True) + self.maxLineLabel.setVisible(True) + self.minLineEdit.setVisible(True) + self.maxLineEdit.setVisible(True) + self.applyMaskBtn.setText("Mask between") + elif triggeredAction is self.aboveThresholdAction: + self.minLineLabel.setVisible(False) + self.maxLineLabel.setVisible(True) + self.minLineEdit.setVisible(False) + self.maxLineEdit.setVisible(True) + self.applyMaskBtn.setText("Mask above") + self.applyMaskBtn.setToolTip(triggeredAction.toolTip()) def _maskBtnClicked(self): if self.belowThresholdAction.isChecked(): |