anon-iclr-submission/benchname-bug-localization huggingface dataset:
Repository: silx-kit/silx
Issue: Issue with position info picking

This issue happens from time to time when displaying an image occupying the whole plot area with a `Plot2D`:
```
ERROR:silx.gui.plot.tools.PositionInfo:Error while converting coordinates (514.000000, 48.000000)with converter 'Data'
ERROR:silx.gui.plot.tools.PositionInfo:Traceback (most recent call last):
  File "silx/gui/plot/tools/PositionInfo.py", line 273, in _updateStatusBar
    value = func(xData, yData)
  File "silx/utils/weakref.py", line 178, in __call__
    return fn(*args, **kwargs)
  File "silx/gui/plot/PlotWindow.py", line 938, in _getImageValue
    value = image.getData(copy=False)[row, col]
IndexError: index 200 is out of bounds for axis 0 with size 200
```
The picking returns an index outside the image range (here [0, 199])....
It seems to only happen with the matplotlib backend.


Changed files:
silx/gui/plot/backends/BackendMatplotlib.py

diff --git a/silx/gui/plot/backends/BackendMatplotlib.py b/silx/gui/plot/backends/BackendMatplotlib.py
index df7589a58..e2872e8ae 100755
--- a/silx/gui/plot/backends/BackendMatplotlib.py
+++ b/silx/gui/plot/backends/BackendMatplotlib.py
@@ -375,8 +375,9 @@ class Image(AxesImage):
             x, y = mouseevent.xdata, mouseevent.ydata
             ox, oy = self.__silx_origin
             sx, sy = self.__silx_scale
-            column = int((x - ox) / sx)
-            row = int((y - oy) / sy)
+            height, width = self.get_size()
+            column = numpy.clip(int((x - ox) / sx), 0, width - 1)
+            row = numpy.clip(int((y - oy) / sy), 0, height - 1)
             info['ind'] = (row,), (column,)
         return inside, info
Repository: silx-kit/silx
Issue: Data.path() fails if data_slice is not an iterable

For now `DataUrl` allows to define data slice as a not iterable object (like an int).
But in this case, call to DataUrl.path() raise an error.

source code to reproduce:
``` python
url = DataUrl(scheme="silx", file_path="/foo.h5", data_slice=1)
url.path()
```
the call of url.path() raises the error:

``` bash
data_slice = ",".join([slice_to_string(s) for s in self.__data_slice])
TypeError: 'int' object is not iterable
```

Changed files:
silx/io/test/test_url.py, silx/io/url.py

diff --git a/silx/io/test/test_url.py b/silx/io/test/test_url.py
index 5093fc258..e68c67a7b 100644
--- a/silx/io/test/test_url.py
+++ b/silx/io/test/test_url.py
@@ -197,6 +197,15 @@ class TestDataUrl(unittest.TestCase):
         url = DataUrl(scheme="silx", file_path="/foo.h5", data_slice=(5, 1))
         self.assertFalse(url.is_valid())
 
+    def test_path_creation(self):
+        """make sure the construction of path succeed and that we can
+        recreate a DataUrl from a path"""
+        for data_slice in (1, (1,)):
+            with self.subTest(data_slice=data_slice):
+                url = DataUrl(scheme="silx", file_path="/foo.h5", data_slice=data_slice)
+                path = url.path()
+                DataUrl(path=path)
+
 
 def suite():
     test_suite = unittest.TestSuite()
diff --git a/silx/io/url.py b/silx/io/url.py
index c8cdc847c..c7231f1f0 100644
--- a/silx/io/url.py
+++ b/silx/io/url.py
@@ -30,6 +30,7 @@ __date__ = "29/01/2018"
 
 import logging
 import six
+from collections import Iterable
 
 parse = six.moves.urllib.parse
 
@@ -297,7 +298,10 @@ class DataUrl(object):
             if self.__data_path is not None:
                 queries.append("path=" + self.__data_path)
             if self.__data_slice is not None:
-                data_slice = ",".join([slice_to_string(s) for s in self.__data_slice])
+                if isinstance(self.__data_slice, Iterable):
+                    data_slice = ",".join([slice_to_string(s) for s in self.__data_slice])
+                else:
+                    data_slice = slice_to_string(self.__data_slice)
                 queries.append("slice=" + data_slice)
             query = "&".join(queries)
Repository: silx-kit/silx
Issue: [plot] Data background is not used when plot do not display the axes

I think it is a regression.

- Set both background with a different color
- One is displayed outside the data view (beyond the axes)
- Another one is dislayed under the data (inside the axes)
- Switch the plot mode to hide the axes
- The data background is not anymore used (i think we expect it to be used)

Changed files:
silx/gui/plot/backends/BackendMatplotlib.py

diff --git a/silx/gui/plot/backends/BackendMatplotlib.py b/silx/gui/plot/backends/BackendMatplotlib.py
index 03544ab52..df7589a58 100755
--- a/silx/gui/plot/backends/BackendMatplotlib.py
+++ b/silx/gui/plot/backends/BackendMatplotlib.py
@@ -1199,7 +1199,7 @@ class BackendMatplotlib(BackendBase.BackendBase):
         else:
             dataBackgroundColor = backgroundColor
 
-        if self.ax.axison:
+        if self.ax.get_frame_on():
             self.fig.patch.set_facecolor(backgroundColor)
             if self._matplotlibVersion < _parse_version('2'):
                 self.ax.set_axis_bgcolor(dataBackgroundColor)
@@ -1218,7 +1218,7 @@ class BackendMatplotlib(BackendBase.BackendBase):
             gridColor = foregroundColor
 
         for axes in (self.ax, self.ax2):
-            if axes.axison:
+            if axes.get_frame_on():
                 axes.spines['bottom'].set_color(foregroundColor)
                 axes.spines['top'].set_color(foregroundColor)
                 axes.spines['right'].set_color(foregroundColor)
Repository: silx-kit/silx
Issue: [plot] addTabbedDockWidget do not manage removed docks

This API stores docks inside `_dockWidgets`, but i see nowhere a function to clean up this list.

As result we can add docks, but we can't remove them.

I use to create ROI docks that i destroy. At the second call, the layout is broken, cause the code tries to tabbify the new one, on the previous one which not anymore own by the plot, or whatever.

Changed files:
silx/gui/plot/PlotWindow.py, silx/gui/plot/test/testPlotWindow.py

diff --git a/silx/gui/plot/PlotWindow.py b/silx/gui/plot/PlotWindow.py
index 069dbc60d..a6abb3798 100644
--- a/silx/gui/plot/PlotWindow.py
+++ b/silx/gui/plot/PlotWindow.py
@@ -464,7 +464,7 @@ class PlotWindow(PlotWidget):
         """Add a dock widget as a new tab if there are already dock widgets
         in the plot. When the first tab is added, the area is chosen
         depending on the plot geometry:
-        it the window is much wider than it is high, the right dock area
+        if the window is much wider than it is high, the right dock area
         is used, else the bottom dock area is used.
 
         :param dock_widget: Instance of :class:`QDockWidget` to be added.
@@ -485,6 +485,17 @@ class PlotWindow(PlotWidget):
             self.tabifyDockWidget(self._dockWidgets[0],
                                   dock_widget)
 
+    def removeDockWidget(self, dockwidget):
+        """Removes the *dockwidget* from the main window layout and hides it.
+
+        Note that the *dockwidget* is *not* deleted.
+
+        :param QDockWidget dockwidget:
+        """
+        if dockwidget in self._dockWidgets:
+            self._dockWidgets.remove(dockwidget)
+        super(PlotWindow, self).removeDockWidget(dockwidget)
+
     def __handleFirstDockWidgetShow(self, visible):
         """Handle QDockWidget.visibilityChanged
 
diff --git a/silx/gui/plot/test/testPlotWindow.py b/silx/gui/plot/test/testPlotWindow.py
index a8d83de7a..8e7b35cdc 100644
--- a/silx/gui/plot/test/testPlotWindow.py
+++ b/silx/gui/plot/test/testPlotWindow.py
@@ -86,6 +86,29 @@ class TestPlotWindow(TestCaseQt):
         self.assertIsNot(toolButton, None)
         self.mouseClick(toolButton, qt.Qt.LeftButton)
 
+    def testDockWidgets(self):
+        """Test add/remove dock widgets"""
+        dock1 = qt.QDockWidget('Test 1')
+        dock1.setWidget(qt.QLabel('Test 1'))
+
+        self.plot.addTabbedDockWidget(dock1)
+        self.qapp.processEvents()
+
+        self.plot.removeDockWidget(dock1)
+        self.qapp.processEvents()
+
+        dock2 = qt.QDockWidget('Test 2')
+        dock2.setWidget(qt.QLabel('Test 2'))
+
+        self.plot.addTabbedDockWidget(dock2)
+        self.qapp.processEvents()
+
+        if qt.BINDING != 'PySide2':
+            # Weird bug with PySide2 later upon gc.collect() when getting the layout
+            self.assertNotEqual(self.plot.layout().indexOf(dock2),
+                                -1,
+                                "dock2 not properly displayed")
+
     def testToolAspectRatio(self):
         self.plot.toolBar()
         self.plot.keepDataAspectRatioButton.keepDataAspectRatio()
Repository: silx-kit/silx
Issue: Exception raised in ColormapDialog

With recent updates of the `ColormapDialog`, I get this error from time to time:
```
Exception ignored in: <bound method ColormapDialog._itemAboutToFinalize of <silx.gui.dialog.ColormapDialog.ColormapDialog object at 0x7f12b196d438>>
Traceback (most recent call last):
  File "/users/tvincent/src/silx/build/lib.linux-x86_64-3.7/silx/gui/dialog/ColormapDialog.py", line 1201, in _itemAboutToFinalize
    self.setItem(None)
  File "/users/tvincent/src/silx/build/lib.linux-x86_64-3.7/silx/gui/dialog/ColormapDialog.py", line 1148, in setItem
    self._invalidateData()
  File "/users/tvincent/src/silx/build/lib.linux-x86_64-3.7/silx/gui/dialog/ColormapDialog.py", line 957, in _invalidateData
    if self.isVisible():
RuntimeError: wrapped C/C++ object of type ColormapDialog has been deleted
```


Changed files:
silx/gui/dialog/ColormapDialog.py

diff --git a/silx/gui/dialog/ColormapDialog.py b/silx/gui/dialog/ColormapDialog.py
index ead85d152..336cc47e2 100644
--- a/silx/gui/dialog/ColormapDialog.py
+++ b/silx/gui/dialog/ColormapDialog.py
@@ -1,7 +1,7 @@
 # coding: utf-8
 # /*##########################################################################
 #
-# Copyright (c) 2004-2019 European Synchrotron Radiation Facility
+# Copyright (c) 2004-2020 European Synchrotron Radiation Facility
 #
 # Permission is hereby granted, free of charge, to any person obtaining a copy
 # of this software and associated documentation files (the "Software"), to deal
@@ -82,6 +82,7 @@ import weakref
 from silx.math.combo import min_max
 from silx.gui.plot import items
 from silx.gui import icons
+from silx.gui.qt import inspect as qtinspect
 from silx.gui.widgets.ColormapNameComboBox import ColormapNameComboBox
 from silx.math.histogram import Histogramnd
 from silx.utils import deprecation
@@ -1187,17 +1188,17 @@ class ColormapDialog(qt.QDialog):
 
     def _colormapAboutToFinalize(self, weakrefColormap):
         """Callback when the data weakref is about to be finalized."""
-        if self._colormap is weakrefColormap:
+        if self._colormap is weakrefColormap and qtinspect.isValid(self):
             self.setColormap(None)
 
     def _dataAboutToFinalize(self, weakrefData):
         """Callback when the data weakref is about to be finalized."""
-        if self._data is weakrefData:
+        if self._data is weakrefData and qtinspect.isValid(self):
             self.setData(None)
 
     def _itemAboutToFinalize(self, weakref):
         """Callback when the data weakref is about to be finalized."""
-        if self._item is weakref:
+        if self._item is weakref and qtinspect.isValid(self):
             self.setItem(None)
 
     @deprecation.deprecated(reason="It is private data", since_version="0.13")
Repository: silx-kit/silx
Issue: [plot] The lines displayed by the crossair option blinking a lot

Sometimes it is displayed, sometimes not depending on the mouse location.

As result sometimes the mouse stop and there is no crossair anymore.

Changed files:
silx/gui/plot/backends/BackendMatplotlib.py

diff --git a/silx/gui/plot/backends/BackendMatplotlib.py b/silx/gui/plot/backends/BackendMatplotlib.py
index 1b9fdea0b..233649431 100755
--- a/silx/gui/plot/backends/BackendMatplotlib.py
+++ b/silx/gui/plot/backends/BackendMatplotlib.py
@@ -1266,7 +1266,7 @@ class BackendMatplotlibQt(FigureCanvasQTAgg, BackendMatplotlib):
     def _onMouseMove(self, event):
         if self._graphCursor:
             lineh, linev = self._graphCursor
-            if event.inaxes != self.ax and lineh.get_visible():
+            if event.inaxes not in (self.ax, self.ax2) and lineh.get_visible():
                 lineh.set_visible(False)
                 linev.set_visible(False)
                 self._plot._setDirtyPlot(overlayOnly=True)
Repository: silx-kit/silx
Issue: [plot] Adding manually a non-visible item to a plot make this item unusable

Diagnosed together with @t20100 

This not works
```
        self.__toolTipMarker = Marker()
        self.__toolTipMarker._setLegend("marker-tooltip")
        self.__toolTipMarker.setColor("pink")
        self.__toolTipMarker.setSymbol("+")
        self.__toolTipMarker.setSymbolSize(10)
        self.__toolTipMarker.setVisible(False)
        self.__plot._add(self.__toolTipMarker)
```
This works
```
        self.__toolTipMarker = Marker()
        self.__toolTipMarker._setLegend("marker-tooltip")
        self.__toolTipMarker.setColor("pink")
        self.__toolTipMarker.setSymbol("+")
        self.__toolTipMarker.setSymbolSize(10)
        self.__plot._add(self.__toolTipMarker)
        self.__toolTipMarker.setVisible(False)
```


Changed files:
silx/gui/plot/PlotWidget.py

diff --git a/silx/gui/plot/PlotWidget.py b/silx/gui/plot/PlotWidget.py
index 49e444a47..e47249e2e 100755
--- a/silx/gui/plot/PlotWidget.py
+++ b/silx/gui/plot/PlotWidget.py
@@ -624,8 +624,7 @@ class PlotWidget(qt.QMainWindow):
         # Add item to plot
         self._content[key] = item
         item._setPlot(self)
-        if item.isVisible():
-            self._itemRequiresUpdate(item)
+        self._itemRequiresUpdate(item)
         if isinstance(item, items.DATA_ITEMS):
             self._invalidateDataRange()  # TODO handle this automatically
Repository: silx-kit/silx
Issue: [plot] StackView issue with colormap

There seems to be an issue with `StackView` colormap handling.

To reproduce:

```
import numpy
from silx import sx                                                     
w = sx.StackView()                                                      
w.show()                                                                
w.setColormap(colormap='viridis', autoscale=True)                       
w.setStack(numpy.arange(10**3).reshape(10, 10, 10))
```

and the colormap used is switching to the grey one....

Setting the colormap with: `w.setColormap(Colormap('viridis'))` or `w.setColormap(colormap='viridis')` works fine.

This looks to be due to setting `self.__autoscaleCmap` (https://github.com/silx-kit/silx/blob/master/silx/gui/plot/StackView.py#L834), which looks like not needed any longer and causing trouble.

Thanks to Alessandro for spotting it.


Changed files:
silx/gui/plot/StackView.py

diff --git a/silx/gui/plot/StackView.py b/silx/gui/plot/StackView.py
index 904e526e3..7e4c389c2 100644
--- a/silx/gui/plot/StackView.py
+++ b/silx/gui/plot/StackView.py
@@ -542,7 +542,12 @@ class StackView(qt.QMainWindow):
         # This call to setColormap redefines the meaning of autoscale
         # for 3D volume: take global min/max rather than frame min/max
         if self.__autoscaleCmap:
-            self.setColormap(autoscale=True)
+            # note: there is no real autoscale in the stack widget, it is more
+            # like a hack computing stack min and max
+            colormap = self.getColormap()
+            _vmin, _vmax = colormap.getColormapRange(data=self._stack)
+            colormap.setVRange(_vmin, _vmax)
+            self.setColormap(colormap=colormap)
 
         # init plot
         self._plot.addImage(self.__transposed_view[0, :, :],
Repository: silx-kit/silx
Issue: [OpenCL] Issue with the destructor of Processing...

In PyFAI I have random issues when destroying OpenCL contexts where self.sem is already distroyed when calling the clean-up of the log.


Changed files:
silx/opencl/processing.py

diff --git a/silx/opencl/processing.py b/silx/opencl/processing.py
index 707aa726d..6b475b9a0 100644
--- a/silx/opencl/processing.py
+++ b/silx/opencl/processing.py
@@ -41,7 +41,7 @@ __author__ = "Jerome Kieffer"
 __contact__ = "Jerome.Kieffer@ESRF.eu"
 __license__ = "MIT"
 __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
-__date__ = "11/01/2019"
+__date__ = "05/08/2019"
 __status__ = "stable"
 
 
@@ -152,9 +152,12 @@ class OpenclProcessing(object):
     def __del__(self):
         """Destructor: release all buffers and programs
         """
-        self.reset_log()
-        self.free_kernels()
-        self.free_buffers()
+        try:
+            self.reset_log()
+            self.free_kernels()
+            self.free_buffers()
+        except Exception:
+            pass
         self.queue = None
         self.device = None
         self.ctx = None
Repository: silx-kit/silx
Issue: Error with python-3.8

Apparently the destrurctor is not making a copy of the keys to destroy the dict:
```
Traceback (most recent call last):
  File "/home/jerome/workspace/silx/build/lib.linux-x86_64-3.8/silx/opencl/sift/alignment.py", line 149, in __del__
    self._free_buffers()
  File "/home/jerome/workspace/silx/build/lib.linux-x86_64-3.8/silx/opencl/sift/alignment.py", line 171, in _free_buffers
    for buffer_name in self.cl_mem:
RuntimeError: dictionary keys changed during iteration
```

Changed files:
silx/opencl/sift/alignment.py

diff --git a/silx/opencl/sift/alignment.py b/silx/opencl/sift/alignment.py
index c09df9137..80241079f 100644
--- a/silx/opencl/sift/alignment.py
+++ b/silx/opencl/sift/alignment.py
@@ -37,7 +37,7 @@ __authors__ = ["Jérôme Kieffer", "Pierre Paleo"]
 __contact__ = "jerome.kieffer@esrf.eu"
 __license__ = "MIT"
 __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
-__date__ = "09/02/2018"
+__date__ = "06/05/2020"
 __status__ = "production"
 
 import os
@@ -168,11 +168,11 @@ class LinearAlign(OpenclProcessing):
         """
         free all memory allocated on the device
         """
-        for buffer_name in self.cl_mem:
+        for buffer_name in list(self.cl_mem.keys()):
             if self.cl_mem[buffer_name] is not None:
                 try:
-                    del self.cl_mem[buffer_name]
-                    self.cl_mem[buffer_name] = None
+                    buffer = self.cl_mem.pop(buffer_name)
+                    del buffer
                 except pyopencl.LogicError:
                     logger.error("Error while freeing buffer %s" % buffer_name)
Repository: silx-kit/silx
Issue: Plot: Exception with 0 image and sqrt colormap

Maybe not the last silx version.
```
ERROR:silx.gui.qt._qt:<class 'AssertionError'>    File "/users/valls/Software/miniconda3/envs/blissenv/lib/python3.7/site-packages/silx/gui/_glutils/OpenGLWidget.py", line 224, in paintGL
    parent.paintGL()
  File "/users/valls/Software/miniconda3/envs/blissenv/lib/python3.7/site-packages/silx/gui/plot/backends/BackendOpenGL.py", line 413, in paintGL
    self._paintFBOGL()
  File "/users/valls/Software/miniconda3/envs/blissenv/lib/python3.7/site-packages/silx/gui/plot/backends/BackendOpenGL.py", line 363, in _paintFBOGL
    self._renderPlotAreaGL()
  File "/users/valls/Software/miniconda3/envs/blissenv/lib/python3.7/site-packages/silx/gui/plot/backends/BackendOpenGL.py", line 678, in _renderPlotAreaGL
    self._renderItems(overlay=False)
  File "/users/valls/Software/miniconda3/envs/blissenv/lib/python3.7/site-packages/silx/gui/plot/backends/BackendOpenGL.py", line 454, in _renderItems
    isXLog, isYLog)
  File "/users/valls/Software/miniconda3/envs/blissenv/lib/python3.7/site-packages/silx/gui/plot/backends/glutils/GLPlotImage.py", line 468, in render
    self._renderLinear(matrix)
  File "/users/valls/Software/miniconda3/envs/blissenv/lib/python3.7/site-packages/silx/gui/plot/backends/glutils/GLPlotImage.py", line 397, in _renderLinear
    self._setCMap(prog)
  File "/users/valls/Software/miniconda3/envs/blissenv/lib/python3.7/site-packages/silx/gui/plot/backends/glutils/GLPlotImage.py", line 340, in _setCMap
    dataMin, dataMax = self.cmapRange  # If log, it is stricly positive
  File "/users/valls/Software/miniconda3/envs/blissenv/lib/python3.7/site-packages/silx/gui/plot/backends/glutils/GLPlotImage.py", line 286, in cmapRange
    assert self._cmapRange[0] >= 0. and self._cmapRange[1] > 0.
```

Changed files:
silx/gui/plot/backends/glutils/GLPlotImage.py

diff --git a/silx/gui/plot/backends/glutils/GLPlotImage.py b/silx/gui/plot/backends/glutils/GLPlotImage.py
index cfb57c6c0..fb672fa69 100644
--- a/silx/gui/plot/backends/glutils/GLPlotImage.py
+++ b/silx/gui/plot/backends/glutils/GLPlotImage.py
@@ -291,7 +291,7 @@ class GLPlotColormap(_GLPlotData2D):
         if self.normalization == 'log':
             assert self._cmapRange[0] > 0. and self._cmapRange[1] > 0.
         elif self.normalization == 'sqrt':
-            assert self._cmapRange[0] >= 0. and self._cmapRange[1] > 0.
+            assert self._cmapRange[0] >= 0. and self._cmapRange[1] >= 0.
         return self._cmapRange
 
     @cmapRange.setter
Repository: silx-kit/silx
Issue: [roi] setColor do not update the plot

Sounds like from my test that the `setColor` from ROI object do not trigger a repaint of the plot.

As result the ROI color is updated at the next plot refresh, like a zoom in/out.

Changed files:
silx/gui/plot/items/roi.py

diff --git a/silx/gui/plot/items/roi.py b/silx/gui/plot/items/roi.py
index ff73fe6b2..7de57232f 100644
--- a/silx/gui/plot/items/roi.py
+++ b/silx/gui/plot/items/roi.py
@@ -474,19 +474,18 @@ class RegionOfInterest(_RegionOfInterestBase, core.HighlightedMixIn):
             style = self.getCurrentStyle()
             self._updatedStyle(event, style)
         else:
-            hilighted = self.isHighlighted()
-            if hilighted:
-                if event == items.ItemChangedType.HIGHLIGHTED_STYLE:
-                    style = self.getCurrentStyle()
-                    self._updatedStyle(event, style)
-            else:
-                if event in [items.ItemChangedType.COLOR,
-                             items.ItemChangedType.LINE_STYLE,
-                             items.ItemChangedType.LINE_WIDTH,
-                             items.ItemChangedType.SYMBOL,
-                             items.ItemChangedType.SYMBOL_SIZE]:
-                    style = self.getCurrentStyle()
-                    self._updatedStyle(event, style)
+            styleEvents = [items.ItemChangedType.COLOR,
+                           items.ItemChangedType.LINE_STYLE,
+                           items.ItemChangedType.LINE_WIDTH,
+                           items.ItemChangedType.SYMBOL,
+                           items.ItemChangedType.SYMBOL_SIZE]
+            if self.isHighlighted():
+                styleEvents.append(items.ItemChangedType.HIGHLIGHTED_STYLE)
+
+            if event in styleEvents:
+                style = self.getCurrentStyle()
+                self._updatedStyle(event, style)
+
         super(RegionOfInterest, self)._updated(event, checkVisibility)
 
     def _updatedStyle(self, event, style):
Repository: silx-kit/silx
Issue: Changing ROI mode while having an incomplete ROI leads to an exception

To reproduce, use `examples/plotInteractiveImageROI.py`, select polygon ROI mode, start creating a polygon with a few points, then while the polygon is not closed, select the rectangle ROI mode.
This leads to:

```
Traceback (most recent call last):
  File "silx/gui/plot/tools/roi.py", line 294, in _plotInteractiveModeChanged
    self.__roiInteractiveModeEnded()
  File "silx/gui/plot/tools/roi.py", line 669, in __roiInteractiveModeEnded
    self.removeRoi(self._drawnROI)
  File "silx/gui/plot/tools/roi.py", line 551, in removeRoi
    self._restart()
  File "silx/gui/plot/tools/roi.py", line 646, in _restart
    firstInteractionShapeKind = roiClass.getFirstInteractionShape()
AttributeError: 'NoneType' object has no attribute 'getFirstInteractionShape'

```

Changed files:
silx/gui/plot/tools/roi.py

diff --git a/silx/gui/plot/tools/roi.py b/silx/gui/plot/tools/roi.py
index 431ecb222..5906bc2b5 100644
--- a/silx/gui/plot/tools/roi.py
+++ b/silx/gui/plot/tools/roi.py
@@ -666,8 +666,9 @@ class RegionOfInterestManager(qt.QObject):
 
             if self._drawnROI is not None:
                 # Cancel ROI create
-                self.removeRoi(self._drawnROI)
+                roi = self._drawnROI
                 self._drawnROI = None
+                self.removeRoi(roi)
 
             plot = self.parent()
             if plot is not None:
Repository: silx-kit/silx
Issue: [qt] Conflict with ipython loading pyqt4 and silx loading pyqt5

From ipython, when there is both pyqt4 and pyqt5, it happens that %gui qt loads pyqt4 but silx.gui.qt try to load pyqt5...

Changed files:
silx/gui/qt.py

diff --git a/silx/gui/qt.py b/silx/gui/qt.py
index 370b1af0d..0664dff37 100644
--- a/silx/gui/qt.py
+++ b/silx/gui/qt.py
@@ -72,13 +72,13 @@ HAS_SVG = False
 """True if Qt provides support for Scalable Vector Graphics (QtSVG)."""
 
 # First check for an already loaded wrapper
-if 'PySide' in sys.modules:
+if 'PySide.QtCore' in sys.modules:
     BINDING = 'PySide'
 
-elif 'PyQt5' in sys.modules:
+elif 'PyQt5.QtCore' in sys.modules:
     BINDING = 'PyQt5'
 
-elif 'PyQt4' in sys.modules:
+elif 'PyQt4.QtCore' in sys.modules:
     BINDING = 'PyQt4'
 
 else:  # Then try Qt bindings
Repository: silx-kit/silx
Issue: [plot3d] Issue with color picker in parameter tree on MacOS

On MacOS El Captain with python 3.4, PyQt4.8.7, there is a issue with the color picker: changing one color in the param tree changes other colors… Cancel and OK buttons are added to the dialog each time  the dialog is opened.

Changed files:
silx/gui/plot3d/SFViewParamTree.py

diff --git a/silx/gui/plot3d/SFViewParamTree.py b/silx/gui/plot3d/SFViewParamTree.py
index ef4b850d3..84ea2a428 100644
--- a/silx/gui/plot3d/SFViewParamTree.py
+++ b/silx/gui/plot3d/SFViewParamTree.py
@@ -33,6 +33,7 @@ __license__ = "MIT"
 __date__ = "10/01/2017"
 
 import logging
+import sys
 
 import numpy
 
@@ -635,6 +636,10 @@ class QColorEditor(qt.QWidget):
 
     def __showColorDialog(self):
         dialog = qt.QColorDialog(parent=self)
+        if sys.platform == 'darwin':
+            # Use of native color dialog on macos might cause problems
+            dialog.setOption(qt.QColorDialog.DontUseNativeDialog, True)
+
         self.__previousColor = self.__color
         dialog.setAttribute(qt.Qt.WA_DeleteOnClose)
         dialog.setModal(True)
@@ -1216,6 +1221,8 @@ class TreeView(qt.QTreeView):
         super(TreeView, self).__init__(parent)
         self.__openedIndex = None
 
+        self.setIconSize(qt.QSize(16, 16))
+
         header = self.header()
         if hasattr(header, 'setSectionResizeMode'):  # Qt5
             header.setSectionResizeMode(qt.QHeaderView.ResizeToContents)
Repository: silx-kit/silx
Issue: ModuleNotFoundError: No module named 'concurrent.futures'; 'concurrent' is not a package

Fun issue, no idea why it happens now on my machine.

This avoid to launch Flint with OpenGL, so it is quite annoying.

```
In [1]: import silx.gui.utils.glutils              
   ...: silx.gui.utils.glutils.isOpenGLAvailable()                                                                                                                                                                                                   
['/users/valls/Software/miniconda3/envs/silxenv/bin/python', '/users/valls/workspace/silx.git/build/lib.linux-x86_64-3.7/silx/gui/utils/glutils.py', '2', '1']
Traceback (most recent call last):
  File "/users/valls/workspace/silx.git/build/lib.linux-x86_64-3.7/silx/gui/utils/glutils.py", line 30, in <module>
    import subprocess
  File "/users/valls/Software/miniconda3/envs/silxenv/lib/python3.7/subprocess.py", line 50, in <module>
    import signal
  File "/users/valls/workspace/silx.git/build/lib.linux-x86_64-3.7/silx/gui/utils/signal.py", line 32, in <module>
    from silx.gui.utils import concurrent
  File "/users/valls/workspace/silx.git/build/lib.linux-x86_64-3.7/silx/gui/utils/concurrent.py", line 35, in <module>
    from concurrent.futures import Future
  File "/users/valls/workspace/silx.git/build/lib.linux-x86_64-3.7/silx/gui/utils/concurrent.py", line 35, in <module>
    from concurrent.futures import Future
ModuleNotFoundError: No module named 'concurrent.futures'; 'concurrent' is not a package
Out[1]: <_isOpenGLAvailableResult: False, "Qt OpenGL widget error: retcode=1, error=b''">
```

Changed files:
silx/gui/utils/glutils.py

diff --git a/silx/gui/utils/glutils.py b/silx/gui/utils/glutils.py
index fca9a32ba..83cfd8900 100644
--- a/silx/gui/utils/glutils.py
+++ b/silx/gui/utils/glutils.py
@@ -27,6 +27,13 @@
 
 import os
 import sys
+
+if __name__ == "__main__":
+    # When run as a script, remove directory from sys.path
+    # This avoids other script in same directory to override Python modules
+    if os.path.abspath(sys.path[0]) == os.path.abspath(os.path.dirname(__file__)):
+        sys.path.pop(0)
+
 import subprocess
 from silx.gui import qt
Repository: silx-kit/silx
Issue: ModuleNotFoundError: No module named 'concurrent.futures'; 'concurrent' is not a package

Fun issue, no idea why it happens now on my machine.

This avoid to launch Flint with OpenGL, so it is quite annoying.

```
In [1]: import silx.gui.utils.glutils              
   ...: silx.gui.utils.glutils.isOpenGLAvailable()                                                                                                                                                                                                   
['/users/valls/Software/miniconda3/envs/silxenv/bin/python', '/users/valls/workspace/silx.git/build/lib.linux-x86_64-3.7/silx/gui/utils/glutils.py', '2', '1']
Traceback (most recent call last):
  File "/users/valls/workspace/silx.git/build/lib.linux-x86_64-3.7/silx/gui/utils/glutils.py", line 30, in <module>
    import subprocess
  File "/users/valls/Software/miniconda3/envs/silxenv/lib/python3.7/subprocess.py", line 50, in <module>
    import signal
  File "/users/valls/workspace/silx.git/build/lib.linux-x86_64-3.7/silx/gui/utils/signal.py", line 32, in <module>
    from silx.gui.utils import concurrent
  File "/users/valls/workspace/silx.git/build/lib.linux-x86_64-3.7/silx/gui/utils/concurrent.py", line 35, in <module>
    from concurrent.futures import Future
  File "/users/valls/workspace/silx.git/build/lib.linux-x86_64-3.7/silx/gui/utils/concurrent.py", line 35, in <module>
    from concurrent.futures import Future
ModuleNotFoundError: No module named 'concurrent.futures'; 'concurrent' is not a package
Out[1]: <_isOpenGLAvailableResult: False, "Qt OpenGL widget error: retcode=1, error=b''">
```

Changed files:
silx/gui/utils/glutils.py

diff --git a/silx/gui/utils/glutils.py b/silx/gui/utils/glutils.py
index fca9a32ba..aa885c9e0 100644
--- a/silx/gui/utils/glutils.py
+++ b/silx/gui/utils/glutils.py
@@ -70,7 +70,7 @@ def _runtimeOpenGLCheck(version):
 
     try:
         error = subprocess.check_output(
-            [sys.executable, __file__, major, minor],
+            [sys.executable, "-I", __file__, major, minor],
             env=env,
             timeout=2)
     except subprocess.TimeoutExpired:
Repository: silx-kit/silx
Issue: Mask image issue when drawing outside the image

Drawing a rectangle mask ouside an image on the left side of the image actually draws a rectangle mask on the image....

Changed files:
silx/gui/plot/MaskToolsWidget.py

diff --git a/silx/gui/plot/MaskToolsWidget.py b/silx/gui/plot/MaskToolsWidget.py
index c06366f10..a95e277fe 100644
--- a/silx/gui/plot/MaskToolsWidget.py
+++ b/silx/gui/plot/MaskToolsWidget.py
@@ -187,6 +187,8 @@ class ImageMask(BaseMask):
         :param bool mask: True to mask (default), False to unmask.
         """
         assert 0 < level < 256
+        if row + height <= 0 or col + width <= 0:
+            return  # Rectangle outside image, avoid negative indices
         selection = self._mask[max(0, row):row + height + 1,
                                max(0, col):col + width + 1]
         if mask:
Repository: silx-kit/silx
Issue: setStepType only available in Qt 5.12

Hi,

I got this exception with `silx view`, packaged for debian10 (Qt5 version 5.11.3):
```
  File "/usr/lib/python3/dist-packages/silx/gui/dialog/ColormapDialog.py", line 869, in __init__
    self._gammaSpinBox.setStepType(qt.QDoubleSpinBox.AdaptiveDecimalStepType)
```

This function was introduced in Qt 5.12.

This is a regression introduced recently by:
https://github.com/silx-kit/silx/pull/3054



Changed files:
silx/gui/dialog/ColormapDialog.py

diff --git a/silx/gui/dialog/ColormapDialog.py b/silx/gui/dialog/ColormapDialog.py
index 4cee10536..707e9e6b7 100644
--- a/silx/gui/dialog/ColormapDialog.py
+++ b/silx/gui/dialog/ColormapDialog.py
@@ -866,7 +866,7 @@ class ColormapDialog(qt.QDialog):
         self._gammaSpinBox = qt.QDoubleSpinBox(parent=self)
         self._gammaSpinBox.setEnabled(False)
         self._gammaSpinBox.setRange(0., 1000.)
-        self._gammaSpinBox.setStepType(qt.QDoubleSpinBox.AdaptiveDecimalStepType)
+        self._gammaSpinBox.setSingleStep(0.1)
         self._gammaSpinBox.valueChanged.connect(self._gammaUpdated)
         self._gammaSpinBox.setValue(2.)
Repository: silx-kit/silx
Issue: [image dialog] NoneType' object has no attribute 'index'

Occurred on `pyFAI-integrate` at the program termination. The dialog was closed a long time ago.

```
Traceback (most recent call last):
  File "/home/valls/.local/lib/python3.5/site-packages/silx/gui/dialog/AbstractDataFileDialog.py", line 1058, in __directoryLoaded
    index = self.__fileModel.index(path)
AttributeError: 'NoneType' object has no attribute 'index'
```

Changed files:
silx/gui/dialog/AbstractDataFileDialog.py

diff --git a/silx/gui/dialog/AbstractDataFileDialog.py b/silx/gui/dialog/AbstractDataFileDialog.py
index e79519d34..29e7bb563 100644
--- a/silx/gui/dialog/AbstractDataFileDialog.py
+++ b/silx/gui/dialog/AbstractDataFileDialog.py
@@ -1042,6 +1042,8 @@ class AbstractDataFileDialog(qt.QDialog):
                 return
         self.__directoryLoadedFilter = path
         self.__processing += 1
+        if self.__fileModel is None:
+            return
         index = self.__fileModel.setRootPath(path)
         if not index.isValid():
             # There is a problem with this path
@@ -1058,6 +1060,8 @@ class AbstractDataFileDialog(qt.QDialog):
                 # The first click on the sidebar sent 2 events
                 self.__processing -= 1
                 return
+        if self.__fileModel is None:
+            return
         index = self.__fileModel.index(path)
         self.__browser.setRootIndex(index, model=self.__fileModel)
         self.__updatePath()
Repository: silx-kit/silx
Issue: [RoiCurveWidget] fails to update from marker for the ROI of ID 0

Roi which has the ID 0 cannot be updated from the markers

Changed files:
silx/gui/plot/CurvesROIWidget.py

diff --git a/silx/gui/plot/CurvesROIWidget.py b/silx/gui/plot/CurvesROIWidget.py
index 6c219898d..81b0bfd81 100644
--- a/silx/gui/plot/CurvesROIWidget.py
+++ b/silx/gui/plot/CurvesROIWidget.py
@@ -945,7 +945,7 @@ class ROITable(TableWidget):
         if ddict['event'] == 'markerMoved':
             label = ddict['label']
             roiID = self._markersHandler.getRoiID(markerID=label)
-            if roiID:
+            if roiID is not None:
                 # avoid several emission of sigROISignal
                 old = self.blockSignals(True)
                 self._markersHandler.changePosition(markerID=label,
Repository: silx-kit/silx
Issue: [test] CI fails for TestSpecH5

Expected logs are not produced/catched propely:
```
======================================================================
ERROR: testVisit (silx.io.test.test_spech5.TestSpecH5)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\\projects\\silx\\venv_test\\lib\\site-packages\\silx\\test\\utils.py", line 219, in wrapper
    result = func(*args, **kwargs)
  File "C:\\projects\\silx\\venv_test\\lib\\site-packages\\silx\\test\\utils.py", line 175, in __exit__
    expected_count, logging.getLevelName(level), count))
RuntimeError: Expected 2 WARNING logging messages, got 0
======================================================================
ERROR: testVisitItems (silx.io.test.test_spech5.TestSpecH5)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\\projects\\silx\\venv_test\\lib\\site-packages\\silx\\test\\utils.py", line 219, in wrapper
    result = func(*args, **kwargs)
  File "C:\\projects\\silx\\venv_test\\lib\\site-packages\\silx\\test\\utils.py", line 175, in __exit__
    expected_count, logging.getLevelName(level), count))
RuntimeError: Expected 2 WARNING logging messages, got 0
======================================================================
```


Changed files:
silx/io/commonh5.py, silx/io/test/test_spech5.py

diff --git a/silx/io/commonh5.py b/silx/io/commonh5.py
index be38ef00c..5fc820354 100644
--- a/silx/io/commonh5.py
+++ b/silx/io/commonh5.py
@@ -28,11 +28,6 @@ files. They are used in :mod:`spech5` and :mod:`fabioh5`.
 .. note:: This module has a dependency on the `h5py <http://www.h5py.org/>`_
     library, which is not a mandatory dependency for `silx`.
 """
-
-__authors__ = ["V. Valls", "P. Knobel"]
-__license__ = "MIT"
-__date__ = "28/08/2017"
-
 import collections
 import h5py
 import numpy
@@ -42,7 +37,7 @@ from .utils import is_dataset
 
 __authors__ = ["V. Valls", "P. Knobel"]
 __license__ = "MIT"
-__date__ = "22/08/2017"
+__date__ = "28/08/2017"
 
 
 class _MappingProxyType(collections.MutableMapping):
diff --git a/silx/io/test/test_spech5.py b/silx/io/test/test_spech5.py
index 9e9c8e58b..1d04c6f0d 100644
--- a/silx/io/test/test_spech5.py
+++ b/silx/io/test/test_spech5.py
@@ -503,7 +503,6 @@ class TestSpecH5(unittest.TestCase):
                       self.sfh5["/25.1"].values())
 
     # visit and visititems ignore links
-    @utils.test_logging(spech5.logger1.name, warning=2)
     def testVisit(self):
         name_list = []
         self.sfh5.visit(name_list.append)
@@ -531,7 +530,6 @@ class TestSpecH5(unittest.TestCase):
         self.assertIn("positioners/Pslit HGap", name_list_no_slash)
         self.assertIn("positioners", name_list_no_slash)
 
-    @utils.test_logging(spech5.logger1.name, warning=2)
     def testVisitItems(self):
         dataset_name_list = []
Repository: silx-kit/silx
Issue: [spech5] Silx convert of MCAs may generate files with wrong number of channels

When converting a SPEC file with MCAs, the channels field and the data field do not have the same number of channels.

Changed files:
silx/io/test/test_spech5.py, silx/io/spech5.py

diff --git a/silx/io/spech5.py b/silx/io/spech5.py
index 6eb3e5685..a112fe048 100644
--- a/silx/io/spech5.py
+++ b/silx/io/spech5.py
@@ -198,7 +198,7 @@ from silx.third_party import six
 
 __authors__ = ["P. Knobel", "D. Naudet"]
 __license__ = "MIT"
-__date__ = "29/01/2018"
+__date__ = "01/03/2018"
 
 logger1 = logging.getLogger(__name__)
 
@@ -689,9 +689,12 @@ class InstrumentMcaGroup(commonh5.Group, SpecH5Group):
         commonh5.Group.__init__(self, name=name, parent=parent,
                                 attrs={"NX_class": to_h5py_utf8("NXdetector")})
 
-        self.add_node(McaDataDataset(parent=self,
+        mcaDataDataset = McaDataDataset(parent=self,
                                      analyser_index=analyser_index,
-                                     scan=scan))
+                                     scan=scan)
+        self.add_node(mcaDataDataset)
+        spectrum_length = mcaDataDataset.shape[-1]
+        mcaDataDataset = None
 
         if len(scan.mca.channels) == 1:
             # single @CALIB line applying to multiple devices
@@ -700,6 +703,21 @@ class InstrumentMcaGroup(commonh5.Group, SpecH5Group):
         else:
             calibration_dataset = scan.mca.calibration[analyser_index]
             channels_dataset = scan.mca.channels[analyser_index]
+
+        channels_length = len(channels_dataset) 
+        if (channels_length > 1) and (spectrum_length > 0):
+            logger1.info("Spectrum and channels length mismatch")
+            # this should always be the case
+            if channels_length > spectrum_length:
+                channels_dataset = channels_dataset[:spectrum_length]
+            elif channels_length < spectrum_length:
+                # only trust first channel and increment
+                channel0 = channels_dataset[0]
+                increment = channels_dataset[1] - channels_dataset[0]
+                channels_dataset = numpy.linspace(channel0,
+                                        channel0 + increment * spectrum_length,
+                                        spectrum_length, endpoint=False)
+
         self.add_node(SpecH5NodeDataset(name="calibration",
                                         data=calibration_dataset,
                                         parent=self))
diff --git a/silx/io/test/test_spech5.py b/silx/io/test/test_spech5.py
index 27de0e83a..b842243be 100644
--- a/silx/io/test/test_spech5.py
+++ b/silx/io/test/test_spech5.py
@@ -675,7 +675,7 @@ sftext_no_cols = r"""#F C:/DATA\\test.mca
 #D Thu Jul  7 08:40:19 2016
 #C no data cols, one mca analyser, single spectrum
 #@MCA %16C
-#@CHANN 151 29 29 1
+#@CHANN 151 0 150 1
 #@CALIB 0 2 0
 @A 789 784 788 814 847 862 880 904 925 955 987 1015 1031 1070 1111 1139 \\
 1203 1236 1290 1392 1492 1558 1688 1813 1977 2119 2346 2699 3121 3542 4102 4970 \\
Repository: silx-kit/silx
Issue: [silx view] hdf5plugin not installed message

Both, silx.io and fabio import h5py. Therefore when the application tries to import hdf5plugin, the later cannot be imported because h5py is already imported.

That is desired behavior when somebody is using the library, but not for the silx view application.

The try/except with the warning (or without) around the import of hdf5plugin should be moved before any of silx.io or fabio are imported.

Changed files:
silx/app/view.py

diff --git a/silx/app/view.py b/silx/app/view.py
index dfe6f7d35..556f28dea 100644
--- a/silx/app/view.py
+++ b/silx/app/view.py
@@ -1,6 +1,6 @@
 # coding: utf-8
 # /*##########################################################################
-# Copyright (C) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (C) 2016-2018 European Synchrotron Radiation Facility
 #
 # Permission is hereby granted, free of charge, to any person obtaining a copy
 # of this software and associated documentation files (the "Software"), to deal
@@ -25,7 +25,7 @@
 
 __authors__ = ["V. Valls"]
 __license__ = "MIT"
-__date__ = "05/01/2018"
+__date__ = "29/01/2018"
 
 import sys
 import os
@@ -37,12 +37,6 @@ _logger = logging.getLogger(__name__)
 """Module logger"""
 
 from silx.gui import qt
-import silx.io
-
-try:
-    import fabio
-except ImportError:
-    fabio = None
 
 
 class Viewer(qt.QMainWindow):
@@ -148,10 +142,14 @@ class Viewer(qt.QMainWindow):
         dialog.setWindowTitle("Open")
         dialog.setModal(True)
 
+        # NOTE: hdf5plugin have to be loaded before
+        import silx.io
         extensions = collections.OrderedDict()
         for description, ext in silx.io.supported_extensions().items():
             extensions[description] = " ".join(sorted(list(ext)))
 
+        # NOTE: hdf5plugin have to be loaded before
+        import fabio
         if fabio is not None:
             extensions["NeXus layout from EDF files"] = "*.edf"
             extensions["NeXus layout from TIFF image files"] = "*.tif *.tiff"
Repository: silx-kit/silx
Issue: [plot] Updating a curve with color defined for each point fails

To reproduce:
```
from silx import sx
w = sx.Plot1D()
w.show()
w.addCurve((1, 2), (1, 2), color=((1., 0., 0.), (0., 0., 1.)), symbol='o', linestyle='')
w.addCurve((1, 2), (1, 2), color=((1., 0., 0.), (0., 0., 1.)), symbol='o', linestyle='')
```

2nd `addCurve` fails with error:
```
silx/gui/plot/items/core.pyc in setColor(self, color, copy)
    567                 assert color.ndim == 2
    568 
--> 569         if self._color != color:
    570             self._color = color
    571             self._updated(ItemChangedType.COLOR)

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
```

Replacing `if self._color != color:` with `if not numpy.all(numpy.equal(self._color, color)):` solves the issue.



Changed files:
silx/gui/plot/test/testPlotWidget.py, silx/gui/plot/items/core.py

diff --git a/silx/gui/plot/items/core.py b/silx/gui/plot/items/core.py
index 0f4ffb971..34ac700d6 100644
--- a/silx/gui/plot/items/core.py
+++ b/silx/gui/plot/items/core.py
@@ -543,7 +543,7 @@ class ColorMixIn(object):
     def getColor(self):
         """Returns the RGBA color of the item
 
-        :rtype: 4-tuple of float in [0, 1]
+        :rtype: 4-tuple of float in [0, 1] or array of colors
         """
         return self._color
 
@@ -566,9 +566,8 @@ class ColorMixIn(object):
             else:  # Array of colors
                 assert color.ndim == 2
 
-        if self._color != color:
-            self._color = color
-            self._updated(ItemChangedType.COLOR)
+        self._color = color
+        self._updated(ItemChangedType.COLOR)
 
 
 class YAxisMixIn(object):
diff --git a/silx/gui/plot/test/testPlotWidget.py b/silx/gui/plot/test/testPlotWidget.py
index deeb19877..ccee428a6 100644
--- a/silx/gui/plot/test/testPlotWidget.py
+++ b/silx/gui/plot/test/testPlotWidget.py
@@ -371,6 +371,27 @@ class TestPlotCurve(PlotWidgetTestCase):
                            color=color, linestyle="-", symbol='o')
         self.plot.resetZoom()
 
+        # Test updating color array
+
+        # From array to array
+        newColors = numpy.ones((len(self.xData), 3), dtype=numpy.float32)
+        self.plot.addCurve(self.xData, self.yData,
+                           legend="curve 2",
+                           replace=False, resetzoom=False,
+                           color=newColors, symbol='o')
+
+        # Array to single color
+        self.plot.addCurve(self.xData, self.yData,
+                           legend="curve 2",
+                           replace=False, resetzoom=False,
+                           color='green', symbol='o')
+
+        # single color to array
+        self.plot.addCurve(self.xData, self.yData,
+                           legend="curve 2",
+                           replace=False, resetzoom=False,
+                           color=color, symbol='o')
+
 
 class TestPlotMarker(PlotWidgetTestCase):
     """Basic tests for add*Marker"""