summaryrefslogtreecommitdiff
path: root/PyMca5/PyMcaGui/plotting
diff options
context:
space:
mode:
Diffstat (limited to 'PyMca5/PyMcaGui/plotting')
-rw-r--r--PyMca5/PyMcaGui/plotting/ColormapDialog.py75
-rw-r--r--PyMca5/PyMcaGui/plotting/ImageView.py898
-rw-r--r--PyMca5/PyMcaGui/plotting/MaskImageTools.py6
-rw-r--r--PyMca5/PyMcaGui/plotting/MaskImageWidget.py291
-rw-r--r--PyMca5/PyMcaGui/plotting/MaskScatterWidget.py584
-rw-r--r--PyMca5/PyMcaGui/plotting/MaskToolBar.py331
-rw-r--r--PyMca5/PyMcaGui/plotting/McaROIWidget.py26
-rw-r--r--PyMca5/PyMcaGui/plotting/PlotWidget.py15
-rw-r--r--PyMca5/PyMcaGui/plotting/PlotWindow.py5
-rw-r--r--PyMca5/PyMcaGui/plotting/ProfileScanWidget.py4
-rw-r--r--PyMca5/PyMcaGui/plotting/PyMca_Icons.py13
-rw-r--r--PyMca5/PyMcaGui/plotting/Q4PyMcaPrintPreview.py11
-rw-r--r--PyMca5/PyMcaGui/plotting/RGBCorrelatorGraph.py178
-rw-r--r--PyMca5/PyMcaGui/plotting/ScatterPlotCorrelatorWidget.py4
-rw-r--r--PyMca5/PyMcaGui/plotting/SilxMaskImageWidget.py32
-rw-r--r--PyMca5/PyMcaGui/plotting/_ImageProfile.py34
16 files changed, 964 insertions, 1543 deletions
diff --git a/PyMca5/PyMcaGui/plotting/ColormapDialog.py b/PyMca5/PyMcaGui/plotting/ColormapDialog.py
index b42bac2..e0851ce 100644
--- a/PyMca5/PyMcaGui/plotting/ColormapDialog.py
+++ b/PyMca5/PyMcaGui/plotting/ColormapDialog.py
@@ -28,12 +28,14 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
-from . import PlotWidget
+from silx.gui.plot import PlotWidget
QTVERSION = qt.qVersion()
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
class MyQLineEdit(qt.QLineEdit):
def __init__(self,parent=None,name=""):
@@ -47,8 +49,7 @@ class MyQLineEdit(qt.QLineEdit):
self.returnPressed[()].emit()
def setPaletteBackgroundColor(self, color):
- if DEBUG:
- print("setPalettebackgroundColor not implemented yet")
+ _logger.debug("setPalettebackgroundColor not implemented yet")
pass
"""
@@ -213,9 +214,9 @@ class ColormapDialog(qt.QDialog):
# Graph widget for color curve...
- self.c = PlotWidget.PlotWidget(self, backend=None)
+ self.c = PlotWidget(self, backend=None)
self.c.setGraphXLabel("Data Values")
- self.c.setZoomModeEnabled(False)
+ self.c.setInteractiveMode('select')
self.marge = (abs(self.dataMax) + abs(self.dataMin)) / 6.0
self.minmd = self.dataMin - self.marge
@@ -244,11 +245,11 @@ class ColormapDialog(qt.QDialog):
color = "black"
#TODO symbol
legend = "%d" % i
- self.c.insertXMarker(x[i],
- legend=legend,
- text=labelList[i],
- draggable=draggable,
- color=color)
+ self.c.addXMarker(x[i],
+ legend=legend,
+ text=labelList[i],
+ draggable=draggable,
+ color=color)
self.markers.append((legend, ""))
self.c.setMinimumSize(qt.QSize(250,200))
@@ -267,16 +268,13 @@ class ColormapDialog(qt.QDialog):
bins, counts = self.histogramData
self.c.addCurve(bins, counts,
"Histogram",
- color='pink', # TODO: Change fill color
- symbol='s',
- linestyle='-', # Line style
- #fill=True,
- yaxis='right')
- # TODO: Do not use info!
+ color='darkYellow',
+ histogram='center',
+ yaxis='right',
+ fill=True)
def _update(self):
- if DEBUG:
- print("colormap _update called")
+ _logger.debug("colormap _update called")
self.marge = (abs(self.dataMax) + abs(self.dataMin)) / 6.0
self.minmd = self.dataMin - self.marge
self.maxpd = self.dataMax + self.marge
@@ -300,17 +298,15 @@ class ColormapDialog(qt.QDialog):
color = "black"
key = self.markers[i][0]
label = self.markers[i][1]
- self.c.insertXMarker(self.__x[i],
- legend=key,
- text=label,
- draggable=draggable,
- color=color)
- self.c.replot()
+ self.c.addXMarker(self.__x[i],
+ legend=key,
+ text=label,
+ draggable=draggable,
+ color=color)
self.sendColormap()
def buttonGroupChange(self, val):
- if DEBUG:
- print("buttonGroup asking to update colormap")
+ _logger.debug("buttonGroup asking to update colormap")
self.setColormapType(val, update=True)
self._update()
@@ -327,8 +323,7 @@ class ColormapDialog(qt.QDialog):
self._update()
def chval(self, ddict):
- if DEBUG:
- print("Received ", ddict)
+ _logger.debug("Received %s", ddict)
if ddict['event'] == 'markerMoving':
diam = int(ddict['label'])
x = ddict['x']
@@ -368,8 +363,7 @@ class ColormapDialog(qt.QDialog):
self.sendColormap()
def setAutoscale(self, val):
- if DEBUG:
- print("setAutoscale called", val)
+ _logger.debug("setAutoscale called %s", val)
if val:
self.autoScaleButton.setChecked(True)
self.autoScale90Button.setChecked(False)
@@ -378,14 +372,14 @@ class ColormapDialog(qt.QDialog):
self.setMaxValue(self.dataMax)
self.maxText.setEnabled(0)
self.minText.setEnabled(0)
- self.c.setEnabled(0)
+ self.c.setEnabled(False)
#self.c.disablemarkermode()
else:
self.autoScaleButton.setChecked(False)
self.autoScale90Button.setChecked(False)
self.minText.setEnabled(1)
self.maxText.setEnabled(1)
- self.c.setEnabled(1)
+ self.c.setEnabled(True)
#self.c.enablemarkermode()
"""
@@ -403,12 +397,12 @@ class ColormapDialog(qt.QDialog):
self.setMaxValue(self.dataMax - abs(self.dataMax/10))
self.minText.setEnabled(0)
self.maxText.setEnabled(0)
- self.c.setEnabled(0)
+ self.c.setEnabled(False)
else:
self.autoScale90Button.setChecked(False)
self.minText.setEnabled(1)
self.maxText.setEnabled(1)
- self.c.setEnabled(1)
+ self.c.setEnabled(True)
self.c.setFocus()
@@ -424,7 +418,7 @@ class ColormapDialog(qt.QDialog):
self.__x[1] = v
key = self.markers[1][0]
label = self.markers[1][1]
- self.c.insertXMarker(v, legend=key, text=label, color="blue", draggable=True)
+ self.c.addXMarker(v, legend=key, text=label, color="blue", draggable=True)
self.c.addCurve(self.__x,
self.__y,
legend="ConstrainedCurve",
@@ -455,7 +449,7 @@ class ColormapDialog(qt.QDialog):
self.__x[1] = val
key = self.markers[1][0]
label = self.markers[1][1]
- self.c.insertXMarker(val, legend=key, text=label, color="blue", draggable=True)
+ self.c.addXMarker(val, legend=key, text=label, color="blue", draggable=True)
self.c.addCurve(self.__x, self.__y,
legend="ConstrainedCurve",
color='black',
@@ -472,7 +466,7 @@ class ColormapDialog(qt.QDialog):
self.__x[2] = v
key = self.markers[2][0]
label = self.markers[2][1]
- self.c.insertXMarker(v, legend=key, text=label, color="blue", draggable=True)
+ self.c.addXMarker(v, legend=key, text=label, color="blue", draggable=True)
self.c.addCurve(self.__x, self.__y,
legend="ConstrainedCurve",
color='black',
@@ -501,7 +495,7 @@ class ColormapDialog(qt.QDialog):
self.__x[2] = val
key = self.markers[2][0]
label = self.markers[2][1]
- self.c.insertXMarker(val, legend=key, text=label, color="blue", draggable=True)
+ self.c.addXMarker(val, legend=key, text=label, color="blue", draggable=True)
self.c.addCurve(self.__x, self.__y,
legend="ConstrainedCurve",
color='black',
@@ -542,8 +536,7 @@ class ColormapDialog(qt.QDialog):
send 'ColormapChanged' signal
"""
def sendColormap(self):
- if DEBUG:
- print("sending colormap")
+ _logger.debug("sending colormap")
try:
cmap = self.getColormap()
self.sigColormapChanged.emit(cmap)
diff --git a/PyMca5/PyMcaGui/plotting/ImageView.py b/PyMca5/PyMcaGui/plotting/ImageView.py
index 2f8bd11..3371533 100644
--- a/PyMca5/PyMcaGui/plotting/ImageView.py
+++ b/PyMca5/PyMcaGui/plotting/ImageView.py
@@ -31,25 +31,11 @@ __contact__ = "thomas.vincent@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
__doc__ = """
-QWidget displaying a 2D image with histograms on its sides.
+The classes in this module are deprecated. Use
+:class:`silx.gui.plot.ImageView` and
+:class:`silx.gui.plot.ImageViewMainWindow` instead.
-The :class:`ImageView` implements this widget, and
-:class:`ImageViewMainWindow` provides a main window with additional toolbar
-and status bar.
-
-Basic usage of :class:`ImageView` is through the following methods:
-
-- :meth:`ImageView.getColormap`, :meth:`ImageView.setColormap` to update the
- default colormap to use and update the currently displayed image.
-- :meth:`ImageView.setImage` to update the displayed image.
-
-The :class:`ImageView` uses :class:`PlotWindow` and also
-exposes :class:`PyMca5.PyMcaGraph.Plot` API for further control
-(plot title, axes labels, adding other images, ...).
-
-For an example of use, see the implementation of :class:`ImageViewMainWindow`.
-
-The ImageView module can also be used to open an EDF or TIFF file
+This module can be used to open an EDF or TIFF file
from the shell command line.
To view an image file:
``python -m PyMca5.PyMcaGui.plotting.ImageView <file to open>``
@@ -59,872 +45,50 @@ To get help:
# import ######################################################################
-
-import numpy as np
-
+import logging
+import traceback
try:
from .. import PyMcaQt as qt
except ImportError:
from PyMca5.PyMcaGui import PyMcaQt as qt
-from .PlotWindow import PlotWindow
-from .Toolbars import ProfileToolBar, LimitsToolBar
-
-from PyMca5.PyMcaGraph import Plot
-
-
-# utils #######################################################################
-
-_COLORMAP_CURSOR_COLORS = {
- 'gray': 'pink',
- 'reversed gray': 'pink',
- 'temperature': 'black',
- 'red': 'gray',
- 'green': 'gray',
- 'blue': 'gray'}
-
-
-def _cursorColorForColormap(colormapName):
- """Get a color suitable for overlay over a colormap.
-
- :param str colormapName: The name of the colormap.
- :return: Name of the color.
- :rtype: str
- """
- return _COLORMAP_CURSOR_COLORS.get(colormapName, 'black')
-
-
-# RadarView ###################################################################
-
-class RadarView(qt.QGraphicsView):
- """Widget presenting a synthetic view of a 2D area and
- the current visible area.
-
- Coordinates are as in QGraphicsView:
- x goes from left to right and y goes from top to bottom.
- This widget preserves the aspect ratio of the areas.
-
- The 2D area and the visible area can be set with :meth:`setDataRect`
- and :meth:`setVisibleRect`.
- When the visible area has been dragged by the user, its new position
- is signaled by the *visibleRectDragged* signal.
-
- It is possible to invert the direction of the axes by using the
- :meth:`scale` method of QGraphicsView.
- """
-
- visibleRectDragged = qt.pyqtSignal(float, float, float, float)
- """Signals that the visible rectangle has been dragged.
-
- It provides: left, top, width, height in data coordinates.
- """
-
- _DATA_PEN = qt.QPen(qt.QColor('white'))
- _DATA_BRUSH = qt.QBrush(qt.QColor('light gray'))
- _VISIBLE_PEN = qt.QPen(qt.QColor('red'))
- _VISIBLE_BRUSH = qt.QBrush(qt.QColor(0, 0, 0, 0))
- _TOOLTIP = 'Radar View:\nVisible area (in red)\nof the image (in gray).'
-
- _PIXMAP_SIZE = 256
-
- class _DraggableRectItem(qt.QGraphicsRectItem):
- """RectItem which signals its change through visibleRectDragged."""
- def __init__(self, *args, **kwargs):
- super(RadarView._DraggableRectItem, self).__init__(*args, **kwargs)
- self.setFlag(qt.QGraphicsItem.ItemIsMovable)
- self.setFlag(qt.QGraphicsItem.ItemSendsGeometryChanges)
- self._ignoreChange = False
- self._constraint = 0, 0, 0, 0
-
- def setConstraintRect(self, left, top, width, height):
- """Set the constraint rectangle for dragging.
-
- The coordinates are in the _DraggableRectItem coordinate system.
-
- This constraint only applies to modification through interaction
- (i.e., this constraint is not applied to change through API).
-
- If the _DraggableRectItem is smaller than the constraint rectangle,
- the _DraggableRectItem remains within the constraint rectangle.
- If the _DraggableRectItem is wider than the constraint rectangle,
- the constraint rectangle remains within the _DraggableRectItem.
- """
- self._constraint = left, left + width, top, top + height
-
- def setPos(self, *args, **kwargs):
- """Overridden to ignore changes from API in itemChange."""
- self._ignoreChange = True
- super(RadarView._DraggableRectItem, self).setPos(*args, **kwargs)
- self._ignoreChange = False
-
- def moveBy(self, *args, **kwargs):
- """Overridden to ignore changes from API in itemChange."""
- self._ignoreChange = True
- super(RadarView._DraggableRectItem, self).moveBy(*args, **kwargs)
- self._ignoreChange = False
-
- def itemChange(self, change, value):
- """Callback called before applying changes to the item."""
- if (change == qt.QGraphicsItem.ItemPositionChange and
- not self._ignoreChange):
- # Makes sure that the visible area is in the data
- # or that data is in the visible area if area is too wide
- x, y = value.x(), value.y()
- xMin, xMax, yMin, yMax = self._constraint
-
- if self.rect().width() <= (xMax - xMin):
- if x < xMin:
- value.setX(xMin)
- elif x > xMax - self.rect().width():
- value.setX(xMax - self.rect().width())
- else:
- if x > xMin:
- value.setX(xMin)
- elif x < xMax - self.rect().width():
- value.setX(xMax - self.rect().width())
-
- if self.rect().height() <= (yMax - yMin):
- if y < yMin:
- value.setY(yMin)
- elif y > yMax - self.rect().height():
- value.setY(yMax - self.rect().height())
- else:
- if y > yMin:
- value.setY(yMin)
- elif y < yMax - self.rect().height():
- value.setY(yMax - self.rect().height())
-
- if self.pos() != value:
- # Notify change through signal
- views = self.scene().views()
- assert len(views) == 1
- views[0].visibleRectDragged.emit(
- value.x() + self.rect().left(),
- value.y() + self.rect().top(),
- self.rect().width(),
- self.rect().height())
-
- return value
-
- return super(RadarView._DraggableRectItem, self).itemChange(
- change, value)
-
- def __init__(self, parent=None):
- self._scene = qt.QGraphicsScene()
- self._dataRect = self._scene.addRect(0, 0, 1, 1,
- self._DATA_PEN,
- self._DATA_BRUSH)
- self._visibleRect = self._DraggableRectItem(0, 0, 1, 1)
- self._visibleRect.setPen(self._VISIBLE_PEN)
- self._visibleRect.setBrush(self._VISIBLE_BRUSH)
- self._scene.addItem(self._visibleRect)
-
- super(RadarView, self).__init__(self._scene, parent)
- self.setHorizontalScrollBarPolicy(qt.Qt.ScrollBarAlwaysOff)
- self.setVerticalScrollBarPolicy(qt.Qt.ScrollBarAlwaysOff)
- self.setFocusPolicy(qt.Qt.NoFocus)
- self.setStyleSheet('border: 0px')
- self.setToolTip(self._TOOLTIP)
-
- def sizeHint(self):
- # """Overridden to avoid sizeHint to depend on content size."""
- return self.minimumSizeHint()
-
- def wheelEvent(self, event):
- # """Overridden to disable vertical scrolling with wheel."""
- event.ignore()
-
- def resizeEvent(self, event):
- # """Overridden to fit current content to new size."""
- self.fitInView(self._scene.itemsBoundingRect(), qt.Qt.KeepAspectRatio)
- super(RadarView, self).resizeEvent(event)
-
- def setDataRect(self, left, top, width, height):
- """Set the bounds of the data rectangular area.
-
- This sets the coordinate system.
- """
- self._dataRect.setRect(left, top, width, height)
- self._visibleRect.setConstraintRect(left, top, width, height)
- self.fitInView(self._scene.itemsBoundingRect(), qt.Qt.KeepAspectRatio)
-
- def setVisibleRect(self, left, top, width, height):
- """Set the visible rectangular area.
-
- The coordinates are relative to the data rect.
- """
- self._visibleRect.setRect(0, 0, width, height)
- self._visibleRect.setPos(left, top)
- self.fitInView(self._scene.itemsBoundingRect(), qt.Qt.KeepAspectRatio)
-
-
-# ImageView ###################################################################
-
-class ImageView(qt.QWidget):
- """Display a single image with horizontal and vertical histograms.
-
- Use :meth:`setImage` to control the displayed image.
- This class also provides the :class:`PyMca5.PyMcaGraph.Plot` API.
- """
-
- HISTOGRAMS_COLOR = 'blue'
- """Color to use for the side histograms."""
-
- HISTOGRAMS_HEIGHT = 200
- """Height in pixels of the side histograms."""
-
- IMAGE_MIN_SIZE = 200
- """Minimum size in pixels of the image area."""
-
- # Qt signals
- valueChanged = qt.pyqtSignal(float, float, float)
- """Signals that the data value under the cursor has changed.
-
- It provides: row, column, data value.
-
- When the cursor is over an histogram, either row or column is Nan
- and the provided data value is the histogram value
- (i.e., the sum along the corresponding row/column).
- Row and columns are either Nan or integer values.
- """
-
- def __init__(self, parent=None, windowFlags=qt.Qt.Widget, backend=None):
- self._imageLegend = '__ImageView__image' + str(id(self))
- self._cache = None # Store currently visible data information
- self._updatingLimits = False
-
- super(ImageView, self).__init__(parent, windowFlags)
- self.setStyleSheet('background-color: white;')
- self._initWidgets(backend)
-
- # Sync PlotBackend and ImageView
- self._updateYAxisInverted()
-
- # Set-up focus proxy to handle arrow key event
- self.setFocusProxy(self._imagePlot)
-
- def _initWidgets(self, backend):
- """Set-up layout and plots."""
- # Monkey-patch for histogram size
- # alternative: create a layout that does not use widget size hints
- def sizeHint():
- return qt.QSize(self.HISTOGRAMS_HEIGHT, self.HISTOGRAMS_HEIGHT)
-
- self._histoHPlot = Plot.Plot(backend=backend)
- self._histoHPlot.setZoomModeEnabled(True)
- self._histoHPlot.setCallback(self._histoHPlotCB)
- self._histoHPlot.getWidgetHandle().sizeHint = sizeHint
- self._histoHPlot.getWidgetHandle().minimumSizeHint = sizeHint
-
- self._imagePlot = PlotWindow(backend=backend, plugins=False,
- colormap=True, flip=True,
- grid=False, togglePoints=False,
- logx=False, logy=False,
- aspect=True)
- self._imagePlot.usePlotBackendColormap = True
- self._imagePlot.setPanWithArrowKeys(True)
-
- self._imagePlot.setZoomModeEnabled(True) # Color is set in setColormap
- self._imagePlot.sigPlotSignal.connect(self._imagePlotCB)
- self._imagePlot.hFlipToolButton.clicked.connect(
- self._updateYAxisInverted)
- self._imagePlot.sigColormapChangedSignal.connect(self.setColormap)
-
- self._histoVPlot = Plot.Plot(backend=backend)
- self._histoVPlot.setZoomModeEnabled(True)
- self._histoVPlot.setCallback(self._histoVPlotCB)
- self._histoVPlot.getWidgetHandle().sizeHint = sizeHint
- self._histoVPlot.getWidgetHandle().minimumSizeHint = sizeHint
-
- self._radarView = RadarView()
- self._radarView.visibleRectDragged.connect(self._radarViewCB)
-
- self._layout = qt.QGridLayout()
- self._layout.addWidget(self._imagePlot, 0, 0)
- self._layout.addWidget(self._histoVPlot.getWidgetHandle(), 0, 1)
- self._layout.addWidget(self._histoHPlot.getWidgetHandle(), 1, 0)
- self._layout.addWidget(self._radarView, 1, 1)
-
- self._layout.setColumnMinimumWidth(0, self.IMAGE_MIN_SIZE)
- self._layout.setColumnStretch(0, 1)
- self._layout.setColumnMinimumWidth(1, self.HISTOGRAMS_HEIGHT)
- self._layout.setColumnStretch(1, 0)
-
- self._layout.setRowMinimumHeight(0, self.IMAGE_MIN_SIZE)
- self._layout.setRowStretch(0, 1)
- self._layout.setRowMinimumHeight(1, self.HISTOGRAMS_HEIGHT)
- self._layout.setRowStretch(1, 0)
-
- self._layout.setSpacing(0)
- self._layout.setContentsMargins(0, 0, 0, 0)
-
- self.setLayout(self._layout)
-
- def _dirtyCache(self):
- self._cache = None
-
- def _updateHistograms(self):
- """Update histograms content using current active image."""
- activeImage = self._imagePlot.getActiveImage()
- if activeImage is not None:
- wasUpdatingLimits = self._updatingLimits
- self._updatingLimits = True
-
- data, legend, info, pixmap = activeImage
- xScale, yScale = info['plot_xScale'], info['plot_yScale']
- height, width = data.shape
-
- xMin, xMax = self._imagePlot.getGraphXLimits()
- yMin, yMax = self._imagePlot.getGraphYLimits()
-
- # Convert plot area limits to image coordinates
- # and work in image coordinates (i.e., in pixels)
- xMin = int((xMin - xScale[0]) / xScale[1])
- xMax = int((xMax - xScale[0]) / xScale[1])
- yMin = int((yMin - yScale[0]) / yScale[1])
- yMax = int((yMax - yScale[0]) / yScale[1])
-
- if (xMin < width and xMax >= 0 and
- yMin < height and yMax >= 0):
- # The image is at least partly in the plot area
- # Get the visible bounds in image coords (i.e., in pixels)
- subsetXMin = 0 if xMin < 0 else xMin
- subsetXMax = (width if xMax >= width else xMax) + 1
- subsetYMin = 0 if yMin < 0 else yMin
- subsetYMax = (height if yMax >= height else yMax) + 1
-
- if (self._cache is None or
- subsetXMin != self._cache['dataXMin'] or
- subsetXMax != self._cache['dataXMax'] or
- subsetYMin != self._cache['dataYMin'] or
- subsetYMax != self._cache['dataYMax']):
- # The visible area of data has changed, update histograms
-
- # Rebuild histograms for visible area
- visibleData = data[subsetYMin:subsetYMax,
- subsetXMin:subsetXMax]
- histoHVisibleData = np.sum(visibleData, axis=0)
- histoVVisibleData = np.sum(visibleData, axis=1)
-
- self._cache = {
- 'dataXMin': subsetXMin,
- 'dataXMax': subsetXMax,
- 'dataYMin': subsetYMin,
- 'dataYMax': subsetYMax,
-
- 'histoH': histoHVisibleData,
- 'histoHMin': np.min(histoHVisibleData),
- 'histoHMax': np.max(histoHVisibleData),
-
- 'histoV': histoVVisibleData,
- 'histoVMin': np.min(histoVVisibleData),
- 'histoVMax': np.max(histoVVisibleData)
- }
-
- # Convert to histogram curve and update plots
- # Taking into account origin and scale
- coords = np.arange(2 * histoHVisibleData.size)
- xCoords = (coords + 1) // 2 + subsetXMin
- xCoords = xScale[0] + xScale[1] * xCoords
- xData = np.take(histoHVisibleData, coords // 2)
- self._histoHPlot.addCurve(xCoords, xData,
- xlabel='', ylabel='',
- replace=False, replot=False,
- color=self.HISTOGRAMS_COLOR,
- linestyle='-',
- selectable=False)
- vMin = self._cache['histoHMin']
- vMax = self._cache['histoHMax']
- vOffset = 0.1 * (vMax - vMin)
- if vOffset == 0.:
- vOffset = 1.
- self._histoHPlot.setGraphYLimits(vMin - vOffset,
- vMax + vOffset)
-
- coords = np.arange(2 * histoVVisibleData.size)
- yCoords = (coords + 1) // 2 + subsetYMin
- yCoords = yScale[0] + yScale[1] * yCoords
- yData = np.take(histoVVisibleData, coords // 2)
- self._histoVPlot.addCurve(yData, yCoords,
- xlabel='', ylabel='',
- replace=False, replot=False,
- color=self.HISTOGRAMS_COLOR,
- linestyle='-',
- selectable=False)
- vMin = self._cache['histoVMin']
- vMax = self._cache['histoVMax']
- vOffset = 0.1 * (vMax - vMin)
- if vOffset == 0.:
- vOffset = 1.
- self._histoVPlot.setGraphXLimits(vMin - vOffset,
- vMax + vOffset)
- else:
- self._dirtyCache()
- self._histoHPlot.clearCurves()
- self._histoVPlot.clearCurves()
+from silx.gui.plot.ImageView import ImageView as SilxImageView
+from silx.gui.plot.ImageView import ImageViewMainWindow as SilxImageViewMainWindow
- self._updatingLimits = wasUpdatingLimits
- def _updateRadarView(self):
- """Update radar view visible area.
+_logger = logging.getLogger(__name__)
+_logger.warning("%s is deprecated, you are advised to use "
+ "silx.gui.plot.ImageView instead",
+ __name__)
+for line in traceback.format_stack(limit=3):
+ _logger.warning(line.rstrip())
- Takes care of y coordinate conversion.
- """
- xMin, xMax = self._imagePlot.getGraphXLimits()
- yMin, yMax = self._imagePlot.getGraphYLimits()
- self._radarView.setVisibleRect(xMin, yMin, xMax - xMin, yMax - yMin)
-
- # Plots event listeners
-
- def _imagePlotCB(self, eventDict):
- """Callback for imageView plot events."""
- if eventDict['event'] == 'mouseMoved':
- activeImage = self._imagePlot.getActiveImage()
- if activeImage is not None:
- data = activeImage[0]
- height, width = data.shape
- x, y = int(eventDict['x']), int(eventDict['y'])
- if x >= 0 and x < width and y >= 0 and y < height:
- self.valueChanged.emit(float(x), float(y),
- data[y][x])
- elif eventDict['event'] == 'limitsChanged':
- # Do not handle histograms limitsChanged while
- # updating their limits from here.
- self._updatingLimits = True
-
- # Refresh histograms
- self._updateHistograms()
-
- # could use eventDict['xdata'], eventDict['ydata'] instead
- xMin, xMax = self._imagePlot.getGraphXLimits()
- yMin, yMax = self._imagePlot.getGraphYLimits()
-
- # Set horizontal histo limits
- self._histoHPlot.setGraphXLimits(xMin, xMax)
- self._histoHPlot.replot()
-
- # Set vertical histo limits
- self._histoVPlot.setGraphYLimits(yMin, yMax)
- self._histoVPlot.replot()
-
- self._updateRadarView()
-
- self._updatingLimits = False
-
- # Replot in case limitsChanged due to set*Limits
- # called from console.
- # This results in an extra replot call in other cases.
- self._imagePlot.replot()
-
- def _histoHPlotCB(self, eventDict):
- """Callback for horizontal histogram plot events."""
- if eventDict['event'] == 'mouseMoved':
- if self._cache is not None:
- activeImage = self._imagePlot.getActiveImage()
- if activeImage is not None:
- xOrigin, xScaleFactor = activeImage[2]['plot_xScale']
-
- minValue = xOrigin + xScaleFactor * self._cache['dataXMin']
- data = self._cache['histoH']
- width = data.shape[0]
- x = int(eventDict['x'])
- if x >= minValue and x < minValue + width:
- self.valueChanged.emit(float('nan'), float(x),
- data[x - minValue])
- elif eventDict['event'] == 'limitsChanged':
- if (not self._updatingLimits and
- eventDict['xdata'] != self._imagePlot.getGraphXLimits()):
- xMin, xMax = eventDict['xdata']
- self._imagePlot.setGraphXLimits(xMin, xMax)
- self._imagePlot.replot()
-
- def _histoVPlotCB(self, eventDict):
- """Callback for vertical histogram plot events."""
- if eventDict['event'] == 'mouseMoved':
- if self._cache is not None:
- activeImage = self._imagePlot.getActiveImage()
- if activeImage is not None:
- yOrigin, yScaleFactor = activeImage[2]['plot_yScale']
-
- minValue = yOrigin + yScaleFactor * self._cache['dataYMin']
- data = self._cache['histoV']
- height = data.shape[0]
- y = int(eventDict['y'])
- if y >= minValue and y < minValue + height:
- self.valueChanged.emit(float(y), float('nan'),
- data[y - minValue])
- elif eventDict['event'] == 'limitsChanged':
- if (not self._updatingLimits and
- eventDict['ydata'] != self._imagePlot.getGraphYLimits()):
- yMin, yMax = eventDict['ydata']
- self._imagePlot.setGraphYLimits(yMin, yMax)
- self._imagePlot.replot()
-
- def _radarViewCB(self, left, top, width, height):
- """Slot for radar view visible rectangle changes."""
- if not self._updatingLimits:
- # Takes care of Y axis conversion
- self._imagePlot.setLimits(left, left + width, top, top + height)
- self._imagePlot.replot()
-
- def _updateYAxisInverted(self):
- """Sync image, vertical histogram and radar view axis orientation."""
- inverted = self._imagePlot.isYAxisInverted()
-
- self._imagePlot.invertYAxis(inverted)
- self._histoVPlot.invertYAxis(inverted)
-
- # Use scale to invert radarView
- # RadarView default Y direction is from top to bottom
- # As opposed to Plot. So invert RadarView when Plot is NOT inverted.
- self._radarView.resetTransform()
- if not inverted:
- self._radarView.scale(1., -1.)
- self._updateRadarView()
-
- self._imagePlot.replot()
- self._histoVPlot.replot()
- self._radarView.update()
-
- def getHistogram(self, axis):
- """Return the histogram and corresponding row or column extent.
-
- The returned value when an histogram is available is a dict with keys:
-
- - 'data': numpy array of the histogram values.
- - 'extent': (start, end) row or column index.
- end index is not included in the histogram.
- :param str axis: 'x' for horizontal, 'y' for vertical
- :return: The histogram and its extent as a dict or None.
- :rtype: dict
+class ImageView(SilxImageView):
+ def __init__(self, parent=None, windowFlags=None, backend=None):
"""
- assert axis in ('x', 'y')
- if self._cache is None:
- return None
- else:
- if axis == 'x':
- return dict(
- data=np.array(self._cache['histoH'], copy=True),
- extent=(self._cache['dataXMin'], self._cache['dataXMax']))
- else:
- return dict(
- data=np.array(self._cache['histoV'], copy=True),
- extent=(self._cache['dataYMin'], self._cache['dataYMax']))
- def radarView(self):
- """Get the lower right radarView widget."""
- return self._radarView
-
- def setRadarView(self, radarView):
- """Change the lower right radarView widget.
-
- :param RadarView radarView: Widget subclassing RadarView to replace
- the lower right corner widget.
- """
- self._radarView.visibleRectDragged.disconnect(self._radarViewCB)
- self._radarView = radarView
- self._radarView.visibleRectDragged.connect(self._radarViewCB)
- self._layout.addWidget(self._radarView, 1, 1)
-
- self._updateYAxisInverted()
-
- # PlotWindow toolbar
-
- def toolBar(self):
- """Returns the tool bar associated with the image plot.
-
- This is the toolBar provided by :class:`PlotWindow`.
-
- :return: The toolBar associated to the image plot.
- :rtype: QToolBar
- """
- return self._imagePlot.toolBar
-
- # High-level API
-
- def getColormap(self):
- """Get the default colormap description.
-
- :return: A description of the current colormap.
- See :meth:`setColormap` for details.
- :rtype: dict
+ :param parent:
+ :param windowFlags: windowFlags (e.g. qt.Qt.Widget, qt.Qt.Window...)
+ If None, the silx default behavior is used: behave as a widget if
+ parent is not None, else behave as a Window.
+ :param backend:
"""
- return self._imagePlot.getDefaultColormap()
-
- def setColormap(self, colormap=None, normalization=None,
- autoscale=None, vmin=None, vmax=None, colors=256):
- """Set the default colormap and update active image.
-
- Parameters that are not provided are taken from the current colormap.
-
- The colormap parameter can also be a dict with the following keys:
-
- - *name*: string. The colormap to use:
- 'gray', 'reversed gray', 'temperature', 'red', 'green', 'blue'.
- - *normalization*: string. The mapping to use for the colormap:
- either 'linear' or 'log'.
- - *autoscale*: bool. Whether to use autoscale (True)
- or range provided by keys 'vmin' and 'vmax' (False).
- - *vmin*: float. The minimum value of the range to use if 'autoscale'
- is False.
- - *vmax*: float. The maximum value of the range to use if 'autoscale'
- is False.
-
- :param colormap: Name of the colormap in
- 'gray', 'reversed gray', 'temperature', 'red', 'green', 'blue'.
- Or the description of the colormap as a dict.
- :type colormap: dict or str.
- :param str normalization: Colormap mapping: 'linear' or 'log'.
- :param bool autoscale: Whether to use autoscale (True)
- or [vmin, vmax] range (False).
- :param float vmin: The minimum value of the range to use if
- 'autoscale' is False.
- :param float vmax: The maximum value of the range to use if
- 'autoscale' is False.
- """
- cmapDict = self._imagePlot.getDefaultColormap()
-
- if isinstance(colormap, dict):
- # Support colormap parameter as a dict
- assert normalization is None
- assert autoscale is None
- assert vmin is None
- assert vmax is None
- assert colors == 256
- for key, value in colormap.items():
- cmapDict[key] = value
-
- else:
- if colormap is not None:
- cmapDict['name'] = colormap
- if normalization is not None:
- cmapDict['normalization'] = normalization
- if autoscale is not None:
- cmapDict['autoscale'] = autoscale
- if vmin is not None:
- cmapDict['vmin'] = vmin
- if vmax is not None:
- cmapDict['vmax'] = vmax
-
- if 'colors' not in cmapDict:
- cmapDict['colors'] = 256
-
- cursorColor = _cursorColorForColormap(cmapDict['name'])
- self._imagePlot.setZoomModeEnabled(True, color=cursorColor)
+ super(ImageView, self).__init__(parent=parent, backend=backend)
- self._imagePlot.setDefaultColormap(cmapDict)
+ # SilxImageView does not have a windowFlags parameter.
+ # A silx PlotWidget behaves as a Widget if parent is not None,
+ # else it behaves as a QMainWindow.
+ if windowFlags is not None:
+ self.setWindowFlags(windowFlags)
- activeImage = self._imagePlot.getActiveImage()
- if activeImage is not None: # Refresh image with new colormap
- data, legend, info, pixmap = activeImage
-
- self._imagePlot.addImage(data, legend=legend, info=info,
- colormap=self.getColormap(),
- replace=False, replot=False)
- self._imagePlot.replot()
-
- def setImage(self, image, origin=(0, 0), scale=(1., 1.),
- copy=True, reset=True):
- """Set the image to display.
-
- :param image: A 2D array representing the image or None to empty plot.
- :type image: numpy.ndarray-like with 2 dimensions or None.
- :param origin: The (x, y) position of the origin of the image.
- Default: (0, 0).
- The origin is the lower left corner of the image when
- the Y axis is not inverted.
- :type origin: Tuple of 2 floats: (origin x, origin y).
- :param scale: The scale factor to apply to the image on X and Y axes.
- Default: (1, 1).
- It is the size of a pixel in the coordinates of the axes.
- Scales must be positive numbers.
- :type scale: Tuple of 2 floats: (scale x, scale y).
- :param bool copy: Whether to copy image data (default) or not.
- :param bool reset: Whether to reset zoom and ROI (default) or not.
- """
- self._dirtyCache()
-
- assert len(origin) == 2
- assert len(scale) == 2
- assert scale[0] > 0
- assert scale[1] > 0
-
- if image is None:
- self._imagePlot.removeImage(self._imageLegend, replot=False)
- return
-
- data = np.array(image, order='C', copy=copy)
- assert data.size != 0
- assert len(data.shape) == 2
- height, width = data.shape
-
- self._imagePlot.addImage(data,
- legend=self._imageLegend,
- xScale=(origin[0], scale[0]),
- yScale=(origin[1], scale[1]),
- colormap=self.getColormap(),
- replace=False,
- replot=False)
- self._imagePlot.setActiveImage(self._imageLegend)
- self._updateHistograms()
-
- self._radarView.setDataRect(origin[0],
- origin[1],
- width * scale[0],
- height * scale[1])
-
- if reset:
- self.resetZoom()
- else:
- self._histoHPlot.replot()
- self._histoVPlot.replot()
- self._imagePlot.replot()
-
- ####################
- # Plot API proxies #
- ####################
-
- # Rebuild side histograms if active image gets changed through the Plot API
-
- def addImage(self, data, legend=None, info=None,
- replace=True, replot=True,
- xScale=None, yScale=None, z=0,
- selectable=False, draggable=False,
- colormap=None, **kw):
- if legend == self._imagePlot.getActiveImage(just_legend=True):
- # Updating active image, resets side histograms cache
- self._dirtyCache()
-
- result = self._imagePlot.addImage(data, legend, info, replace, replot,
- xScale, yScale, z,
- selectable, draggable,
- colormap, **kw)
- self._updateHistograms()
-
- if replot:
- self._histoHPlot.replot()
- self._histoVPlot.replot()
-
- return result
-
- def clear(self):
- self._dirtyCache()
- return self._imagePlot.clear()
-
- def clearImages(self):
- self._dirtyCache()
- return self._imagePlot.clearImages()
-
- def removeImage(self, legend, replot=True):
- if legend == self._imagePlot.getActiveImage(just_legend=True):
- # Removing active image, resets side histograms cache
- self._dirtyCache()
-
- result = self._imageView.removeImage(legend, replot)
- self._updateHistograms()
-
- if replot:
- self._histoHPlot.replot()
- self._histoVPlot.replot()
-
- return result
-
- def setActiveImage(self, legend, replot=True):
- # Active image changes, resets side histogram cache
- self._dirtyCache()
-
- result = self._imagePlot.setActiveImage(legend, replot)
- self._updateHistograms()
-
- if replot:
- self._histoHPlot.replot()
- self._histoVPlot.replot()
- return result
-
- # Invert axes
-
- def invertYAxis(self, flag=True):
- result = self._imagePlot.invertYAxis(flag)
- self._updateYAxisInverted() # To sync vert. histo and radar view
- return result
-
- # Ugly yet simple proxy for the Plot API
-
- def __getattr__(self, name):
- """Proxy to expose image plot API."""
- return getattr(self._imagePlot, name)
-
-
-# ImageViewMainWindow #########################################################
-
-class ImageViewMainWindow(qt.QMainWindow):
- """QMainWindow embedding an ImageView.
-
- Surrounds the ImageView with an associated toolbar and status bar.
- """
+class ImageViewMainWindow(SilxImageViewMainWindow):
def __init__(self, parent=None, windowFlags=qt.Qt.Widget, backend=None):
- self._dataInfo = None
- super(ImageViewMainWindow, self).__init__(parent, windowFlags)
-
- # Create the ImageView widget and add it to the QMainWindow
- self.imageView = ImageView(backend=backend)
- self.imageView.setGraphXLabel('X')
- self.imageView.setGraphYLabel('Y')
- self.imageView.setGraphTitle('Image')
- self.imageView._imagePlot.sigColormapChangedSignal.connect(
- self._colormapUpdated)
- self.setCentralWidget(self.imageView)
-
- # Using PlotWindow's toolbar
- self.addToolBar(self.imageView.toolBar())
- self.profileToolBar = ProfileToolBar(self.imageView._imagePlot)
- self.addToolBar(self.profileToolBar)
- self.addToolBar(qt.Qt.BottomToolBarArea, LimitsToolBar(self.imageView))
-
- self.statusBar()
-
- # Connect to ImageView's signal
- self.imageView.valueChanged.connect(self._statusBarSlot)
-
- def _colormapUpdated(self, colormap):
- """Sync ROI color with current colormap"""
- self.profileToolBar.overlayColor = _cursorColorForColormap(
- colormap['name'])
-
- def _statusBarSlot(self, row, column, value):
- """Update status bar with coordinates/value from plots."""
- if np.isnan(row):
- msg = 'Column: %d, Sum: %g' % (int(column), value)
- elif np.isnan(column):
- msg = 'Row: %d, Sum: %g' % (int(row), value)
- else:
- msg = 'Position: (%d, %d), Value: %g' % (int(row), int(column),
- value)
- if self._dataInfo is not None:
- msg = self._dataInfo + ', ' + msg
-
- self.statusBar().showMessage(msg)
-
- def setImage(self, image, *args, **kwargs):
- """Set the displayed image.
-
- See :meth:`ImageView.setImage` for details.
- """
- if hasattr(image, 'dtype') and hasattr(image, 'shape'):
- assert len(image.shape) == 2
- height, width = image.shape
- self._dataInfo = 'Data: %dx%d (%s)' % (width, height,
- str(image.dtype))
- self.statusBar().showMessage(self._dataInfo)
- else:
- self._dataInfo = None
+ super(ImageViewMainWindow, self).__init__(parent, backend)
+ if windowFlags is not None:
+ self.setWindowFlags(windowFlags)
- # Set the new image in ImageView widget
- self.imageView.setImage(image, *args, **kwargs)
- self.profileToolBar.updateProfile()
- self.setStatusBar(None)
# main ########################################################################
diff --git a/PyMca5/PyMcaGui/plotting/MaskImageTools.py b/PyMca5/PyMcaGui/plotting/MaskImageTools.py
index 61466f7..5c6394f 100644
--- a/PyMca5/PyMcaGui/plotting/MaskImageTools.py
+++ b/PyMca5/PyMcaGui/plotting/MaskImageTools.py
@@ -30,8 +30,6 @@ __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
__doc__ = """
Common tools to deal with common graphics operations on images.
"""
-import sys
-import os
import numpy
from PyMca5 import spslut
@@ -253,9 +251,9 @@ def applyMaskToImage(pixmap, mask=None, colors=None, copy=True):
if __name__ == "__main__":
from PyMca5.PyMcaGui import PyMcaQt as qt
- from PyMca5.PyMcaGui import PlotWidget
+ from silx.gui.plot import PlotWidget
app = qt.QApplication([])
- w = PlotWidget.PlotWidget()
+ w = PlotWidget()
data = numpy.arange(10000.).reshape(100, 100)
mask = numpy.zeros(data.shape, dtype=numpy.uint8)
mask[25:75, 25:75] = 1
diff --git a/PyMca5/PyMcaGui/plotting/MaskImageWidget.py b/PyMca5/PyMcaGui/plotting/MaskImageWidget.py
index 5116c8b..5be6bae 100644
--- a/PyMca5/PyMcaGui/plotting/MaskImageWidget.py
+++ b/PyMca5/PyMcaGui/plotting/MaskImageWidget.py
@@ -30,6 +30,7 @@ __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import os
import numpy
+import logging
from PyMca5.PyMcaGraph.ctools import pnpoly
from . import RGBCorrelatorGraph
from . import ColormapDialog
@@ -61,7 +62,8 @@ OVERLAY_DRAW = True
DEFAULT_COLORMAP_INDEX = 2
DEFAULT_COLORMAP_LOG_FLAG = False
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
USE_PICKER = False
@@ -85,7 +87,6 @@ class MaskImageWidget(qt.QWidget):
self.setMaximumWidth(int(screenWidth)-5)
self.setMinimumWidth(min(int(0.5*screenWidth),800))
- self._y1AxisInverted = False
self.__selectionMask = None
self._selectionColors = None
self.__imageData = None
@@ -185,13 +186,12 @@ class MaskImageWidget(qt.QWidget):
self.buildStandaloneSaveMenu()
self.graphWidget.zoomResetToolButton.clicked.connect(self._zoomResetSignal)
- self.graphWidget.graph.setDrawModeEnabled(False)
- self.graphWidget.graph.setZoomModeEnabled(True)
+ self.graphWidget.graph.setInteractiveMode('zoom')
if self.__selectionFlag:
if self.__imageIconsFlag:
self.setSelectionMode(False)
self._toggleSelectionMode()
- self.graphWidget.graph.setDrawModeEnabled(True,
+ self.graphWidget.graph.setInteractiveMode('draw',
shape="rectangle",
label="mask")
else:
@@ -323,9 +323,8 @@ class MaskImageWidget(qt.QWidget):
self._profileSignalSlot(ddict)
def _profileSignalSlot(self, ddict):
- if DEBUG:
- print("_profileSignalSLot, event = %s" % ddict['event'])
- print("Received ddict = ", ddict)
+ _logger.debug("_profileSignalSLot, event = %s", ddict['event'])
+ _logger.debug("Received ddict = %s", ddict)
if ddict['event'] in [None, "NONE"]:
#Nothing to be made
@@ -333,10 +332,10 @@ class MaskImageWidget(qt.QWidget):
if ddict['event'] == "profileWidthChanged":
if self.__lastOverlayLegend is not None:
- legend = self.__lastOverlayLegend
- #TODO: Find a better way to deal with this
- if legend in self.graphWidget.graph._itemDict:
- info = self.graphWidget.graph._itemDict[legend]['info']
+ shape = self.graphWidget.graph._getItem(kind='item',
+ legend=self.__lastOverlayLegend)
+ if shape is not None:
+ info = shape.getInfo(copy=False)
if info['mode'] == ddict['mode']:
newDict = {}
newDict['event'] = "updateProfile"
@@ -344,7 +343,6 @@ class MaskImageWidget(qt.QWidget):
newDict['ydata'] = info['ydata'] * 1
newDict['mode'] = info['mode'] * 1
newDict['pixelwidth'] = ddict['pixelwidth'] * 1
- info = None
#self._updateProfileCurve(newDict)
self._profileSignalSlot(newDict)
return
@@ -355,13 +353,13 @@ class MaskImageWidget(qt.QWidget):
self._profileSelectionWindow = ProfileScanWidget.ProfileScanWidget(actions=False)
else:
self._profileSelectionWindow = ProfileScanWidget.ProfileScanWidget(actions=True)
- self._profileSelectionWindow.sigAddClicked.connect( \
+ self._profileSelectionWindow.sigAddClicked.connect(
self._profileSelectionSlot)
- self._profileSelectionWindow.sigRemoveClicked.connect( \
+ self._profileSelectionWindow.sigRemoveClicked.connect(
self._profileSelectionSlot)
self._profileSelectionWindow.sigReplaceClicked.connect(
self._profileSelectionSlot)
- self._interpolate = SpecfitFuns.interpol
+ self._interpolate = SpecfitFuns.interpol
#if I do not return here and the user interacts with the graph while
#the profileSelectionWindow is not shown, I get crashes under Qt 4.5.3 and MacOS X
#when calling _getProfileCurve
@@ -376,16 +374,14 @@ class MaskImageWidget(qt.QWidget):
if curve is None:
return
xdata, ydata, legend, info = curve
- replot=True
- replace=True
idx = numpy.isfinite(ydata)
xdata = xdata[idx]
ydata = ydata[idx]
self._profileSelectionWindow.addCurve(xdata, ydata,
legend=legend,
info=info,
- replot=replot,
- replace=replace)
+ resetzoom=True,
+ replace=True)
def getGraphTitle(self):
try:
@@ -438,7 +434,7 @@ class MaskImageWidget(qt.QWidget):
if ddict['event'] == 'profileModeChanged':
if self.__lastOverlayLegend:
- self.graphWidget.graph.removeItem(self.__lastOverlayLegend, replot=True)
+ self.graphWidget.graph.removeItem(self.__lastOverlayLegend)
return
#if I show the image here it does not crash, but it is not nice because
@@ -476,13 +472,12 @@ class MaskImageWidget(qt.QWidget):
ydata = imageData[row, :]
legend = "Row = %d" % row
if overlay:
- #self.drawOverlayItem(x, y, legend=name, info=info, replot, replace)
+ #self.drawOverlayItem(x, y, legend=name, info=info, replace)
self.drawOverlayItem([0.0, shape[1], shape[1], 0.0],
[row, row, row+1, row+1],
legend=ddict['mode'],
info=ddict,
- replace=True,
- replot=True)
+ replace=True)
else:
row0 = int(int(ddict['row'][0]) - 0.5 * width)
if row0 < 0:
@@ -497,13 +492,12 @@ class MaskImageWidget(qt.QWidget):
ydata = imageData[row0:row1+1, :].sum(axis=0)
legend = "Row = %d to %d" % (row0, row1)
if overlay:
- #self.drawOverlayItem(x, y, legend=name, info=info, replot, replace)
+ #self.drawOverlayItem(x, y, legend=name, info=info, replace)
self.drawOverlayItem([0.0, 0.0, shape[1], shape[1]],
[row0, row1+1, row1+1, row0],
legend=ddict['mode'],
info=ddict,
- replace=True,
- replot=True)
+ replace=True)
xdata = numpy.arange(shape[1]).astype(numpy.float)
if self._xScale is not None:
xdata = self._xScale[0] + xdata * self._xScale[1]
@@ -519,13 +513,12 @@ class MaskImageWidget(qt.QWidget):
ydata = imageData[:, column]
legend = "Column = %d" % column
if overlay:
- #self.drawOverlayItem(x, y, legend=name, info=info, replot, replace)
+ #self.drawOverlayItem(x, y, legend=name, info=info, replace)
self.drawOverlayItem([column, column, column+1, column+1],
[0.0, shape[0], shape[0], 0.0],
legend=ddict['mode'],
info=ddict,
- replace=True,
- replot=True)
+ replace=True)
else:
col0 = int(int(ddict['column'][0]) - 0.5 * width)
if col0 < 0:
@@ -540,13 +533,12 @@ class MaskImageWidget(qt.QWidget):
ydata = imageData[:, col0:col1+1].sum(axis=1)
legend = "Col = %d to %d" % (col0, col1)
if overlay:
- #self.drawOverlayItem(x, y, legend=name, info=info, replot, replace)
+ #self.drawOverlayItem(x, y, legend=name, info=info, replace)
self.drawOverlayItem([col0, col0, col1+1, col1+1],
[0, shape[0], shape[0], 0.],
legend=ddict['mode'],
info=ddict,
- replace=True,
- replot=True)
+ replace=True)
xdata = numpy.arange(shape[0]).astype(numpy.float)
if self._yScale is not None:
xdata = self._yScale[0] + xdata * self._yScale[1]
@@ -577,8 +569,7 @@ class MaskImageWidget(qt.QWidget):
if npoints == 1:
#all points are the same
- if DEBUG:
- print("START AND END POINT ARE THE SAME!!")
+ _logger.debug("START AND END POINT ARE THE SAME!!")
return
if width < 0: # width = pixelwidth - 1
@@ -591,13 +582,12 @@ class MaskImageWidget(qt.QWidget):
xdata = numpy.arange(float(npoints))
if overlay:
- #self.drawOverlayItem(x, y, legend=name, info=info, replot, replace)
+ #self.drawOverlayItem(x, y, legend=name, info=info, replace)
self.drawOverlayItem([col0, col1],
[row0, row1],
legend=ddict['mode'],
info=ddict,
- replace=True,
- replot=True)
+ replace=True)
elif deltaCol == 0:
#vertical line
col0 = int(int(ddict['column'][0]) - 0.5 * width)
@@ -624,13 +614,12 @@ class MaskImageWidget(qt.QWidget):
npoints = max(ydata.shape)
xdata = numpy.arange(float(npoints))
if overlay:
- #self.drawOverlayItem(x, y, legend=name, info=info, replot, replace)
+ #self.drawOverlayItem(x, y, legend=name, info=info, replace)
self.drawOverlayItem([col0, col0, col1+1, col1+1],
[row0, row1+1, row1+1, row0],
legend=ddict['mode'],
info=ddict,
- replace=True,
- replot=True)
+ replace=True)
elif deltaRow == 0:
#horizontal line
row0 = int(int(ddict['row'][0]) - 0.5 * width)
@@ -657,13 +646,12 @@ class MaskImageWidget(qt.QWidget):
npoints = max(ydata.shape)
xdata = numpy.arange(float(npoints))
if overlay:
- #self.drawOverlayItem(x, y, legend=name, info=info, replot, replace)
+ #self.drawOverlayItem(x, y, legend=name, info=info, replace)
self.drawOverlayItem([col0, col0, col1+1, col1+1],
[row0, row1+1, row1+1, row0],
legend=ddict['mode'],
info=ddict,
- replace=True,
- replot=True)
+ replace=True)
else:
#restore original value of width
width = ddict['pixelwidth']
@@ -687,9 +675,8 @@ class MaskImageWidget(qt.QWidget):
newRow0 = 0.0
newRow1 = -(col1-col0) * sinalpha + (row1-row0) * cosalpha
- if DEBUG:
- print("new X0 Y0 = %f, %f " % (newCol0, newRow0))
- print("new X1 Y1 = %f, %f " % (newCol1, newRow1))
+ _logger.debug("new X0 Y0 = %f, %f ", newCol0, newRow0)
+ _logger.debug("new X1 Y1 = %f, %f ", newCol1, newRow1)
tmpX = numpy.linspace(newCol0, newCol1, npoints).astype(numpy.float)
rotMatrix = numpy.zeros((2,2), numpy.float)
@@ -697,19 +684,19 @@ class MaskImageWidget(qt.QWidget):
rotMatrix[0,1] = - sinalpha
rotMatrix[1,0] = sinalpha
rotMatrix[1,1] = cosalpha
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
#test if I recover the original points
- testX = numpy.zeros((2, 1) , numpy.float)
+ testX = numpy.zeros((2, 1), numpy.float)
colRow = numpy.dot(rotMatrix, testX)
- print("Recovered X0 = %f" % (colRow[0,0] + col0))
- print("Recovered Y0 = %f" % (colRow[1,0] + row0))
- print("It should be = %f, %f" % (col0, row0))
- testX[0,0] = newCol1
- testX[1,0] = newRow1
+ _logger.debug("Recovered X0 = %f", colRow[0, 0] + col0)
+ _logger.debug("Recovered Y0 = %f", colRow[1, 0] + row0)
+ _logger.debug("It should be = %f, %f", col0, row0)
+ testX[0, 0] = newCol1
+ testX[1, 0] = newRow1
colRow = numpy.dot(rotMatrix, testX)
- print("Recovered X1 = %f" % (colRow[0,0] + col0))
- print("Recovered Y1 = %f" % (colRow[1,0] + row0))
- print("It should be = %f, %f" % (col1, row1))
+ _logger.debug("Recovered X1 = %f", colRow[0, 0] + col0)
+ _logger.debug("Recovered Y1 = %f", colRow[1, 0] + row0)
+ _logger.debug("It should be = %f, %f", col1, row1)
#find the drawing limits
testX = numpy.zeros((2, 4) , numpy.float)
@@ -727,21 +714,18 @@ class MaskImageWidget(qt.QWidget):
for a in rowLimits0:
if (a >= shape[0]) or (a < 0):
- if DEBUG:
- print("outside row limits",a)
+ _logger.debug("outside row limits %s", a)
return
for a in colLimits0:
if (a >= shape[1]) or (a < 0):
- if DEBUG:
- print("outside column limits",a)
+ _logger.debug("outside column limits %s", a)
return
r0 = rowLimits0[0]
r1 = rowLimits0[1]
if r0 > r1:
- if DEBUG:
- print("r0 > r1", r0, r1)
+ _logger.debug("r0 > r1 %s %s", r0, r1)
raise ValueError("r0 > r1")
x = numpy.zeros((2, npoints) , numpy.float)
@@ -809,8 +793,7 @@ class MaskImageWidget(qt.QWidget):
rowLimits0,
legend=ddict['mode'],
info=ddict,
- replace=True,
- replot=True)
+ replace=True)
if self.__lineProjectionMode == 'X':
xLabel = self.getXLabel()
xdata += col0
@@ -831,8 +814,7 @@ class MaskImageWidget(qt.QWidget):
float(deltaRow) * deltaRow)/(npoints-1.0)
xdata *= deltaDistance
else:
- if DEBUG:
- print("Mode %s not supported yet" % ddict['mode'])
+ _logger.debug("Mode %s not supported yet", ddict['mode'])
return
self.__lastOverlayWidth = ddict['pixelwidth']
@@ -842,8 +824,7 @@ class MaskImageWidget(qt.QWidget):
return xdata, ydata, legend, info
def _profileSelectionSlot(self, ddict):
- if DEBUG:
- print(ddict)
+ _logger.debug("%s", ddict)
# the curves as [[x0, y0, legend0, info0], ...]
curveList = ddict['curves']
label = ddict['label']
@@ -851,25 +832,17 @@ class MaskImageWidget(qt.QWidget):
if ddict['event'] == 'ADD':
for i in range(n):
x, y, legend, info = curveList[i]
- info['profilelabel'] = label
- if i == (n-1):
- replot = True
+ resetzoom = (i == (n-1))
self._profileScanWindow.addCurve(x, y, legend=legend, info=info,
- replot=replot, replace=False)
+ resetzoom=resetzoom, replace=False)
elif ddict['event'] == 'REPLACE':
for i in range(n):
x, y, legend, info = curveList[i]
info['profilelabel'] = label
- if i in [0, n-1]:
- replace = True
- else:
- replace = False
- if i == (n-1):
- replot = True
- else:
- replot = False
+ replace = (i in [0, n-1])
+ resetzoom = (i == (n-1))
self._profileScanWindow.addCurve(x, y, legend=legend, info=info,
- replot=replot, replace=replace)
+ resetzoom=resetzoom, replace=replace)
elif ddict['event'] == 'REMOVE':
curveList = self._profileScanWindow.getAllCurves()
if curveList in [None, []]:
@@ -885,13 +858,10 @@ class MaskImageWidget(qt.QWidget):
n = len(toDelete)
for i in range(n):
legend = toDelete[i]
- if i == (n-1):
- replot = True
- else:
- replot = False
- self._profileScanWindow.removeCurve(legend, replot=replot)
+ resetzoom = (i == (n-1))
+ self._profileScanWindow.removeCurve(legend, resetzoom=resetzoom)
- def drawOverlayItem(self, x, y, legend=None, info=None, replace=False, replot=True):
+ def drawOverlayItem(self, x, y, legend=None, info=None, replace=False):
#same call as the plot1D addCurve command
if legend is None:
legend="UnnamedOverlayItem"
@@ -911,31 +881,22 @@ class MaskImageWidget(qt.QWidget):
for i in y:
yList.append(self._yScale[0] + i * self._yScale[1])
self.graphWidget.graph.addItem(xList, yList, legend=legend, info=info,
- replace=replace, replot=replot,
- shape="polygon", fill=True)
+ replace=replace, shape="polygon", fill=True)
self.__lastOverlayLegend = legend
def _hFlipIconSignal(self):
- self._y1AxisInverted = self.graphWidget.graph.isYAxisInverted()
- if self._y1AxisInverted:
- self._y1AxisInverted = False
- else:
- self._y1AxisInverted = True
- #self.graphWidget.graph.zoomReset()
- self.graphWidget.graph.invertYAxis(self._y1AxisInverted)
- self._y1AxisInverted = self.graphWidget.graph.isYAxisInverted()
- self.graphWidget.graph.replot()
+ yaxis = self.graphWidget.graph.getYAxis()
+ yaxis.setInverted(not yaxis.isInverted())
#inform the other widgets
ddict = {}
ddict['event'] = "hFlipSignal"
- ddict['current'] = self._y1AxisInverted * 1
+ ddict['current'] = yaxis.isInverted() * 1
ddict['id'] = id(self)
self.emitMaskImageSignal(ddict)
def setY1AxisInverted(self, value):
- self._y1AxisInverted = value
- self.graphWidget.graph.invertYAxis(self._y1AxisInverted)
+ self.graphWidget.graph.getYAxis().setInverted(value)
def setXLabel(self, label="Column"):
return self.graphWidget.setXLabel(label)
@@ -988,38 +949,34 @@ class MaskImageWidget(qt.QWidget):
self._replaceImageClicked)
def _setEraseSelectionMode(self):
- if DEBUG:
- print("_setEraseSelectionMode")
+ _logger.debug("_setEraseSelectionMode")
self.__eraseMode = True
self.__brushMode = True
- self.graphWidget.graph.setDrawModeEnabled(False)
+ self.graphWidget.graph.setInteractiveMode('select')
def _setRectSelectionMode(self):
- if DEBUG:
- print("_setRectSelectionMode")
+ _logger.debug("_setRectSelectionMode")
self.__eraseMode = False
self.__brushMode = False
- self.graphWidget.graph.setDrawModeEnabled(True,
+ self.graphWidget.graph.setInteractiveMode("draw",
shape="rectangle",
label="mask")
def _setPolygonSelectionMode(self):
self.__eraseMode = False
self.__brushMode = False
- self.graphWidget.graph.setDrawModeEnabled(True,
+ self.graphWidget.graph.setInteractiveMode('draw',
shape="polygon",
label="mask")
def _setBrushSelectionMode(self):
- if DEBUG:
- print("_setBrushSelectionMode")
+ _logger.debug("_setBrushSelectionMode")
self.__eraseMode = False
self.__brushMode = True
- self.graphWidget.graph.setDrawModeEnabled(False)
+ self.graphWidget.graph.setInteractiveMode('select')
def _setBrush(self):
- if DEBUG:
- print("_setBrush")
+ _logger.debug("_setBrush")
if self.__brushMenu is None:
self.__brushMenu = qt.QMenu()
self.__brushMenu.addAction(QString(" 1 Image Pixel Width"),
@@ -1055,25 +1012,25 @@ class MaskImageWidget(qt.QWidget):
self.__brushWidth = 20
def _toggleSelectionMode(self):
- drawMode = self.graphWidget.graph.getDrawMode()
- if drawMode is None:
+ mode = self.graphWidget.graph.getInteractiveMode()
+ if mode['mode'] != 'draw':
# we are not drawing anything
- if self.graphWidget.graph.isZoomModeEnabled():
+ if self.graphWidget.graph.getInteractiveMode()['mode'] == 'zoom':
# we have to pass to mask mode
self.setSelectionMode(True)
else:
# we set zoom mode and show the line icons
self.setSelectionMode(False)
- elif drawMode['label'] is not None:
- if drawMode['label'].startswith('mask'):
- #we set the zoom mode and show the line icons
+ elif mode['label'] is not None:
+ if mode['label'].startswith('mask'):
+ # we set the zoom mode and show the line icons
self.setSelectionMode(False)
else:
# we disable zoom and drawing and set mask mode
self.setSelectionMode(True)
- elif drawMode['label'] in [None]:
+ elif mode['label'] in [None]:
# we are not drawing anything
- if self.graphWidget.graph.isZoomModeEnabled():
+ if self.graphWidget.graph.getInteractiveMode()['mode'] == 'zoom':
# we have to pass to mask mode
self.setSelectionMode(True)
else:
@@ -1085,17 +1042,17 @@ class MaskImageWidget(qt.QWidget):
#if not self.__imageIconsFlag:
# mode = False
if mode:
- self.graphWidget.graph.setDrawModeEnabled(True,
- 'rectangle',
+ self.graphWidget.graph.setInteractiveMode('draw',
+ shape='rectangle',
label='mask')
- self.__brushMode = False
+ self.__brushMode = False
self.graphWidget.hideProfileSelectionIcons()
self.graphWidget.selectionToolButton.setChecked(True)
self.graphWidget.selectionToolButton.setDown(True)
self.graphWidget.showImageIcons()
else:
self.graphWidget.showProfileSelectionIcons()
- self.graphWidget.graph.setZoomModeEnabled(True)
+ self.graphWidget.graph.setInteractiveMode('zoom')
self.graphWidget.selectionToolButton.setChecked(False)
self.graphWidget.selectionToolButton.setDown(False)
self.graphWidget.hideImageIcons()
@@ -1169,8 +1126,7 @@ class MaskImageWidget(qt.QWidget):
self._resetSelection(True)
def _resetSelection(self, owncall=True):
- if DEBUG:
- print("_resetSelection")
+ _logger.debug("_resetSelection")
self.__selectionMask = None
if self.__imageData is None:
return
@@ -1210,8 +1166,8 @@ class MaskImageWidget(qt.QWidget):
if data is None:
self.__imageData = data
self.__selectionMask = None
- self.plotImage(update = True)
- self.graphWidget._zoomReset(replot=True)
+ self.plotImage(update=True)
+ self.graphWidget.graph.resetZoom()
return
else:
self.__imageData = data
@@ -1226,8 +1182,8 @@ class MaskImageWidget(qt.QWidget):
self.colormapDialog.setDisplayedMaxValue(maxData)
self.colormapDialog.setDataMinMax(minData, maxData, update=True)
else:
- self.plotImage(update = True)
- self.graphWidget._zoomReset(replot=True)
+ self.plotImage(update=True)
+ self.graphWidget.graph.resetZoom()
def getImageData(self):
return self.__imageData
@@ -1282,8 +1238,8 @@ class MaskImageWidget(qt.QWidget):
self.__pixmap0 = pixmap
if clearmask:
self.__selectionMask = None
- self.plotImage(update = True)
- self.graphWidget._zoomReset(replot=True)
+ self.plotImage(update=True)
+ self.graphWidget.graph.resetZoom()
def plotImage(self, update=True):
if self.__imageData is None:
@@ -1295,13 +1251,14 @@ class MaskImageWidget(qt.QWidget):
self.__pixmap0 = self.__pixmap.copy()
self.__applyMaskToImage()
- # replot=False as it triggers a zoom reset in Plot.py
+ origin, scale = None, None
+ if self._xScale is not None:
+ origin = (self._xScale[0], self._yScale[0])
+ scale = (self._xScale[1], self._yScale[1])
self.graphWidget.graph.addImage(self.__pixmap,
- "image",
- xScale=self._xScale,
- yScale=self._yScale,
- replot=False)
- self.graphWidget.graph.replot()
+ "image", resetzoom=False,
+ origin=origin,
+ scale=scale)
self.updateProfileSelectionWindow()
def getPixmapFromData(self):
@@ -1535,18 +1492,15 @@ class MaskImageWidget(qt.QWidget):
alteration = (1 - (0.2 * (self.__selectionMask > 0))) - \
0.1 * (self.__selectionMask == self._roiTags[self._nRoi - 1])
if self.colormap is None:
- if DEBUG:
- print("Colormap is None")
+ _logger.debug("Colormap is None")
if self.__image is not None:
if self.__image.format() == qt.QImage.Format_ARGB32:
- if DEBUG:
- print("__applyMaskToImage CASE 1")
+ _logger.debug("__applyMaskToImage CASE 1")
for i in range(4):
self.__pixmap[:,:,i] = (self.__pixmap0[:,:,i] *\
alteration).astype(numpy.uint8)
else:
- if DEBUG:
- print("__applyMaskToImage CASE 2")
+ _logger.debug("__applyMaskToImage CASE 2")
self.__pixmap = self.__pixmap0.copy()
tmp = self.__selectionMask > 0
self.__pixmap[tmp, 0] = 0x40
@@ -1559,8 +1513,7 @@ class MaskImageWidget(qt.QWidget):
self.__pixmap[roiTag, 3] = 2*0x40
else:
if self.__defaultColormap > 1:
- if DEBUG:
- print("__applyMaskToImage CASE 3")
+ _logger.debug("__applyMaskToImage CASE 3")
self.__pixmap = self.__pixmap0.copy()
for i in range(3):
self.__pixmap[:,:,i] = (self.__pixmap0[:,:,i] *\
@@ -1573,8 +1526,7 @@ class MaskImageWidget(qt.QWidget):
for i in range(3):
self.__pixmap[:,:,i] *= tmpMask
else:
- if DEBUG:
- print("__applyMaskToImage CASE 4")
+ _logger.debug("__applyMaskToImage CASE 4")
self.__pixmap = self.__pixmap0.copy()
self.__pixmap[self.__selectionMask>0,0] = 0x40
self.__pixmap[self.__selectionMask>0,2] = 0x70
@@ -1594,8 +1546,7 @@ class MaskImageWidget(qt.QWidget):
self.__pixmap[tmpMask,2] = 0xff
self.__pixmap[tmpMask,3] = 0xff
elif int(str(self.colormap[0])) > 1: #color
- if DEBUG:
- print("__applyMaskToImage CASE 5")
+ _logger.debug("__applyMaskToImage CASE 5")
for i in range(3):
self.__pixmap[:,:,i] = (self.__pixmap0[:,:,i] * alteration)
if 0:
@@ -1606,8 +1557,7 @@ class MaskImageWidget(qt.QWidget):
for i in range(3):
self.__pixmap[:,:,i] *= tmpMask
elif self._maxNRois > 1:
- if DEBUG:
- print("__applyMaskToImage CASE 6")
+ _logger.debug("__applyMaskToImage CASE 6")
tmp = 1 - (self.__selectionMask>0)
tmp2 = (self.__selectionMask == self._roiTags[self._nRoi - 1])
self.__pixmap[:, :, 2] = (0x70 * (self.__selectionMask>0) + \
@@ -1616,8 +1566,7 @@ class MaskImageWidget(qt.QWidget):
self.__pixmap[:,:, 3] = (0x40 * (self.__selectionMask>0) + 0x40 * tmp2) +\
tmp * self.__pixmap0[:,:,3]
else:
- if DEBUG:
- print("__applyMaskToImage CASE 7")
+ _logger.debug("__applyMaskToImage CASE 7")
self.__pixmap = self.__pixmap0.copy()
tmp = 1 - self.__selectionMask
self.__pixmap[:, :, 2] = (0x70 * self.__selectionMask) +\
@@ -1802,7 +1751,7 @@ class MaskImageWidget(qt.QWidget):
elif self.__pixmap0 is not None:
imageShape = self.__pixmap0.shape[0:2]
else:
- print("Cannot handle polygon mask")
+ _logger.warning("Cannot handle polygon mask")
return
x = self._xScale[0] + self._xScale[1] * numpy.arange(imageShape[1])
y = self._yScale[0] + self._yScale[1] * numpy.arange(imageShape[0])
@@ -1888,8 +1837,7 @@ class MaskImageWidget(qt.QWidget):
if ownsignal:
pass
if None in [ddict['x'], ddict['y']]:
- if DEBUG:
- print("Signal from outside region", ddict)
+ _logger.debug("Signal from outside region %s", ddict)
return
if self.graphWidget.infoWidget.isHidden() or self.__brushMode:
@@ -1948,7 +1896,7 @@ class MaskImageWidget(qt.QWidget):
self.setMouseText("%g, %g, %g" % (x, y, self.__imageData[row, column]))
if self.__brushMode:
- if self.graphWidget.graph.isZoomModeEnabled():
+ if self.graphWidget.graph.getInteractiveMode()['mode'] == 'zoom':
return
if ddict['button'] != "left":
return
@@ -1982,9 +1930,8 @@ class MaskImageWidget(qt.QWidget):
self.sigMaskImageWidgetSignal.emit(ddict)
def _zoomResetSignal(self):
- if DEBUG:
- print("_zoomResetSignal")
- self.graphWidget._zoomReset(replot=False)
+ _logger.debug("_zoomResetSignal")
+ self.graphWidget.graph.resetZoom()
self.plotImage(True)
def getOutputFileName(self):
@@ -1996,7 +1943,8 @@ class MaskImageWidget(qt.QWidget):
filedialog.setFileMode(filedialog.AnyFile)
filedialog.setAcceptMode(qt.QFileDialog.AcceptSave)
filedialog.setWindowIcon(qt.QIcon(qt.QPixmap(IconDict["gioconda16"])))
- formatlist = ["ASCII Files *.dat",
+ formatlist = ["TIFF Files *.tif",
+ "ASCII Files *.dat",
"EDF Files *.edf",
'CSV(, separated) Files *.csv',
'CSV(; separated) Files *.csv',
@@ -2008,7 +1956,7 @@ class MaskImageWidget(qt.QWidget):
for f in formatlist:
strlist.append(f)
if self._saveFilter is None:
- self._saveFilter =formatlist[0]
+ self._saveFilter = formatlist[0]
if hasattr(filedialog, "setFilters"):
filedialog.setFilters(strlist)
filedialog.selectFilter(self._saveFilter)
@@ -2027,12 +1975,12 @@ class MaskImageWidget(qt.QWidget):
self._saveFilter = qt.safe_str(filedialog.selectedFilter())
else:
self._saveFilter = qt.safe_str(filedialog.selectedNameFilter())
- filterused = "."+self._saveFilter[-3:]
+ filterused = "." + self._saveFilter[-3:]
PyMcaDirs.outputDir = os.path.dirname(filename)
if len(filename) < 4:
- filename = filename+ filterused
+ filename = filename + filterused
elif filename[-4:] != filterused :
- filename = filename+ filterused
+ filename = filename + filterused
else:
filename = ""
return filename
@@ -2063,10 +2011,15 @@ class MaskImageWidget(qt.QWidget):
return
if filename is None:
filename = self.getOutputFileName()
- if not len(filename):return
+ if not len(filename):
+ return
if filename.lower().endswith(".edf"):
ArraySave.save2DArrayListAsEDF(imageList, filename, labels)
+ elif filename.lower().endswith(".tif"):
+ ArraySave.save2DArrayListAsMonochromaticTiff(imageList,
+ filename,
+ labels)
elif filename.lower().endswith(".csv"):
if "," in self._saveFilter:
csvseparator = ","
diff --git a/PyMca5/PyMcaGui/plotting/MaskScatterWidget.py b/PyMca5/PyMcaGui/plotting/MaskScatterWidget.py
index d9ece40..09fff5c 100644
--- a/PyMca5/PyMcaGui/plotting/MaskScatterWidget.py
+++ b/PyMca5/PyMcaGui/plotting/MaskScatterWidget.py
@@ -37,70 +37,109 @@ ___doc__ = """
- Final layer containing the selected points with the selected colors.
"""
-import sys
-import os
import numpy
+import logging
from PyMca5.PyMcaGraph.ctools import pnpoly
-DEBUG = 0
+_logger = logging.getLogger(__name__)
-from . import PlotWindow
from . import MaskImageWidget
from . import MaskImageTools
-qt = PlotWindow.qt
+from PyMca5.PyMcaGui import PyMcaQt as qt
+from .MaskToolBar import MaskToolBar
+from . import ColormapDialog
+from .PyMca_Icons import IconDict
+
+from silx.gui.plot import PlotWindow
+
if hasattr(qt, "QString"):
QString = qt.QString
else:
QString = qt.safe_str
-IconDict = PlotWindow.IconDict
-class MaskScatterWidget(PlotWindow.PlotWindow):
+
+class MaskScatterWidget(PlotWindow):
sigMaskScatterWidgetSignal = qt.pyqtSignal(object)
DEFAULT_COLORMAP_INDEX = 2
DEFAULT_COLORMAP_LOG_FLAG = True
- def __init__(self, parent=None, backend=None, plugins=False, newplot=False,
- control=False, position=False, maxNRois=1, grid=False,
- logx=False, logy=False, togglePoints=False, normal=True,
- polygon=True, colormap=True, aspect=True,
- imageIcons=True, bins=None, **kw):
+ def __init__(self, parent=None, backend=None, control=False,
+ position=False, maxNRois=1, grid=False, logScale=False,
+ curveStyle=False, resetzoom=True,
+ aspectRatio=True, imageIcons=True, polygon=True, bins=None):
super(MaskScatterWidget, self).__init__(parent=parent,
backend=backend,
- plugins=plugins,
- newplot=newplot,
control=control,
position=position,
grid=grid,
- logx=logx,
- logy=logy,
- togglePoints=togglePoints,
- normal=normal,
- aspect=aspect,
- colormap=colormap,
- imageIcons=imageIcons,
- polygon=polygon,
- **kw)
- self._buildAdditionalSelectionMenuDict()
+ logScale=logScale,
+ curveStyle=curveStyle,
+ resetzoom=resetzoom,
+ aspectRatio=aspectRatio,
+ colormap=False,
+ mask=False,
+ yInverted=False,
+ roi=False,
+ copy=True,
+ print_=False)
+ if parent is None:
+ self.setWindowTitle("MaskScatterWidget")
+ self.setActiveCurveHandling(False)
+
+ # No context menu by default, execute zoomBack on right click
+ plotArea = self.getWidgetHandle()
+ plotArea.setContextMenuPolicy(qt.Qt.CustomContextMenu)
+ plotArea.customContextMenuRequested.connect(self._zoomBack)
+
+ self.colormapIcon = qt.QIcon(qt.QPixmap(IconDict["colormap"]))
+ self.colormapToolButton = qt.QToolButton(self.toolBar())
+ self.colormapToolButton.setIcon(self.colormapIcon)
+ self.colormapToolButton.setToolTip('Change Colormap')
+ self.colormapToolButton.clicked.connect(self._colormapIconSignal)
+ self.colormapAction = self.toolBar().insertWidget(self.getSaveAction(),
+ self.colormapToolButton)
+
+ self.maskToolBar = None
+ if polygon or imageIcons:
+ self.maskToolBar = MaskToolBar(parent=self,
+ plot=self,
+ imageIcons=imageIcons,
+ polygon=polygon)
+ self.addToolBar(self.maskToolBar)
+
self._selectionCurve = None
self._selectionMask = None
- self._selectionColors = numpy.zeros((len(self.colorList), 4), numpy.uint8)
self._alphaLevel = None
- for i in range(len(self.colorList)):
- self._selectionColors[i, 0] = eval("0x" + self.colorList[i][-2:])
- self._selectionColors[i, 1] = eval("0x" + self.colorList[i][3:-2])
- self._selectionColors[i, 2] = eval("0x" + self.colorList[i][1:3])
- self._selectionColors[i, 3] = 0xff
+ self._xScale = None
+ self._yScale = None
+
self._maxNRois = maxNRois
self._nRoi = 1
self._zoomMode = True
self._eraseMode = False
self._brushMode = False
self._brushWidth = 5
- self._brushMenu = None
self._bins = bins
self._densityPlotWidget = None
self._pixmap = None
+ self._imageData = None
+ self.colormapDialog = None
+ self.colormap = None
self.setPlotViewMode("scatter", bins=bins)
- self.setDrawModeEnabled(False)
+
+ def _colormapIconSignal(self):
+ image = self.getActiveImage()
+ if image is None:
+ return
+
+ if hasattr(image, "getColormap"):
+ if self.colormapDialog is None:
+ self._initColormapDialog(image.getData(),
+ image.getColormap()._toDict())
+ self.colormapDialog.show()
+ else:
+ # RGBA image
+ _logger.info("No colormap to be handled")
+ return
def setPlotViewMode(self, mode="scatter", bins=None):
if mode.lower() != "density":
@@ -110,41 +149,24 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
def _activateScatterPlotView(self):
self._plotViewMode = "scatter"
- for key in ["colormap", "brushSelection", "brush"]:
- self.setToolBarActionVisible(key, False)
- if hasattr(self, "eraseSelectionToolButton"):
- self.eraseSelectionToolButton.setToolTip("Set erase mode if checked")
- self.eraseSelectionToolButton.setCheckable(True)
- if self._eraseMode:
- self.eraseSelectionToolButton.setChecked(True)
- else:
- self.eraseSelectionToolButton.setChecked(False)
- if hasattr(self, "polygonSelectionToolButton"):
- self.polygonSelectionToolButton.setCheckable(True)
- if hasattr(self, "rectSelectionToolButton"):
- self.rectSelectionToolButton.setCheckable(True)
- if hasattr(self, "brushSelectionToolButton"):
- if self.brushSelectionToolButton.isChecked():
- self.brushSelectionToolButton.setChecked(False)
- self._brushMode = False
- self.setZoomModeEnabled(True)
+ self.colormapAction.setVisible(False)
+ self._brushMode = False
+ self.setInteractiveMode("select")
+
+ if hasattr(self, "maskToolBar"):
+ self.maskToolBar.activateScatterPlotView()
+
self.clearImages()
self._updatePlot()
def _activateDensityPlotView(self, bins=None):
self._plotViewMode = "density"
- for key in ["colormap", "brushSelection", "brush", "rectangle"]:
- self.setToolBarActionVisible(key, True)
- if hasattr(self, "eraseSelectionToolButton"):
- self.eraseSelectionToolButton.setCheckable(True)
- if hasattr(self, "brushSelectionToolButton"):
- self.brushSelectionToolButton.setCheckable(True)
- if hasattr(self, "polygonSelectionToolButton"):
- self.polygonSelectionToolButton.setCheckable(True)
- if hasattr(self, "rectSelectionToolButton"):
- self.rectSelectionToolButton.setCheckable(True)
-
- if DEBUG:
+ self.colormapAction.setVisible(True)
+
+ if hasattr(self, "maskToolBar"):
+ self.maskToolBar.activateDensityPlotView()
+
+ if _logger.getEffectiveLevel() == logging.DEBUG:
if self._densityPlotWidget is None:
self._densityPlotWidget = MaskImageWidget.MaskImageWidget(
imageicons=True,
@@ -166,7 +188,7 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
curve = self.getCurve(self._selectionCurve)
if curve is None:
return
- x, y, legend, info = curve[0:4]
+ x, y, = curve[0:2]
if bins is not None:
if type(bins) == type(1):
bins = (bins, bins)
@@ -175,7 +197,7 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
else:
bins = bins[0:2]
elif self._bins is None:
- bins = [int(x.size/ 10), int(y.size/10)]
+ bins = [int(x.size / 10), int(y.size/10)]
if bins[0] > 100:
bins[0] = 100
elif bins[0] < 2:
@@ -198,15 +220,14 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
#print("shape", image[0].shape, "image max min ", image[0].max(), image[0].min())
#print("deltaxmin and max", (self._binsX[1:] - self._binsX[:-1]).min(),
# (self._binsX[1:] - self._binsX[:-1]).max())
- deltaX = (self._binsX[1:]- self._binsX[:-1]).mean()
- deltaY = (self._binsY[1:]- self._binsY[:-1]).mean()
+ deltaX = (self._binsX[1:] - self._binsX[:-1]).mean()
+ deltaY = (self._binsY[1:] - self._binsY[:-1]).mean()
self._xScale = (x0, deltaX)
self._yScale = (y0, deltaY)
return image[0]
def _updateDensityPlot(self, bins=None):
- if DEBUG:
- print("_updateDensityPlot called")
+ _logger.debug("_updateDensityPlot called")
if self._densityPlotWidget is None:
return
curve = self.getCurve(self._selectionCurve)
@@ -234,8 +255,8 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
bins = self._bins
x0 = x.min()
y0 = y.min()
- deltaX = (x.max() - x0)/float(bins[0] - 1)
- deltaY = (y.max() - y0)/float(bins[1] - 1)
+ deltaX = (x.max() - x0) / float(bins[0] - 1)
+ deltaY = (y.max() - y0) / float(bins[1] - 1)
self.xScale = (x0, deltaX)
self.yScale = (y0, deltaY)
binsX = numpy.arange(bins[0]) * deltaX
@@ -244,27 +265,27 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
self._binsX = image[2]
self._binsY = image[1]
self._bins = bins
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
# this does not work properly
# update mask levels
if self._selectionMask is not None:
weights = self._selectionMask[:]
weights.shape = x.shape
if self._maxNRois > 1:
- print("BAD PATH")
+ _logger.debug("BAD PATH")
# this does not work properly yet
weightsSum = weights.sum(dtype=numpy.float64)
volume = (binsY[1] - binsY[0]) * (binsX[1] - binsX[0])
- mask = numpy.round(numpy.histogram2d(y, x,
- bins=(binsY, binsX),
- weights=weights,
- normed=True)[0] * weightsSum * volume).astype(numpy.uint8)
+ mask = numpy.round(numpy.histogram2d(y, x,
+ bins=(binsY, binsX),
+ weights=weights,
+ normed=True)[0] * weightsSum * volume).astype(numpy.uint8)
else:
#print("GOOD PATH")
- mask = numpy.histogram2d(y, x,
- bins=(binsY, binsX),
- weights=weights,
- normed=False)[0]
+ mask = numpy.histogram2d(y, x,
+ bins=(binsY, binsX),
+ weights=weights,
+ normed=False)[0]
mask[mask > 0] = 1
#print(mask.min(), mask.max())
self._densityPlotWidget.setSelectionMask(mask, plot=False)
@@ -275,7 +296,7 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
xScale=self.xScale,
yScale=self.yScale)
- # do not ovelay plot (yet)
+ # do not overlay plot (yet)
pixmap = self._densityPlotWidget.getPixmap() * 1
#pixmap[:, :, 3] = 128
#self.addImage(pixmap,
@@ -285,10 +306,84 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
self._imageData = image[0]
#raise NotImplemented("Density plot view not implemented yet")
+ def _initColormapDialog(self, imageData, colormap=None):
+ """Set-up the colormap dialog default values.
+
+ :param numpy.ndarray imageData: data used to init dialog.
+ :param dict colormap: Description of the colormap as a dict.
+ See :class:`PlotBackend` for details.
+ If None, use default values.
+ """
+ goodData = imageData[numpy.isfinite(imageData)]
+ if goodData.size > 0:
+ maxData = goodData.max()
+ minData = goodData.min()
+ else:
+ qt.QMessageBox.critical(self, "No Data",
+ "Image data does not contain any real value")
+ return
+
+ self.colormapDialog = ColormapDialog.ColormapDialog(self)
+
+ if colormap is None:
+ colormapIndex = self.DEFAULT_COLORMAP_INDEX
+ if colormapIndex == 6:
+ colormapIndex = 1
+ self.colormapDialog.setColormap(colormapIndex)
+ self.colormapDialog.setDataMinMax(minData, maxData)
+ self.colormapDialog.setAutoscale(1)
+ self.colormapDialog.setColormap(self.colormapDialog.colormapIndex)
+ # linear or logarithmic
+ self.colormapDialog.setColormapType(self.DEFAULT_COLORMAP_LOG_FLAG,
+ update=False)
+ else:
+ # Set-up colormap dialog from provided colormap dict
+ cmapList = ColormapDialog.colormapDictToList(colormap)
+ index, autoscale, vMin, vMax, dataMin, dataMax, cmapType = cmapList
+ self.colormapDialog.setColormap(index)
+ self.colormapDialog.setAutoscale(autoscale)
+ self.colormapDialog.setMinValue(vMin)
+ self.colormapDialog.setMaxValue(vMax)
+ self.colormapDialog.setDataMinMax(minData, maxData)
+ self.colormapDialog.setColormapType(cmapType, update=False)
+
+ self.colormap = self.colormapDialog.getColormap() # Is it used?
+ self.colormapDialog.setWindowTitle("Colormap Dialog")
+ self.colormapDialog.sigColormapChanged.connect(
+ self.updateActiveImageColormap)
+ self.colormapDialog._update()
+
+ def updateActiveImageColormap(self, colormap):
+ if len(colormap) == 1:
+ colormap = colormap[0]
+ # TODO: Once everything is ready to work with dict instead of
+ # list, we can remove this translation
+ plotBackendColormap = ColormapDialog.colormapListToDict(colormap)
+ self.setDefaultColormap(plotBackendColormap)
+
+ image = self.getActiveImage()
+ if image is None:
+ if self.colormapDialog is not None:
+ self.colormapDialog.hide()
+ return
+
+ if not hasattr(image, "getColormap"):
+ if self.colormapDialog is not None:
+ self.colormapDialog.hide()
+ return
+ pixmap = MaskImageTools.getPixmapFromData(image.getData(), colormap)
+ self.addImage(image.getData(), legend=image.getLegend(),
+ info=image.getInfo(),
+ pixmap=pixmap)
+
def setSelectionCurveData(self, x, y, legend=None, info=None,
- replot=True, replace=True, linestyle=" ", color=None,
- symbol=None, selectable=None, **kw):
- self.enableActiveCurveHandling(False)
+ replace=True, linestyle=" ", resetzoom=True,
+ color=None, symbol=None, selectable=None,
+ **kw):
+ if "replot" in kw:
+ _logger.warning("MaskScatterWidget.setSelectionCurveData: deprecated replot parameter")
+ resetzoom = kw["replot"] and resetzoom
+ self.setActiveCurveHandling(False)
if legend is None:
legend = "MaskScatterWidget"
if symbol is None:
@@ -309,9 +404,9 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
# the basic curve is drawn
self.addCurve(x=x, y=y, legend=legend, info=info,
- replace=replace, replot=False, linestyle=linestyle,
- color=color, symbol=symbol, selectable=selectable,z=0,
- **kw)
+ replace=replace, resetzoom=False, linestyle=linestyle,
+ color=color, symbol=symbol, selectable=selectable,
+ z=0, **kw)
self._selectionCurve = legend
# if view mode, draw the image
@@ -322,14 +417,18 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
if self.colormapDialog is None:
self._initColormapDialog(imageData)
cmap = self.colormapDialog.getColormap()
- pixmap=MaskImageTools.getPixmapFromData(imageData,
- colormap=cmap)
+ pixmap = MaskImageTools.getPixmapFromData(imageData,
+ colormap=cmap)
+ origin, scale = (0., 0.), (1., 1.)
+ if self._xScale is not None and self._yScale is not None:
+ origin = self._xScale[0], self._yScale[0]
+ scale = self._xScale[1], self._yScale[1]
+
self.addImage(imageData, legend=legend + "density",
- xScale=self._xScale,
- yScale=self._yScale,
+ origin=origin, scale=scale,
z=0,
pixmap=pixmap,
- replot=False)
+ resetzoom=False)
self._imageData = imageData
self._pixmap = pixmap
@@ -339,26 +438,26 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
if self._selectionMask.max():
hasMaskedData = True
- if hasMaskedData or (replace==False):
- self._updatePlot(replot=False)
+ if hasMaskedData or not replace:
+ self._updatePlot(resetzoom=False)
- # update the plot if it was requested
- if replot:
- self.replot()
+ # update the limits if it was requested
+ if resetzoom:
+ self.resetZoom()
if 0 :#or self._plotViewMode == "density":
# get the binned data
imageData = self.getDensityData()
# get the associated pixmap
- pixmap=MaskImageTools.getPixmapFromData(imageData)
+ pixmap = MaskImageTools.getPixmapFromData(imageData)
if 0:
self.addImage(imageData, legend=legend + "density",
- xScale=self._xScale,
- yScale=self._yScale,
- z=0,
- pixmap=pixmap,
- replot=True)
- if DEBUG:
+ xScale=self._xScale,
+ yScale=self._yScale,
+ z=0,
+ pixmap=pixmap,
+ resetzoom=True)
+ if _logger.getEffectiveLevel() == logging.DEBUG:
if self._densityPlotWidget is None:
self._densityPlotWidget = MaskImageWidget.MaskImageWidget(
imageicons=True,
@@ -367,8 +466,8 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
aspect=True,
polygon=True)
self._updateDensityPlot()
- print("CLOSE = ", numpy.allclose(imageData, self._imageData))
- print("CLOSE PIXMAP = ", numpy.allclose(pixmap, self._pixmap))
+ _logger.debug("CLOSE = %s", numpy.allclose(imageData, self._imageData))
+ _logger.debug("CLOSE PIXMAP = %s", numpy.allclose(pixmap, self._pixmap))
self._imageData = imageData
self._pixmap = pixmap
#self._updatePlot()
@@ -403,14 +502,14 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
def getSelectionMask(self):
if self._selectionMask is None:
if self._selectionCurve is not None:
- x, y, legend, info = self.getCurve(self._selectionCurve)
+ x, y = self.getCurve(self._selectionCurve)[0:2]
self._selectionMask = numpy.zeros(x.shape, numpy.uint8)
return self._selectionMask
- def _updatePlot(self, replot=True, replace=True):
+ def _updatePlot(self, resetzoom=False, replace=True):
if self._selectionCurve is None:
return
- x0, y0, legend, info = self.getCurve(self._selectionCurve)
+ x0, y0, legend, info = self.getCurve(self._selectionCurve)[0:4]
# make sure we work with views
x = x0[:]
y = y0[:]
@@ -423,16 +522,16 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
tmpMask = self._selectionMask[:]
tmpMask.shape = -1
for i in range(0, self._maxNRois + 1):
- colors[tmpMask == i, :] = self._selectionColors[i]
+ colors[tmpMask == i, :] = self.maskToolBar._selectionColors[i]
self.setSelectionCurveData(x, y, legend=legend, info=info,
#color=colors,
color="k",
linestyle=" ",
- replot=replot, replace=replace)
+ resetzoom=resetzoom, replace=replace)
else:
if self._selectionMask is None:
for i in range(1, self._maxNRois + 1):
- self.removeCurve(legend=legend + " %02d" % i, replot=False)
+ self.removeCurve(legend=legend + " %02d" % i)
else:
tmpMask = self._selectionMask[:]
tmpMask.shape = -1
@@ -446,77 +545,38 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
xMask = x[tmpMask == i]
yMask = y[tmpMask == i]
if xMask.size < 1:
- self.removeCurve(legend=legend + " %02d" % i,
- replot=False)
+ self.removeCurve(legend=legend + " %02d" % i)
continue
- color = self._selectionColors[i].copy()
+ color = self.maskToolBar._selectionColors[i].copy()
if useAlpha:
if len(color) == 4:
if type(color[3]) in [numpy.uint8, numpy.int]:
color[3] = self._alphaLevel
# a copy of the input info is needed in order not
# to set the main curve to that color
+
self.addCurve(xMask, yMask, legend=legend + " %02d" % i,
- info=info.copy(), color=color, linestyle=" ",
+ info=info.copy(), color=color,
+ ylabel=legend + " %02d" % i,
+ linestyle=" ", symbol="o",
selectable=False,
z=1,
- replot=False, replace=False)
- if replot:
- self.replot()
- #self.resetZoom()
+ resetzoom=False, replace=False)
+ if resetzoom:
+ self.resetZoom()
def setActiveRoiNumber(self, intValue):
if (intValue < 0) or (intValue > self._maxNRois):
raise ValueError("Value %d outside the interval [0, %d]" % (intValue, self._maxNRois))
self._nRoi = intValue
-
- def _eraseSelectionIconSignal(self):
- if self.eraseSelectionToolButton.isChecked():
- self._eraseMode = True
- else:
- self._eraseMode = False
-
- def _polygonIconSignal(self):
- if self.polygonSelectionToolButton.isChecked():
- self.setPolygonSelectionMode()
- else:
- self.setZoomModeEnabled(True)
-
- def _rectSelectionIconSignal(self):
- if DEBUG:
- print("_rectSelectionIconSignal")
- if self.rectSelectionToolButton.isChecked():
- self.setRectangularSelectionMode()
- else:
- self.setZoomModeEnabled(True)
-
- def setZoomModeEnabled(self, flag, color=None):
- if color is None:
- if hasattr(self, "colormapDialog"):
- if self.colormapDialog is None:
- color = "#00FFFF"
- else:
- cmap = self.colormapDialog.getColormap()
- if cmap[0] < 2:
- color = "#00FFFF"
- else:
- color = "black"
- super(MaskScatterWidget, self).setZoomModeEnabled(flag, color=color)
- if flag:
- if hasattr(self,"polygonSelectionToolButton"):
- self.polygonSelectionToolButton.setChecked(False)
- if hasattr(self,"brushSelectionToolButton"):
- self.brushSelectionToolButton.setChecked(False)
-
def _handlePolygonMask(self, points):
- if DEBUG:
- print("_handlePolygonMask called")
+ _logger.debug("_handlePolygonMask called")
if self._eraseMode:
value = 0
else:
value = self._nRoi
- x, y, legend, info = self.getCurve(self._selectionCurve)
+ x, y = self.getCurve(self._selectionCurve)[0:2]
x.shape = -1
y.shape = -1
currentMask = self.getSelectionMask()
@@ -533,12 +593,21 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
self.setSelectionMask(currentMask, plot=True)
self._emitMaskChangedSignal()
+ def setMouseText(self, text=""):
+ try:
+ if text:
+ qt.QToolTip.showText(self.cursor().pos(),
+ text, self, qt.QRect())
+ else:
+ qt.QToolTip.hideText()
+ except:
+ _logger.warning("Error trying to show mouse text <%s>" % text)
+
def graphCallback(self, ddict):
- if DEBUG:
- print("MaskScatterWidget graphCallback", ddict)
+ _logger.debug("MaskScatterWidget graphCallback %s", ddict)
if ddict["event"] == "drawingFinished":
if ddict["parameters"]["shape"].lower() == "rectangle":
- points = numpy.zeros((5,2), dtype=ddict["points"].dtype)
+ points = numpy.zeros((5, 2), dtype=ddict["points"].dtype)
points[0] = ddict["points"][0]
points[1, 0] = ddict["points"][0, 0]
points[1, 1] = ddict["points"][1, 1]
@@ -553,7 +622,7 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
if (self._plotViewMode == "density") and \
(self._imageData is not None):
shape = self._imageData.shape
- row, column = MaskImageTools.convertToRowAndColumn( \
+ row, column = MaskImageTools.convertToRowAndColumn(
ddict['x'],
ddict['y'],
shape,
@@ -601,7 +670,7 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
#self.setMouseText("%g, %g, %g" % (row, column, self.__imageData[rowMin, columnMin]))
#To show mouse coordinates:
#self.setMouseText("%g, %g, %g" % (ddict['x'], ddict['y'], self.__imageData[rowMin, columnMin]))
- if self._xScale is not None:
+ if self._xScale is not None and self._yScale is not None:
x = self._xScale[0] + column * self._xScale[1]
y = self._yScale[0] + row * self._yScale[1]
else:
@@ -610,7 +679,7 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
self.setMouseText("%g, %g, %g" % (x, y, self._imageData[row, column]))
if self._brushMode:
- if self.isZoomModeEnabled():
+ if self.getInteractiveMode()['mode'] == 'zoom':
return
if ddict['button'] != "left":
return
@@ -632,103 +701,7 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
# the base implementation handles ROIs, mouse position and activeCurve
super(MaskScatterWidget, self).graphCallback(ddict)
- def _brushIconSignal(self):
- if DEBUG:
- print("brushIconSignal")
- if self._brushMenu is None:
- self._brushMenu = qt.QMenu()
- self._brushMenu.addAction(QString(" 1 Image Pixel Width"),
- self._setBrush1)
- self._brushMenu.addAction(QString(" 2 Image Pixel Width"),
- self._setBrush2)
- self._brushMenu.addAction(QString(" 3 Image Pixel Width"),
- self._setBrush3)
- self._brushMenu.addAction(QString(" 5 Image Pixel Width"),
- self._setBrush4)
- self._brushMenu.addAction(QString("10 Image Pixel Width"),
- self._setBrush5)
- self._brushMenu.addAction(QString("20 Image Pixel Width"),
- self._setBrush6)
- self._brushMenu.exec_(self.cursor().pos())
-
- def _brushSelectionIconSignal(self):
- if DEBUG:
- print("_setBrushSelectionMode")
- if hasattr(self, "polygonSelectionToolButton"):
- self.polygonSelectionToolButton.setChecked(False)
- self.setDrawModeEnabled(False)
- if self.brushSelectionToolButton.isChecked():
- self._brushMode = True
- self.setZoomModeEnabled(False)
- else:
- self._brushMode = False
- self.setZoomModeEnabled(True)
-
- def _setBrush1(self):
- self._brushWidth = 1
-
- def _setBrush2(self):
- self._brushWidth = 2
-
- def _setBrush3(self):
- self._brushWidth = 3
-
- def _setBrush4(self):
- self._brushWidth = 5
-
- def _setBrush5(self):
- self._brushWidth = 10
-
- def _setBrush6(self):
- self._brushWidth = 20
-
- def setRectangularSelectionMode(self):
- """
- Resets zoom mode and enters selection mode with the current active ROI index
- """
- self._zoomMode = False
- self._brushMode = False
- color = self._selectionColors[self._nRoi]
- # make sure the selection is made with a non transparent color
- if len(color) == 4:
- if type(color[-1]) in [numpy.uint8, numpy.int8]:
- color = color.copy()
- color[-1] = 255
- self.setDrawModeEnabled(True,
- shape="rectangle",
- label="mask",
- color=color)
- self.setZoomModeEnabled(False)
- if hasattr(self, "brushSelectionToolButton"):
- self.brushSelectionToolButton.setChecked(False)
- if hasattr(self,"polygonSelectionToolButton"):
- self.polygonSelectionToolButton.setChecked(False)
- if hasattr(self,"rectSelectionToolButton"):
- self.rectSelectionToolButton.setChecked(True)
-
- def setPolygonSelectionMode(self):
- """
- Resets zoom mode and enters selection mode with the current active ROI index
- """
- self._zoomMode = False
- self._brushMode = False
- color = self._selectionColors[self._nRoi]
- # make sure the selection is made with a non transparent color
- if len(color) == 4:
- if type(color[-1]) in [numpy.uint8, numpy.int8]:
- color = color.copy()
- color[-1] = 255
- self.setDrawModeEnabled(True, shape="polygon", label="mask",
- color=color)
- self.setZoomModeEnabled(False)
- if hasattr(self, "brushSelectionToolButton"):
- self.brushSelectionToolButton.setChecked(False)
- if hasattr(self,"rectSelectionToolButton"):
- self.rectSelectionToolButton.setChecked(False)
- if hasattr(self,"polygonSelectionToolButton"):
- self.polygonSelectionToolButton.setChecked(True)
-
- def setEraseSelectionMode(self, erase=True):
+ def setEraseSelectionMode(self, erase=True): # TODO: unused?
if erase:
self._eraseMode = True
else:
@@ -751,54 +724,11 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
def emitMaskScatterWidgetSignal(self, ddict):
self.sigMaskScatterWidgetSignal.emit(ddict)
- def _imageIconSignal(self):
- self.__resetSelection()
-
- def _buildAdditionalSelectionMenuDict(self):
- self._additionalSelectionMenu = {}
- #scatter view menu
- menu = qt.QMenu()
- menu.addAction(QString("Density plot view"), self.__setDensityPlotView)
- menu.addAction(QString("Reset Selection"), self.__resetSelection)
- menu.addAction(QString("Invert Selection"), self._invertSelection)
- self._additionalSelectionMenu["scatter"] = menu
-
- # density view menu
- menu = qt.QMenu()
- menu.addAction(QString("Scatter plot view"), self.__setScatterPlotView)
- menu.addAction(QString("Reset Selection"), self.__resetSelection)
- menu.addAction(QString("Invert Selection"), self._invertSelection)
- menu.addAction(QString("I >= Colormap Max"), self._selectMax)
- menu.addAction(QString("Colormap Min < I < Colormap Max"),
- self._selectMiddle)
- menu.addAction(QString("I <= Colormap Min"), self._selectMin)
- menu.addAction(QString("Increase mask alpha"), self._increaseMaskAlpha)
- menu.addAction(QString("Decrease mask alpha"), self._decreaseMaskAlpha)
- self._additionalSelectionMenu["density"] = menu
-
- def __setScatterPlotView(self):
- self.setPlotViewMode(mode="scatter")
-
- def __setDensityPlotView(self):
- self.setPlotViewMode(mode="density")
-
- def _additionalIconSignal(self):
- if self._plotViewMode == "density": # and imageData is not none ...
- self._additionalSelectionMenu["density"].exec_(self.cursor().pos())
- else:
- self._additionalSelectionMenu["scatter"].exec_(self.cursor().pos())
-
- def __resetSelection(self):
- # Needed because receiving directly in _resetSelection it was passing
- # False as argument
- self._resetSelection(True)
-
def _resetSelection(self, owncall=True):
- if DEBUG:
- print("_resetSelection")
+ _logger.debug("_resetSelection")
if self._selectionMask is None:
- print("Selection mask is None, doing nothing")
+ _logger.info("Selection mask is None, doing nothing")
return
else:
self._selectionMask[:] = 0
@@ -870,19 +800,18 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
self._emitMaskChangedSignal()
def _setSelectionMaskFromDensityMask(self, densityPlotMask, update=None):
- if DEBUG:
- print("_setSelectionMaskFromDensityMask called")
+ _logger.debug("_setSelectionMaskFromDensityMask called")
curve = self.getCurve(self._selectionCurve)
if curve is None:
return
- x, y, legend, info = curve[0:4]
+ x, y = curve[0:2]
bins = self._bins
x0 = x.min()
y0 = y.min()
deltaX = (x.max() - x0)/float(bins[0])
deltaY = (y.max() - y0)/float(bins[1])
columns = numpy.digitize(x, self._binsX, right=True)
- columns[columns>=densityPlotMask.shape[1]] = \
+ columns[columns >= densityPlotMask.shape[1]] = \
densityPlotMask.shape[1] - 1
rows = numpy.digitize(y, self._binsY, right=True)
rows[rows>=densityPlotMask.shape[0]] = densityPlotMask.shape[0] - 1
@@ -907,8 +836,7 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
self.setSelectionMask(view, plot=True)
def _densityPlotSlot(self, ddict):
- if DEBUG:
- print("_densityPlotSlot called")
+ _logger.debug("_densityPlotSlot called")
if ddict["event"] == "resetSelection":
self.__resetSelection()
return
@@ -918,13 +846,13 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
curve = self.getCurve(self._selectionCurve)
if curve is None:
return
- x, y, legend, info = curve[0:4]
+ x, y = curve[0:2]
bins = self._bins
x0 = x.min()
y0 = y.min()
deltaX = (x.max() - x0)/float(bins[0])
deltaY = (y.max() - y0)/float(bins[1])
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
if self._selectionMask is None:
view = numpy.zeros(x.size, dtype=numpy.uint8)
else:
@@ -960,7 +888,7 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
view2[:] = values[:]
if self._selectionMask is not None:
view2.shape = self._selectionMask.shape
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
if not numpy.allclose(view, view2):
a = view[:]
b = view2[:]
@@ -969,15 +897,15 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
c = 0
for i in range(a.size):
if a[i] != b[i]:
- print(i, "a = ", a[i], "b = ", b[i], "(x, y) = ", x[i], y[i])
+ _logger.debug("%d a = %s, b = %s, (x, y) = (%s, %s)",
+ i, a[i], b[i], x[i], y[i])
c += 1
if c > 10:
break
else:
- print("OK!!!")
+ _logger.debug("OK!!!")
self.setSelectionMask(view2)
-
def _initializeAlpha(self):
self._alphaLevel = 128
@@ -998,6 +926,15 @@ class MaskScatterWidget(PlotWindow.PlotWindow):
self._alphaLevel = 2
self._updatePlot()
+ def setPolygonSelectionMode(self):
+ """
+ Resets zoom mode and enters selection mode with the current active ROI index
+ """
+ self.maskToolBar.setPolygonSelectionMode()
+
+ def _zoomBack(self, pos):
+ self.getLimitsHistory().pop()
+
if __name__ == "__main__":
backend = "matplotlib"
#backend = "opengl"
@@ -1006,7 +943,8 @@ if __name__ == "__main__":
print("Received: ", ddict)
x = numpy.arange(100.)
y = x * 1
- w = MaskScatterWidget(maxNRois=10, bins=(100,100), backend=backend)
+ w = MaskScatterWidget(maxNRois=10, bins=(100, 100), backend=backend,
+ control=True)
w.setSelectionCurveData(x, y, color="k", selectable=False)
import numpy.random
w.setSelectionMask(numpy.random.permutation(100) % 10)
diff --git a/PyMca5/PyMcaGui/plotting/MaskToolBar.py b/PyMca5/PyMcaGui/plotting/MaskToolBar.py
new file mode 100644
index 0000000..b53e81a
--- /dev/null
+++ b/PyMca5/PyMcaGui/plotting/MaskToolBar.py
@@ -0,0 +1,331 @@
+#/*##########################################################################
+# Copyright (C) 2004-2017 V.A. Sole, European Synchrotron Radiation Facility
+#
+# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
+# the ESRF by the Software group.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+#############################################################################*/
+"""This module implements a plot toolbar with buttons to draw and erase masks.
+"""
+
+__author__ = "P. Knobel"
+__license__ = "MIT"
+__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
+
+import numpy
+
+from PyMca5.PyMcaGui import PyMcaQt as qt
+from .PyMca_Icons import IconDict
+
+from silx.gui import colors
+
+if hasattr(qt, "QString"):
+ QString = qt.QString
+else:
+ QString = qt.safe_str
+
+
+_COLORDICT = colors.COLORDICT
+# these are color RGBA strings '#0000ff'
+_COLORLIST = [_COLORDICT['black'],
+ _COLORDICT['blue'],
+ _COLORDICT['red'],
+ _COLORDICT['green'],
+ _COLORDICT['pink'],
+ _COLORDICT['yellow'],
+ _COLORDICT['brown'],
+ _COLORDICT['cyan'],
+ _COLORDICT['magenta'],
+ _COLORDICT['orange'],
+ _COLORDICT['violet'],
+ #_COLORDICT['bluegreen'],
+ _COLORDICT['grey'],
+ _COLORDICT['darkBlue'],
+ _COLORDICT['darkRed'],
+ _COLORDICT['darkGreen'],
+ _COLORDICT['darkCyan'],
+ _COLORDICT['darkMagenta'],
+ _COLORDICT['darkYellow'],
+ _COLORDICT['darkBrown']]
+
+
+class MaskToolBar(qt.QToolBar):
+ """Toolbar with buttons controlling the mask drawing and erasing
+ interactions on a :class:`MaskScatterWidget`, to select or deselect
+ data."""
+ # sigIconSignal = qt.pyqtSignal(object)
+ colorList = _COLORLIST
+
+ def __init__(self, parent=None, plot=None, title="Mask tools",
+ imageIcons=True, polygon=True):
+ super(MaskToolBar, self).__init__(title, parent)
+ assert plot is not None
+ assert imageIcons or polygon,\
+ "It makes no sense to build an empty mask toolbar"
+ self.plot = plot
+ self._brushMenu = None
+
+ self.polygonIcon = qt.QIcon(qt.QPixmap(IconDict["polygon"]))
+ self.imageIcon = qt.QIcon(qt.QPixmap(IconDict["image"]))
+ self.eraseSelectionIcon = qt.QIcon(qt.QPixmap(IconDict["eraseselect"]))
+ self.rectSelectionIcon = qt.QIcon(qt.QPixmap(IconDict["boxselect"]))
+ self.brushSelectionIcon = qt.QIcon(qt.QPixmap(IconDict["brushselect"]))
+ self.brushIcon = qt.QIcon(qt.QPixmap(IconDict["brush"]))
+ self.additionalIcon = qt.QIcon(qt.QPixmap(IconDict["additionalselect"]))
+
+ self.polygonSelectionToolButton = qt.QToolButton(self)
+ self.imageToolButton = qt.QToolButton(self)
+ self.eraseSelectionToolButton = qt.QToolButton(self)
+ self.rectSelectionToolButton = qt.QToolButton(self)
+ self.brushSelectionToolButton = qt.QToolButton(self)
+ self.brushToolButton = qt.QToolButton(self)
+ self.additionalSelectionToolButton = qt.QToolButton(self)
+
+ self.polygonSelectionToolButton.setIcon(self.polygonIcon)
+ self.imageToolButton.setIcon(self.imageIcon)
+ self.eraseSelectionToolButton.setIcon(self.eraseSelectionIcon)
+ self.rectSelectionToolButton.setIcon(self.rectSelectionIcon)
+ self.brushSelectionToolButton.setIcon(self.brushSelectionIcon)
+ self.brushToolButton.setIcon(self.brushIcon)
+ self.additionalSelectionToolButton.setIcon(self.additionalIcon)
+
+ self.polygonSelectionToolButton.setToolTip('Polygon selection\n'
+ 'Click first point to finish')
+ self.imageToolButton.setToolTip('Reset')
+ self.eraseSelectionToolButton.setToolTip('Erase Selection')
+ self.rectSelectionToolButton.setToolTip('Rectangular Selection')
+ self.brushSelectionToolButton.setToolTip('Brush Selection')
+ self.brushToolButton.setToolTip('Brush Size')
+ self.additionalSelectionToolButton.setToolTip('Additional Selections Menu')
+
+ self.eraseSelectionToolButton.setCheckable(True)
+ self.polygonSelectionToolButton.setCheckable(True)
+ self.rectSelectionToolButton.setCheckable(True)
+ self.brushSelectionToolButton.setCheckable(True)
+
+ self.imageAction = self.addWidget(self.imageToolButton)
+ self.eraseSelectionAction = self.addWidget(self.eraseSelectionToolButton)
+ self.rectSelectionAction = self.addWidget(self.rectSelectionToolButton)
+ self.brushSelectionAction = self.addWidget(self.brushSelectionToolButton)
+ self.brushAction = self.addWidget(self.brushToolButton)
+ self.polygonSelectionAction = self.addWidget(self.polygonSelectionToolButton)
+ self.additionalSelectionAction = self.addWidget(self.additionalSelectionToolButton)
+
+ self.imageToolButton.clicked.connect(self._imageIconSignal)
+ self.eraseSelectionToolButton.clicked.connect(self._eraseSelectionIconSignal)
+ self.rectSelectionToolButton.clicked.connect(self._rectSelectionIconSignal)
+ self.brushSelectionToolButton.clicked.connect(self._brushSelectionIconSignal)
+ self.brushToolButton.clicked.connect(self._brushIconSignal)
+ self.polygonSelectionToolButton.clicked.connect(self._polygonIconSignal)
+ self.additionalSelectionToolButton.clicked.connect(self._additionalIconSignal)
+
+ if not imageIcons:
+ self.imageAction.setVisible(False)
+ self.eraseSelectionAction.setVisible(False)
+ self.rectSelectionAction.setVisible(False)
+ self.brushSelectionAction.setVisible(False)
+ self.brushAction.setVisible(False)
+ self.polygonSelectionAction.setVisible(False)
+ self.additionalSelectionAction.setVisible(False)
+
+ if not polygon:
+ self.polygonSelectionAction.setVisible(False)
+
+ self._buildAdditionalSelectionMenuDict()
+
+ # selection colors as a RBGA (uint8) array
+ self._selectionColors = numpy.zeros((len(self.colorList), 4), numpy.uint8)
+ for i in range(len(self.colorList)):
+ self._selectionColors[i, 0] = eval("0x" + self.colorList[i][-2:])
+ self._selectionColors[i, 1] = eval("0x" + self.colorList[i][3:-2])
+ self._selectionColors[i, 2] = eval("0x" + self.colorList[i][1:3])
+ self._selectionColors[i, 3] = 0xff
+
+ self.plot.sigInteractiveModeChanged.connect(self._interactiveModeChanged)
+
+ def activateScatterPlotView(self):
+ self.brushSelectionAction.setVisible(False)
+ self.brushAction.setVisible(False)
+ self.eraseSelectionAction.setToolTip("Set erase mode if checked")
+
+ self.eraseSelectionToolButton.setChecked(self.plot._eraseMode)
+ self.brushSelectionToolButton.setChecked(False)
+
+ def activateDensityPlotView(self):
+ self.brushSelectionAction.setVisible(True)
+ self.brushAction.setVisible(True)
+ self.rectSelectionAction.setVisible(True)
+
+ def _imageIconSignal(self, checked=False):
+ self.plot._resetSelection(owncall=True)
+
+ def _eraseSelectionIconSignal(self, checked=False):
+ self.plot._eraseMode = checked
+
+ def _getSelectionColor(self):
+ """Return a selection color as hex "#RRGGBBAA" string"""
+ rgba_color_array = self._selectionColors[self.plot._nRoi]
+ # make sure the selection is made with a non transparent color
+ if len(rgba_color_array) == 4:
+ rgba_color_array = rgba_color_array.copy()
+ rgba_color_array[-1] = 255
+
+ # convert to string
+ s = "#"
+ for channel_uint8_value in rgba_color_array:
+ s += "{:02x}".format(channel_uint8_value)
+ return s
+
+ def _polygonIconSignal(self, checked=False):
+ if checked:
+ self.plot.setInteractiveMode("draw", shape="polygon",
+ label="mask",
+ color=self._getSelectionColor())
+ self.plot._zoomMode = False
+ self.plot._brushMode = False
+
+ self.brushSelectionToolButton.setChecked(False)
+ self.rectSelectionToolButton.setChecked(False)
+ self.polygonSelectionToolButton.setChecked(True)
+ else:
+ self.plot.setInteractiveMode("select")
+ self._uncheckAllSelectionButtons()
+
+ def setPolygonSelectionMode(self):
+ """
+ Resets zoom mode and enters selection mode with the current active ROI index
+ """
+ self.polygonSelectionToolButton.setChecked(True)
+ self.polygonSelectionAction.trigger() # calls _polygonIconSignal
+
+ def _rectSelectionIconSignal(self, checked=False):
+ if checked:
+ self.plot._zoomMode = False
+ self.plot._brushMode = False
+ self.brushSelectionToolButton.setChecked(False)
+ self.polygonSelectionToolButton.setChecked(False)
+ self.rectSelectionToolButton.setChecked(True)
+
+ self.plot.setInteractiveMode("draw",
+ shape="rectangle",
+ label="mask",
+ color=self._getSelectionColor())
+ else:
+ self.plot.setInteractiveMode("select")
+ self._uncheckAllSelectionButtons()
+
+ def _brushSelectionIconSignal(self, checked=False):
+ self.polygonSelectionToolButton.setChecked(False)
+ self.rectSelectionToolButton.setChecked(False)
+ if checked:
+ self.plot._brushMode = True
+ self.plot.setInteractiveMode('select')
+ else:
+ self._brushMode = False
+
+ def _brushIconSignal(self, checked=False):
+ if self._brushMenu is None:
+ self._brushMenu = qt.QMenu()
+ self._brushMenu.addAction(QString(" 1 Image Pixel Width"),
+ self._setBrush1)
+ self._brushMenu.addAction(QString(" 2 Image Pixel Width"),
+ self._setBrush2)
+ self._brushMenu.addAction(QString(" 3 Image Pixel Width"),
+ self._setBrush3)
+ self._brushMenu.addAction(QString(" 5 Image Pixel Width"),
+ self._setBrush4)
+ self._brushMenu.addAction(QString("10 Image Pixel Width"),
+ self._setBrush5)
+ self._brushMenu.addAction(QString("20 Image Pixel Width"),
+ self._setBrush6)
+ self._brushMenu.exec_(self.cursor().pos())
+
+ def _setBrush1(self):
+ self.plot._brushWidth = 1
+
+ def _setBrush2(self):
+ self.plot._brushWidth = 2
+
+ def _setBrush3(self):
+ self.plot._brushWidth = 3
+
+ def _setBrush4(self):
+ self.plot._brushWidth = 5
+
+ def _setBrush5(self):
+ self.plot._brushWidth = 10
+
+ def _setBrush6(self):
+ self.plot._brushWidth = 20
+
+ def _buildAdditionalSelectionMenuDict(self):
+ self._additionalSelectionMenu = {}
+ #scatter view menu
+ menu = qt.QMenu()
+ menu.addAction(QString("Density plot view"), self.__setDensityPlotView)
+ menu.addAction(QString("Reset Selection"), self.__resetSelection)
+ menu.addAction(QString("Invert Selection"), self.plot._invertSelection)
+ self._additionalSelectionMenu["scatter"] = menu
+
+ # density view menu
+ menu = qt.QMenu()
+ menu.addAction(QString("Scatter plot view"), self.__setScatterPlotView)
+ menu.addAction(QString("Reset Selection"), self.__resetSelection)
+ menu.addAction(QString("Invert Selection"), self.plot._invertSelection)
+ menu.addAction(QString("I >= Colormap Max"), self.plot._selectMax)
+ menu.addAction(QString("Colormap Min < I < Colormap Max"),
+ self.plot._selectMiddle)
+ menu.addAction(QString("I <= Colormap Min"), self.plot._selectMin)
+ menu.addAction(QString("Increase mask alpha"), self.plot._increaseMaskAlpha)
+ menu.addAction(QString("Decrease mask alpha"), self.plot._decreaseMaskAlpha)
+
+ self._additionalSelectionMenu["density"] = menu
+
+ def __setScatterPlotView(self):
+ self.plot.setPlotViewMode(mode="scatter")
+
+ def __setDensityPlotView(self):
+ self.plot.setPlotViewMode(mode="density")
+
+ def __resetSelection(self):
+ self.plot._resetSelection(owncall=True)
+
+ def _additionalIconSignal(self, checked=False):
+ if self.plot._plotViewMode == "density": # and imageData is not none ...
+ self._additionalSelectionMenu["density"].exec_(self.cursor().pos())
+ else:
+ self._additionalSelectionMenu["scatter"].exec_(self.cursor().pos())
+
+ def _uncheckAllSelectionButtons(self):
+ self.brushSelectionToolButton.setChecked(False)
+ self.polygonSelectionToolButton.setChecked(False)
+ self.brushSelectionToolButton.setChecked(False)
+
+ def _interactiveModeChanged(self, source):
+ if self.plot.getInteractiveMode()['mode'] != "draw":
+ self._uncheckAllSelectionButtons()
+
+ # def emitIconSignal(self, key, event="iconClicked"):
+ # ddict = {"key": key,
+ # "event": event}
+ # self.sigIconSignal.emit(ddict)
+
+
diff --git a/PyMca5/PyMcaGui/plotting/McaROIWidget.py b/PyMca5/PyMcaGui/plotting/McaROIWidget.py
index e49948e..5a2c663 100644
--- a/PyMca5/PyMcaGui/plotting/McaROIWidget.py
+++ b/PyMca5/PyMcaGui/plotting/McaROIWidget.py
@@ -29,6 +29,7 @@ __license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import os
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
if hasattr(qt, "QString"):
@@ -41,7 +42,9 @@ QTVERSION = qt.qVersion()
from PyMca5.PyMcaCore import PyMcaDirs
from PyMca5.PyMcaIO import ConfigDict
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
+
class McaROIWidget(qt.QWidget):
sigMcaROIWidgetSignal = qt.pyqtSignal(object)
@@ -109,8 +112,7 @@ class McaROIWidget(qt.QWidget):
self.mcaROITable.sigMcaROITableSignal.connect(self._forward)
def _add(self):
- if DEBUG:
- print("McaROIWidget._add")
+ _logger.debug("McaROIWidget._add")
ddict={}
ddict['event'] = "AddROI"
roilist, roidict = self.mcaROITable.getROIListAndDict()
@@ -409,8 +411,7 @@ class McaROITable(qt.QTableWidget):
else:
if currentroi in self.roidict.keys():
self.selectRow(self.roidict[currentroi]['line'])
- if DEBUG:
- print("Qt4 ensureCellVisible to be implemented")
+ _logger.debug("Qt4 ensureCellVisible to be implemented")
self.building = False
def addROI(self, roi, key=None):
@@ -472,8 +473,7 @@ class McaROITable(qt.QTableWidget):
ddict['row' ] = row
ddict['col' ] = col
if row >= len(self.roilist):
- if DEBUG:
- print("deleting???")
+ _logger.debug("deleting???")
return
row = 0
item = self.item(row, 0)
@@ -492,8 +492,7 @@ class McaROITable(qt.QTableWidget):
self._emitSelectionChangedSignal(row, 0)
def _cellChangedSlot(self, row, col):
- if DEBUG:
- print("_cellChangedSlot(%d, %d)" % (row, col))
+ _logger.debug("_cellChangedSlot(%d, %d)", row, col)
if self.building:
return
if col == 0:
@@ -513,8 +512,7 @@ class McaROITable(qt.QTableWidget):
except:
return
if row >= len(self.roilist):
- if DEBUG:
- print("deleting???")
+ _logger.debug("deleting???")
return
if QTVERSION < '4.0.0':
text = str(self.text(row, 0))
@@ -535,8 +533,7 @@ class McaROITable(qt.QTableWidget):
def nameSlot(self, row, col):
if col != 0: return
if row >= len(self.roilist):
- if DEBUG:
- print("deleting???")
+ _logger.debug("deleting???")
return
item = self.item(row, col)
if item is None:
@@ -572,8 +569,7 @@ class McaROITable(qt.QTableWidget):
col = var[1]
if col == 0:
if row >= len(self.roilist):
- if DEBUG:
- print("deleting???")
+ _logger.debug("deleting???")
return
row = 0
item = self.item(row, col)
diff --git a/PyMca5/PyMcaGui/plotting/PlotWidget.py b/PyMca5/PyMcaGui/plotting/PlotWidget.py
index d6282a8..4619feb 100644
--- a/PyMca5/PyMcaGui/plotting/PlotWidget.py
+++ b/PyMca5/PyMcaGui/plotting/PlotWidget.py
@@ -28,7 +28,9 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
-import os
+import logging
+import traceback
+
from PyMca5.PyMcaGraph import Plot
SVG = True
@@ -82,10 +84,21 @@ else:
if not hasattr(QtCore, "Signal"):
QtCore.Signal = QtCore.pyqtSignal
+
+_logger = logging.getLogger(__name__)
+
DEBUG = 0
if DEBUG:
+ _logger.setLevel(logging.DEBUG)
Plot.DEBUG = DEBUG
+_logger.warning("%s is deprecated, you are advised to use "
+ "silx.gui.plot.PlotWidget instead",
+ __name__)
+for line in traceback.format_stack(limit=3):
+ _logger.warning(line.rstrip())
+
+
class PlotWidget(QtGui.QMainWindow, Plot.Plot):
sigPlotSignal = QtCore.Signal(object)
diff --git a/PyMca5/PyMcaGui/plotting/PlotWindow.py b/PyMca5/PyMcaGui/plotting/PlotWindow.py
index 8dc46f7..b100f3e 100644
--- a/PyMca5/PyMcaGui/plotting/PlotWindow.py
+++ b/PyMca5/PyMcaGui/plotting/PlotWindow.py
@@ -1474,7 +1474,10 @@ class PlotWindow(PlotWidget.PlotWidget):
os.remove(filename)
if filterused[0].upper() == "WIDGET":
fformat = filename[-3:].upper()
- pixmap = qt.QPixmap.grabWidget(self)
+ if hasattr(qt.QPixmap,"grabWidget"):
+ pixmap = qt.QPixmap.grabWidget(self)
+ else:
+ pixmap = self.grab()
if not pixmap.save(filename, fformat):
msg = qt.QMessageBox(self)
msg.setIcon(qt.QMessageBox.Critical)
diff --git a/PyMca5/PyMcaGui/plotting/ProfileScanWidget.py b/PyMca5/PyMcaGui/plotting/ProfileScanWidget.py
index 93cc866..6b3d95a 100644
--- a/PyMca5/PyMcaGui/plotting/ProfileScanWidget.py
+++ b/PyMca5/PyMcaGui/plotting/ProfileScanWidget.py
@@ -34,7 +34,7 @@ if 1:
# if not, we miss profile fitting ...
from PyMca5.PyMcaGui.pymca.ScanWindow import ScanWindow as Window
else:
- from .PlotWindow import PlotWindow as Window
+ from silx.gui.plot import PlotWindow as Window
DEBUG = 0
class ProfileScanWidget(Window):
@@ -118,7 +118,7 @@ class ProfileScanWidget(Window):
elif action == 'REMOVE':
self.sigRemoveClicked.emit(ddict)
else:
- self.replaceAddClicked.emit(ddict)
+ self.sigReplaceClicked.emit(ddict)
def test():
app = qt.QApplication([])
diff --git a/PyMca5/PyMcaGui/plotting/PyMca_Icons.py b/PyMca5/PyMcaGui/plotting/PyMca_Icons.py
index 56fdc97..ebb3f37 100644
--- a/PyMca5/PyMcaGui/plotting/PyMca_Icons.py
+++ b/PyMca5/PyMcaGui/plotting/PyMca_Icons.py
@@ -4177,9 +4177,22 @@ class _PatchedIconDict(MutableMapping):
# we also need to remove the key from internal translation table
del self._translation_table[key]
+
IconDict = _PatchedIconDict(IconDict0)
+def change_icons(plot):
+ """Replace some of the silx icons with PyMca icons.
+
+ :param plot: Silx plot window, or ScanWindow, or McaWindow
+ :return:
+ """
+ from PyMca5.PyMcaGui import PyMcaQt as qt
+ plot.getRoiAction().setIcon(qt.QIcon(qt.QPixmap(IconDict["roi"])))
+ if hasattr(plot, "printPreview"):
+ plot.printPreview.setIcon(qt.QIcon(qt.QPixmap(IconDict["fileprint"])))
+
+
def showIcons():
w = qt.QWidget()
g = qt.QGridLayout(w)
diff --git a/PyMca5/PyMcaGui/plotting/Q4PyMcaPrintPreview.py b/PyMca5/PyMcaGui/plotting/Q4PyMcaPrintPreview.py
index 1a4608b..3734a52 100644
--- a/PyMca5/PyMcaGui/plotting/Q4PyMcaPrintPreview.py
+++ b/PyMca5/PyMcaGui/plotting/Q4PyMcaPrintPreview.py
@@ -28,7 +28,8 @@ __contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
-import os
+import logging
+import traceback
from PyMca5.PyMcaGui import PyMcaQt as qt
DEBUG = 0
__revision__="$Revision: 1.7 $"
@@ -39,6 +40,14 @@ __revision__="$Revision: 1.7 $"
QTVERSION = qt.qVersion()
+_logger = logging.getLogger(__name__)
+_logger.warning("%s is deprecated, you are advised to use "
+ "silx.gui.widgets.PrintPreview instead",
+ __name__)
+
+for line in traceback.format_stack(limit=3):
+ _logger.warning(line.rstrip())
+
################################################################################
################## PyMcaPrintPreview ###################
diff --git a/PyMca5/PyMcaGui/plotting/RGBCorrelatorGraph.py b/PyMca5/PyMcaGui/plotting/RGBCorrelatorGraph.py
index bcaf7ae..24d874c 100644
--- a/PyMca5/PyMcaGui/plotting/RGBCorrelatorGraph.py
+++ b/PyMca5/PyMcaGui/plotting/RGBCorrelatorGraph.py
@@ -30,14 +30,24 @@ __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
import os
import numpy
-from . import PlotWidget
+import logging
from PyMca5.PyMcaGui import PyMcaQt as qt
+from silx.gui.plot import PlotWidget
+from silx.gui.plot.PrintPreviewToolButton import SingletonPrintPreviewToolButton
from .PyMca_Icons import IconDict
-from . import PyMcaPrintPreview
from PyMca5.PyMcaCore import PyMcaDirs
+from silx.gui import icons as silx_icons
+
+if sys.version_info[0] == 3:
+ from io import BytesIO
+else:
+ import cStringIO as _StringIO
+ BytesIO = _StringIO.StringIO
QTVERSION = qt.qVersion()
-DEBUG = 0
+_logger = logging.getLogger(__name__)
+
+
def convertToRowAndColumn(x, y, shape, xScale=None, yScale=None, safe=True):
if xScale is None:
@@ -59,6 +69,7 @@ def convertToRowAndColumn(x, y, shape, xScale=None, yScale=None, safe=True):
r = int(r)
return r, c
+
class RGBCorrelatorGraph(qt.QWidget):
sigProfileSignal = qt.pyqtSignal(object)
@@ -71,17 +82,22 @@ class RGBCorrelatorGraph(qt.QWidget):
self.mainLayout.setContentsMargins(0, 0, 0, 0)
self.mainLayout.setSpacing(0)
self._keepDataAspectRatioFlag = False
+ self.graph = PlotWidget(parent=self, backend=backend)
+ self.graph.setGraphXLabel("Column")
+ self.graph.setGraphYLabel("Row")
+ self.graph.setYAxisAutoScale(True)
+ self.graph.setXAxisAutoScale(True)
+ plotArea = self.graph.getWidgetHandle()
+ plotArea.setContextMenuPolicy(qt.Qt.CustomContextMenu)
+ plotArea.customContextMenuRequested.connect(self._zoomBack)
+
self._buildToolBar(selection, colormap, imageicons,
standalonesave,
standalonezoom=standalonezoom,
profileselection=profileselection,
aspect=aspect,
polygon=polygon)
- self.graph = PlotWidget.PlotWidget(self, backend=backend, aspect=aspect)
- self.graph.setGraphXLabel("Column")
- self.graph.setGraphYLabel("Row")
- self.graph.setYAxisAutoScale(True)
- self.graph.setXAxisAutoScale(True)
+
if profileselection:
if len(self._pickerSelectionButtons):
self.graph.sigPlotSignal.connect(\
@@ -91,9 +107,6 @@ class RGBCorrelatorGraph(qt.QWidget):
self.saveDirectory = os.getcwd()
self.mainLayout.addWidget(self.graph)
- self.printPreview = PyMcaPrintPreview.PyMcaPrintPreview(modal = 0)
- if DEBUG:
- print("printPreview id = %d" % id(self.printPreview))
def sizeHint(self):
return qt.QSize(1.5 * qt.QWidget.sizeHint(self).width(),
@@ -123,6 +136,7 @@ class RGBCorrelatorGraph(qt.QWidget):
self.hLineIcon = qt.QIcon(qt.QPixmap(IconDict["horizontal"]))
self.vLineIcon = qt.QIcon(qt.QPixmap(IconDict["vertical"]))
self.lineIcon = qt.QIcon(qt.QPixmap(IconDict["diagonal"]))
+ self.copyIcon = silx_icons.getQIcon("edit-copy")
self.toolBar = qt.QWidget(self)
self.toolBarLayout = qt.QHBoxLayout(self.toolBar)
@@ -160,16 +174,16 @@ class RGBCorrelatorGraph(qt.QWidget):
#Aspect ratio
if aspect:
self.aspectButton = self._addToolButton(self.solidCircleIcon,
- self._aspectButtonSignal,
- 'Keep data aspect ratio',
- toggle = False)
+ self._aspectButtonSignal,
+ 'Keep data aspect ratio',
+ toggle=False)
self.aspectButton.setChecked(False)
#colormap
if colormap:
tb = self._addToolButton(self.colormapIcon,
None,
- 'Change Colormap')
+ 'Change Colormap')
self.colormapToolButton = tb
#flip
@@ -190,6 +204,10 @@ class RGBCorrelatorGraph(qt.QWidget):
'Save')
self.saveToolButton = tb
+ self.copyToolButton = self._addToolButton(self.copyIcon,
+ self._copyIconSignal,
+ "Copy graph to clipboard")
+
#Selection
if selection:
tb = self._addToolButton(self.selectionIcon,
@@ -221,7 +239,6 @@ class RGBCorrelatorGraph(qt.QWidget):
'Brush Selection')
self.brushSelectionToolButton = tb
-
tb = self._addToolButton(self.brushIcon,
None,
'Select Brush')
@@ -292,7 +309,7 @@ class RGBCorrelatorGraph(qt.QWidget):
#self.lineWidthProfileButton = tb
#self._pickerSelectionButtons.append(tb)
if self._polygonSelection:
- print("Polygon selection not implemented yet")
+ _logger.info("Polygon selection not implemented yet")
#hide profile selection buttons
if imageicons:
for button in self._pickerSelectionButtons:
@@ -311,13 +328,13 @@ class RGBCorrelatorGraph(qt.QWidget):
self.toolBarLayout.addWidget(qt.HorizontalSpacer(self.toolBar))
# ---print
- tb = self._addToolButton(self.printIcon,
- self.printGraph,
- 'Prints the Graph')
+ self.printPreview = SingletonPrintPreviewToolButton(parent=self,
+ plot=self.graph)
+ self.printPreview.setIcon(self.printIcon)
+ self.toolBarLayout.addWidget(self.printPreview)
def _aspectButtonSignal(self):
- if DEBUG:
- print("_aspectButtonSignal")
+ _logger.debug("_aspectButtonSignal")
if self._keepDataAspectRatioFlag:
self.keepDataAspectRatio(False)
else:
@@ -332,7 +349,7 @@ class RGBCorrelatorGraph(qt.QWidget):
self._keepDataAspectRatioFlag = False
self.aspectButton.setIcon(self.solidCircleIcon)
self.aspectButton.setToolTip("Keep data aspect ratio")
- self.graph.keepDataAspectRatio(self._keepDataAspectRatioFlag)
+ self.graph.setKeepDataAspectRatio(self._keepDataAspectRatioFlag)
def showInfo(self):
self.infoWidget.show()
@@ -351,7 +368,7 @@ class RGBCorrelatorGraph(qt.QWidget):
else:
qt.QToolTip.hideText()
except:
- print("Error trying to show mouse text <%s>" % text)
+ _logger.warning("Error trying to show mouse text <%s>" % text)
def focusOutEvent(self, ev):
qt.QToolTip.hideText()
@@ -447,8 +464,8 @@ class RGBCorrelatorGraph(qt.QWidget):
button.hide()
self._pickerSelectionWidthLabel.hide()
self._pickerSelectionWidthValue.hide()
- #self.graph.setPickerSelectionModeOff()
- self.graph.setDrawModeEnabled(False)
+ if self.graph.getInteractiveMode()['mode'] == 'draw':
+ self.graph.setInteractiveMode('select')
def showProfileSelectionIcons(self):
if not len(self._pickerSelectionButtons):
@@ -471,8 +488,7 @@ class RGBCorrelatorGraph(qt.QWidget):
def _setPickerSelectionMode(self, mode=None):
if mode is None:
- self.graph.setDrawModeEnabled(False)
- self.graph.setZoomModeEnabled(True)
+ self.graph.setInteractiveMode('zoom')
else:
if mode == "HORIZONTAL":
shape = "hline"
@@ -480,8 +496,7 @@ class RGBCorrelatorGraph(qt.QWidget):
shape = "vline"
else:
shape = "line"
- self.graph.setZoomModeEnabled(False)
- self.graph.setDrawModeEnabled(True,
+ self.graph.setInteractiveMode('draw',
shape=shape,
label=mode)
ddict = {}
@@ -492,15 +507,14 @@ class RGBCorrelatorGraph(qt.QWidget):
self.sigProfileSignal.emit(ddict)
def _graphPolygonSignalReceived(self, ddict):
- if DEBUG:
- print("PolygonSignal Received")
- for key in ddict.keys():
- print(key, ddict[key])
+ _logger.debug("PolygonSignal Received")
+ for key in ddict.keys():
+ _logger.debug("%s: %s", key, ddict[key])
if ddict['event'] not in ['drawingProgress', 'drawingFinished']:
return
label = ddict['parameters']['label']
- if label not in ['HORIZONTAL', 'VERTICAL', 'LINE']:
+ if label not in ['HORIZONTAL', 'VERTICAL', 'LINE']:
return
ddict['mode'] = label
ddict['pixelwidth'] = self._pickerSelectionWidthValue.value()
@@ -531,32 +545,33 @@ class RGBCorrelatorGraph(qt.QWidget):
self._zoomReset()
def _zoomReset(self, replot=None):
- if DEBUG:
- print("_zoomReset")
- if replot is None:
- replot = True
+ _logger.debug("_zoomReset")
if self.graph is not None:
self.graph.resetZoom()
- if replot:
- self.graph.replot()
def _yAutoScaleToggle(self):
if self.graph is not None:
- if self.graph.isYAxisAutoScale():
- self.graph.setYAxisAutoScale(False)
- self.yAutoScaleToolButton.setDown(False)
- else:
- self.graph.setYAxisAutoScale(True)
- self.yAutoScaleToolButton.setDown(True)
+ self.yAutoScaleToolButton.setDown(
+ not self.graph.isYAxisAutoScale())
+ self.graph.setYAxisAutoScale(
+ not self.graph.isYAxisAutoScale())
def _xAutoScaleToggle(self):
if self.graph is not None:
- if self.graph.isXAxisAutoScale():
- self.graph.setXAxisAutoScale(False)
- self.xAutoScaleToolButton.setDown(False)
- else:
- self.graph.setXAxisAutoScale(True)
- self.xAutoScaleToolButton.setDown(True)
+ self.xAutoScaleToolButton.setDown(
+ not self.graph.isXAxisAutoScale())
+ self.graph.setXAxisAutoScale(
+ not self.graph.isXAxisAutoScale())
+
+ def _copyIconSignal(self):
+ pngFile = BytesIO()
+ self.graph.saveGraph(pngFile, fileFormat='png')
+ pngFile.flush()
+ pngFile.seek(0)
+ pngData = pngFile.read()
+ pngFile.close()
+ image = qt.QImage.fromData(pngData, 'png')
+ qt.QApplication.clipboard().setImage(image)
def _saveIconSignal(self):
self.saveDirectory = PyMcaDirs.outputDir
@@ -620,25 +635,26 @@ class RGBCorrelatorGraph(qt.QWidget):
return
if filetype.upper() == "IMAGE":
- self.saveGraphImage(outputFile, original = True)
+ self.saveGraphImage(outputFile, original=True)
elif filetype.upper() == "ZOOMEDIMAGE":
- self.saveGraphImage(outputFile, original = False)
+ self.saveGraphImage(outputFile, original=False)
else:
self.saveGraphWidget(outputFile)
- def saveGraphImage(self, filename, original = False):
+ def saveGraphImage(self, filename, original=False):
format_ = filename[-3:].upper()
- #This is the whole image, not the zoomed one ...
- rgbData, legend, info, pixmap = self.graph.getActiveImage()
+ activeImage = self.graph.getActiveImage()
+ rgbdata = activeImage.getRgbaImageData()
+ # silx to pymca scale convention (a + b x)
+ xScale = activeImage.getOrigin()[0], activeImage.getScale()[0]
+ yScale = activeImage.getOrigin()[1], activeImage.getScale()[1]
if original:
# save whole image
- bgrData = numpy.array(rgbData, copy=True)
- bgrData[:,:,0] = rgbData[:, :, 2]
- bgrData[:,:,2] = rgbData[:, :, 0]
+ bgradata = numpy.array(rgbdata, copy=True)
+ bgradata[:, :, 0] = rgbdata[:, :, 2]
+ bgradata[:, :, 2] = rgbdata[:, :, 0]
else:
- xScale = info.get("plot_xScale", None)
- yScale = info.get("plot_yScale", None)
- shape = rgbData.shape[:2]
+ shape = rgbdata.shape[:2]
xmin, xmax = self.graph.getGraphXLimits()
ymin, ymax = self.graph.getGraphYLimits()
# save zoomed image, for that we have to get the limits
@@ -652,16 +668,16 @@ class RGBCorrelatorGraph(qt.QWidget):
row1 += 1
if col1 < shape[1]:
col1 += 1
- tmpArray = rgbData[row0:row1, col0:col1, :]
- bgrData = numpy.array(tmpArray, copy=True, dtype=rgbData.dtype)
- bgrData[:,:,0] = tmpArray[:, :, 2]
- bgrData[:,:,2] = tmpArray[:, :, 0]
+ tmpArray = rgbdata[row0:row1, col0:col1, :]
+ bgradata = numpy.array(tmpArray, copy=True, dtype=rgbdata.dtype)
+ bgradata[:, :, 0] = tmpArray[:, :, 2]
+ bgradata[:, :, 2] = tmpArray[:, :, 0]
if self.graph.isYAxisInverted():
- qImage = qt.QImage(bgrData, bgrData.shape[1], bgrData.shape[0],
- qt.QImage.Format_RGB32)
+ qImage = qt.QImage(bgradata, bgradata.shape[1], bgradata.shape[0],
+ qt.QImage.Format_ARGB32)
else:
- qImage = qt.QImage(bgrData, bgrData.shape[1], bgrData.shape[0],
- qt.QImage.Format_RGB32).mirrored(False, True)
+ qImage = qt.QImage(bgradata, bgradata.shape[1], bgradata.shape[0],
+ qt.QImage.Format_ARGB32).mirrored(False, True)
pixmap = qt.QPixmap.fromImage(qImage)
if pixmap.save(filename, format_):
return
@@ -669,10 +685,10 @@ class RGBCorrelatorGraph(qt.QWidget):
qt.QMessageBox.critical(self, "Save Error",
"%s" % sys.exc_info()[1])
return
-
+
def saveGraphWidget(self, filename):
format_ = filename[-3:].upper()
- if hasattr(qt.QPixmap, "graphWidget"):
+ if hasattr(qt.QPixmap, "grabWidget"):
# Qt4
pixmap = qt.QPixmap.grabWidget(self.graph.getWidgetHandle())
else:
@@ -691,20 +707,12 @@ class RGBCorrelatorGraph(qt.QWidget):
else:
return False
- def printGraph(self):
- if hasattr(qt.QPixmap, "grabWidget"):
- pixmap = qt.QPixmap.grabWidget(self.graph.getWidgetHandle())
- else:
- pixmap = self.graph.getWidgetHandle().grab()
- self.printPreview.addPixmap(pixmap)
- if self.printPreview.isReady():
- if self.printPreview.isHidden():
- self.printPreview.show()
- self.printPreview.raise_()
-
def selectColormap(self):
qt.QMessageBox.information(self, "Open", "Not implemented (yet)")
+ def _zoomBack(self, pos):
+ self.graph.getLimitsHistory().pop()
+
class MyQLabel(qt.QLabel):
def __init__(self,parent=None,name=None,fl=0,bold=True, color= qt.Qt.red):
qt.QLabel.__init__(self,parent)
diff --git a/PyMca5/PyMcaGui/plotting/ScatterPlotCorrelatorWidget.py b/PyMca5/PyMcaGui/plotting/ScatterPlotCorrelatorWidget.py
index e55aff9..8d95a0d 100644
--- a/PyMca5/PyMcaGui/plotting/ScatterPlotCorrelatorWidget.py
+++ b/PyMca5/PyMcaGui/plotting/ScatterPlotCorrelatorWidget.py
@@ -141,12 +141,12 @@ class ScatterPlotCorrelatorWidget(MaskScatterWidget.MaskScatterWidget):
self.setSelectionCurveData(x, y, legend=None,
color="k",
symbol=".",
- replot=False,
+ resetzoom=False,
replace=True,
xlabel=xLabel,
ylabel=yLabel,
selectable=False)
- self._updatePlot(replot=False, replace=True)
+ self._updatePlot(resetzoom=False, replace=True)
#matplotlib needs a zoom reset to update the scales
# that problem does not seem to be present with OpenGL
self.resetZoom()
diff --git a/PyMca5/PyMcaGui/plotting/SilxMaskImageWidget.py b/PyMca5/PyMcaGui/plotting/SilxMaskImageWidget.py
index c8345ea..6df787a 100644
--- a/PyMca5/PyMcaGui/plotting/SilxMaskImageWidget.py
+++ b/PyMca5/PyMcaGui/plotting/SilxMaskImageWidget.py
@@ -1,5 +1,5 @@
# /*#########################################################################
-# Copyright (C) 2004-2017 V.A. Sole, European Synchrotron Radiation Facility
+# Copyright (C) 2004-2018 European Synchrotron Radiation Facility
#
# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
# the ESRF by the Software group.
@@ -112,7 +112,8 @@ def convertToRowAndColumn(x, y, shape,
class MyMaskToolsWidget(MaskToolsWidget):
"""Backport of the setSelectionMask behavior implemented in silx 0.6.0,
- to synchronize mask parameters with the active image."""
+ to synchronize mask parameters with the active image.
+ This widget must not be used with silx >= 0.6"""
def setSelectionMask(self, mask, copy=True):
"""Set the mask to a new array.
:param numpy.ndarray mask: The array to use for the mask.
@@ -157,7 +158,7 @@ class MyMaskToolsDockWidget(MaskToolsDockWidget):
"""
def __init__(self, parent=None, plot=None, name='Mask'):
super(MyMaskToolsDockWidget, self).__init__(parent, plot, name)
- if silx.version < "0.6":
+ if silx.version_info < (0, 6):
self.setWidget(MyMaskToolsWidget(plot=plot))
self.widget().sigMaskChanged.connect(self._emitSigMaskChanged)
@@ -206,6 +207,10 @@ class SaveImageListAction(qt.QAction):
if filename.lower().endswith(".edf"):
ArraySave.save2DArrayListAsEDF(imageList, filename, labels)
+ elif filename.lower().endswith(".tif"):
+ ArraySave.save2DArrayListAsMonochromaticTiff(imageList,
+ filename,
+ labels)
elif filename.lower().endswith(".csv"):
assert csvseparator is not None
ArraySave.save2DArrayListAsASCII(imageList, filename, labels,
@@ -267,7 +272,8 @@ class SaveImageListAction(qt.QAction):
filedialog.setFileMode(filedialog.AnyFile)
filedialog.setAcceptMode(qt.QFileDialog.AcceptSave)
filedialog.setWindowIcon(qt.QIcon(qt.QPixmap(IconDict["gioconda16"])))
- formatlist = ["ASCII Files *.dat",
+ formatlist = ["TIFF Files *.tif",
+ "ASCII Files *.dat",
"EDF Files *.edf",
'CSV(, separated) Files *.csv',
'CSV(; separated) Files *.csv',
@@ -307,8 +313,7 @@ class SaveImageListAction(qt.QAction):
class SaveMatplotlib(qt.QAction):
- """Save current image and mask (if any) in a :class:`MaskImageWidget`
- to EDF or CSV"""
+ """Save current image ho high quality graphics using matplotlib"""
def __init__(self, title, maskImageWidget):
super(SaveMatplotlib, self).__init__(QString(title),
maskImageWidget)
@@ -756,15 +761,16 @@ class SilxMaskImageWidget(qt.QMainWindow):
The mask can be cropped or padded to fit active image,
the returned shape is that of the active image.
"""
- if mask is None:
- mask = numpy.zeros_like(self._getMaskToolsDockWidget().getSelectionMask())
- if not len(mask):
- return
# disconnect temporarily to avoid infinite loop
self._getMaskToolsDockWidget().sigMaskChanged.disconnect(
self._emitMaskImageWidgetSignal)
- ret = self._getMaskToolsDockWidget().setSelectionMask(mask,
- copy=copy)
+ if mask is None and silx.version_info <= (0, 7, 0):
+ self._getMaskToolsDockWidget().resetSelectionMask()
+ ret = None
+ else:
+ # from silx 0.8 onwards, setSelectionMask(None) is supported
+ ret = self._getMaskToolsDockWidget().setSelectionMask(mask,
+ copy=copy)
self._getMaskToolsDockWidget().sigMaskChanged.connect(
self._emitMaskImageWidgetSignal)
return ret
@@ -775,7 +781,7 @@ class SilxMaskImageWidget(qt.QMainWindow):
:param bool copy: True (default) to get a copy of the mask.
If False, the returned array MUST not be modified.
:return: The array of the mask with dimension of the 'active' image.
- If there is no active image, an empty array is returned.
+ If there is no active image, None is returned.
:rtype: 2D numpy.ndarray of uint8
"""
return self._getMaskToolsDockWidget().getSelectionMask(copy=copy)
diff --git a/PyMca5/PyMcaGui/plotting/_ImageProfile.py b/PyMca5/PyMcaGui/plotting/_ImageProfile.py
index e57986c..0943317 100644
--- a/PyMca5/PyMcaGui/plotting/_ImageProfile.py
+++ b/PyMca5/PyMcaGui/plotting/_ImageProfile.py
@@ -37,9 +37,10 @@ Functions to extract a profile curve of a region of interest in an image.
# import ######################################################################
import numpy
+import logging
from PyMca5.PyMcaMath.fitting import SpecfitFuns
-DEBUG = 0
+_logger = logging.getLogger(__name__)
# utils #######################################################################
@@ -209,8 +210,7 @@ def _getROILineProfileCurve(image, roiStart, roiEnd, roiWidth,
coordsRange = row0, row1
if nPoints == 1: # all points are the same
- if DEBUG:
- print("START AND END POINT ARE THE SAME!!")
+ _logger.debug("START AND END POINT ARE THE SAME!!")
return None
# the coordinates of the reference points
@@ -249,9 +249,8 @@ def _getROILineProfileCurve(image, roiStart, roiEnd, roiWidth,
newRow0 = 0.0
newRow1 = - (col1 - col0) * sinalpha + (row1 - row0) * cosalpha
- if DEBUG:
- print("new X0 Y0 = %f, %f " % (newCol0, newRow0))
- print("new X1 Y1 = %f, %f " % (newCol1, newRow1))
+ _logger.debug("new X0 Y0 = %f, %f ", newCol0, newRow0)
+ _logger.debug("new X1 Y1 = %f, %f ", newCol1, newRow1)
tmpX = numpy.linspace(newCol0, newCol1,
nPoints).astype(numpy.float)
@@ -260,19 +259,19 @@ def _getROILineProfileCurve(image, roiStart, roiEnd, roiWidth,
rotMatrix[0, 1] = - sinalpha
rotMatrix[1, 0] = sinalpha
rotMatrix[1, 1] = cosalpha
- if DEBUG:
+ if _logger.getEffectiveLevel() == logging.DEBUG:
# test if I recover the original points
testX = numpy.zeros((2, 1), numpy.float)
colRow = numpy.dot(rotMatrix, testX)
- print("Recovered X0 = %f" % (colRow[0, 0] + col0))
- print("Recovered Y0 = %f" % (colRow[1, 0] + row0))
- print("It should be = %f, %f" % (col0, row0))
+ _logger.debug("Recovered X0 = %f", colRow[0, 0] + col0)
+ _logger.debug("Recovered Y0 = %f", colRow[1, 0] + row0)
+ _logger.debug("It should be = %f, %f", col0, row0)
testX[0, 0] = newCol1
testX[1, 0] = newRow1
colRow = numpy.dot(rotMatrix, testX)
- print("Recovered X1 = %f" % (colRow[0, 0] + col0))
- print("Recovered Y1 = %f" % (colRow[1, 0] + row0))
- print("It should be = %f, %f" % (col1, row1))
+ _logger.debug("Recovered X1 = %f", colRow[0, 0] + col0)
+ _logger.debug("Recovered Y1 = %f", colRow[1, 0] + row0)
+ _logger.debug("It should be = %f, %f", col1, row1)
# find the drawing limits
testX = numpy.zeros((2, 4), numpy.float)
@@ -290,21 +289,18 @@ def _getROILineProfileCurve(image, roiStart, roiEnd, roiWidth,
for a in rowLimits0:
if (a >= image.shape[0]) or (a < 0):
- if DEBUG:
- print("outside row limits", a)
+ _logger.debug("outside row limits %s", a)
return None
for a in colLimits0:
if (a >= image.shape[1]) or (a < 0):
- if DEBUG:
- print("outside column limits", a)
+ _logger.debug("outside column limits %s", a)
return None
r0 = rowLimits0[0]
r1 = rowLimits0[1]
if r0 > r1:
- if DEBUG:
- print("r0 > r1", r0, r1)
+ _logger.debug("r0 > r1 %s %s", r0, r1)
raise ValueError("r0 > r1")
x = numpy.zeros((2, nPoints), numpy.float)