summaryrefslogtreecommitdiff
path: root/silx/gui/plot/test
diff options
context:
space:
mode:
authorAlexandre Marie <alexandre.marie@synchrotron-soleil.fr>2020-07-21 14:45:14 +0200
committerAlexandre Marie <alexandre.marie@synchrotron-soleil.fr>2020-07-21 14:45:14 +0200
commit328032e2317e3ac4859196bbf12bdb71795302fe (patch)
tree8cd13462beab109e3cb53410c42335b6d1e00ee6 /silx/gui/plot/test
parent33ed2a64c92b0311ae35456c016eb284e426afc2 (diff)
New upstream version 0.13.0+dfsg
Diffstat (limited to 'silx/gui/plot/test')
-rw-r--r--silx/gui/plot/test/__init__.py8
-rw-r--r--silx/gui/plot/test/testColorBar.py19
-rw-r--r--silx/gui/plot/test/testCurvesROIWidget.py37
-rw-r--r--silx/gui/plot/test/testImageStack.py197
-rw-r--r--silx/gui/plot/test/testInteraction.py22
-rw-r--r--silx/gui/plot/test/testItem.py4
-rw-r--r--silx/gui/plot/test/testPixelIntensityHistoAction.py55
-rwxr-xr-xsilx/gui/plot/test/testPlotWidget.py145
-rw-r--r--silx/gui/plot/test/testPlotWidgetNoBackend.py50
-rw-r--r--silx/gui/plot/test/testPlotWindow.py59
-rw-r--r--silx/gui/plot/test/testProfile.py287
-rw-r--r--silx/gui/plot/test/testStats.py35
12 files changed, 504 insertions, 414 deletions
diff --git a/silx/gui/plot/test/__init__.py b/silx/gui/plot/test/__init__.py
index 89c10c6..0477e2a 100644
--- a/silx/gui/plot/test/__init__.py
+++ b/silx/gui/plot/test/__init__.py
@@ -42,8 +42,8 @@ from . import testPlotInteraction
from . import testPlotWidgetNoBackend
from . import testPlotWidget
from . import testPlotWindow
-from . import testProfile
from . import testStackView
+from . import testImageStack
from . import testItem
from . import testUtilsAxis
from . import testLimitConstraints
@@ -75,8 +75,8 @@ def suite():
testPlotWidgetNoBackend.suite(),
testPlotWidget.suite(),
testPlotWindow.suite(),
- testProfile.suite(),
testStackView.suite(),
+ testImageStack.suite(),
testItem.suite(),
testUtilsAxis.suite(),
testLimitConstraints.suite(),
@@ -85,6 +85,6 @@ def suite():
testSaveAction.suite(),
testScatterView.suite(),
testPixelIntensityHistoAction.suite(),
- testCompareImages.suite()
- ])
+ testCompareImages.suite(),
+ ])
return test_suite
diff --git a/silx/gui/plot/test/testColorBar.py b/silx/gui/plot/test/testColorBar.py
index 9a02e04..a6f141c 100644
--- a/silx/gui/plot/test/testColorBar.py
+++ b/silx/gui/plot/test/testColorBar.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-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
@@ -33,6 +33,7 @@ from silx.gui.utils.testutils import TestCaseQt
from silx.gui.plot.ColorBar import _ColorScale
from silx.gui.plot.ColorBar import ColorBarWidget
from silx.gui.colors import Colormap
+from silx.gui import colors
from silx.gui.plot import Plot2D
from silx.gui import qt
import numpy
@@ -94,10 +95,10 @@ class TestColorScale(TestCaseQt):
self.colorScaleWidget.setColormap(self.colorMapLog1)
val = self.colorScaleWidget.getValueFromRelativePosition(1.0)
- self.assertTrue(val == 100.0)
+ self.assertAlmostEqual(val, 100.0)
val = self.colorScaleWidget.getValueFromRelativePosition(0.5)
- self.assertTrue(val == 10.0)
+ self.assertAlmostEqual(val, 10.0)
val = self.colorScaleWidget.getValueFromRelativePosition(0.0)
self.assertTrue(val == 1.0)
@@ -149,7 +150,7 @@ class TestNoAutoscale(TestCaseQt):
# test ColorScale
val = self.colorScale.getValueFromRelativePosition(1.0)
- self.assertTrue(val == 100.0)
+ self.assertAlmostEqual(val, 100.0)
val = self.colorScale.getValueFromRelativePosition(0.0)
self.assertTrue(val == 1.0)
@@ -315,8 +316,9 @@ class TestColorBarUpdate(TestCaseQt):
self.colorBar.getColorScaleBar().getTickBar()._vmin == 0)
self.assertTrue(
self.colorBar.getColorScaleBar().getTickBar()._vmax == 1)
- self.assertTrue(
- self.colorBar.getColorScaleBar().getTickBar()._norm == "linear")
+ self.assertIsInstance(
+ self.colorBar.getColorScaleBar().getTickBar()._normalizer,
+ colors._LinearNormalization)
# update colormap
colormap.setVMin(0.5)
@@ -330,8 +332,9 @@ class TestColorBarUpdate(TestCaseQt):
self.colorBar.getColorScaleBar().getTickBar()._vmax == 0.8)
colormap.setNormalization('log')
- self.assertTrue(
- self.colorBar.getColorScaleBar().getTickBar()._norm == 'log')
+ self.assertIsInstance(
+ self.colorBar.getColorScaleBar().getTickBar()._normalizer,
+ colors._LogarithmicNormalization)
# TODO : should also check that if the colormap is changing then values (especially in log scale)
# should be coherent if in autoscale
diff --git a/silx/gui/plot/test/testCurvesROIWidget.py b/silx/gui/plot/test/testCurvesROIWidget.py
index 5886456..77c53a8 100644
--- a/silx/gui/plot/test/testCurvesROIWidget.py
+++ b/silx/gui/plot/test/testCurvesROIWidget.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-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
@@ -36,6 +36,7 @@ from collections import OrderedDict
import numpy
from silx.gui import qt
+from silx.gui.plot import items
from silx.gui.plot import Plot1D
from silx.test.utils import temp_dir
from silx.gui.utils.testutils import TestCaseQt, SignalListener
@@ -110,21 +111,20 @@ class TestCurvesROIWidget(TestCaseQt):
# Save ROIs
self.widget.roiWidget.save(self.tmpFile)
self.assertTrue(os.path.isfile(self.tmpFile))
- self.assertTrue(len(self.widget.getRois()) is 2)
+ self.assertEqual(len(self.widget.getRois()), 2)
# Reset ROIs
self.mouseClick(self.widget.roiWidget.resetButton,
qt.Qt.LeftButton)
self.qWait(200)
rois = self.widget.getRois()
- self.assertTrue(len(rois) is 1)
- print(rois)
+ self.assertEqual(len(rois), 1)
roiID = list(rois.keys())[0]
- self.assertTrue(rois[roiID].getName() == 'ICR')
+ self.assertEqual(rois[roiID].getName(), 'ICR')
# Load ROIs
self.widget.roiWidget.load(self.tmpFile)
- self.assertTrue(len(self.widget.getRois()) is 2)
+ self.assertEqual(len(self.widget.getRois()), 2)
del self.tmpFile
@@ -223,16 +223,16 @@ class TestCurvesROIWidget(TestCaseQt):
roiWidget = self.plot.getCurvesRoiDockWidget().roiWidget
self.plot.getCurvesRoiDockWidget().setRois(roisDefs)
- self.assertTrue(len(roiWidget.getRois()) is len(roisDefs))
+ self.assertEqual(len(roiWidget.getRois()), len(roisDefs))
self.plot.getCurvesRoiDockWidget().setVisible(True)
- self.assertTrue(len(roiWidget.getRois()) is len(roisDefs))
+ self.assertEqual(len(roiWidget.getRois()), len(roisDefs))
def testDictCompatibility(self):
"""Test that ROI api is valid with dict and not information is lost"""
roiDict = {'from': 20, 'to': 200, 'type': 'energy', 'comment': 'no',
'name': 'myROI', 'calibration': [1, 2, 3]}
roi = CurvesROIWidget.ROI._fromDict(roiDict)
- self.assertTrue(roi.toDict() == roiDict)
+ self.assertEqual(roi.toDict(), roiDict)
def testShowAllROI(self):
"""Test the show allROI action"""
@@ -254,29 +254,33 @@ class TestCurvesROIWidget(TestCaseQt):
self.widget.roiWidget.showAllMarkers(True)
roiWidget = self.plot.getCurvesRoiDockWidget().roiWidget
roiWidget.setRois(roisDefsDict)
- self.assertTrue(len(self.plot._getAllMarkers()) is 2*3)
+ markers = [item for item in self.plot.getItems()
+ if isinstance(item, items.MarkerBase)]
+ self.assertEqual(len(markers), 2*3)
markersHandler = self.widget.roiWidget.roiTable._markersHandler
roiWidget.showAllMarkers(True)
ICRROI = markersHandler.getVisibleRois()
- self.assertTrue(len(ICRROI) is 2)
+ self.assertEqual(len(ICRROI), 2)
roiWidget.showAllMarkers(False)
ICRROI = markersHandler.getVisibleRois()
- self.assertTrue(len(ICRROI) is 1)
+ self.assertEqual(len(ICRROI), 1)
roiWidget.setRois(roisDefsObj)
self.qapp.processEvents()
- self.assertTrue(len(self.plot._getAllMarkers()) is 2*3)
+ markers = [item for item in self.plot.getItems()
+ if isinstance(item, items.MarkerBase)]
+ self.assertEqual(len(markers), 2*3)
markersHandler = self.widget.roiWidget.roiTable._markersHandler
roiWidget.showAllMarkers(True)
ICRROI = markersHandler.getVisibleRois()
- self.assertTrue(len(ICRROI) is 2)
+ self.assertEqual(len(ICRROI), 2)
roiWidget.showAllMarkers(False)
ICRROI = markersHandler.getVisibleRois()
- self.assertTrue(len(ICRROI) is 1)
+ self.assertEqual(len(ICRROI), 1)
def testRoiEdition(self):
"""Make sure if the ROI object is edited the ROITable will be updated
@@ -331,7 +335,7 @@ class TestCurvesROIWidget(TestCaseQt):
self.widget.show()
self.qapp.processEvents()
self.assertEqual(signalListener.callCount(), 0)
- self.assertTrue(self.widget.roiWidget.roiTable.activeRoi is roi)
+ self.assertIs(self.widget.roiWidget.roiTable.activeRoi, roi)
roi.setFrom(0.0)
self.qapp.processEvents()
self.assertEqual(signalListener.callCount(), 0)
@@ -367,7 +371,6 @@ class TestRoiWidgetSignals(TestCaseQt):
def testSigROISignalAddRmRois(self):
"""Test SigROISignal when adding and removing ROIS"""
- print(self.listener.callCount())
self.assertEqual(self.listener.callCount(), 1)
self.listener.clear()
diff --git a/silx/gui/plot/test/testImageStack.py b/silx/gui/plot/test/testImageStack.py
new file mode 100644
index 0000000..9c21469
--- /dev/null
+++ b/silx/gui/plot/test/testImageStack.py
@@ -0,0 +1,197 @@
+# coding: utf-8
+# /*##########################################################################
+#
+# Copyright (c) 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
+# 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.
+#
+# ###########################################################################*/
+"""Basic tests for ImageStack"""
+
+__authors__ = ["H. Payno"]
+__license__ = "MIT"
+__date__ = "15/01/2020"
+
+
+import unittest
+import tempfile
+import numpy
+import h5py
+
+from silx.gui import qt
+from silx.gui.utils.testutils import TestCaseQt
+from silx.io.url import DataUrl
+from silx.gui.plot.ImageStack import ImageStack
+from silx.gui.utils.testutils import SignalListener
+from collections import OrderedDict
+import os
+import time
+import shutil
+
+
+class TestImageStack(TestCaseQt):
+ """Simple test of the Image stack"""
+
+ def setUp(self):
+ TestCaseQt.setUp(self)
+ self.urls = OrderedDict()
+ self._raw_data = {}
+ self._folder = tempfile.mkdtemp()
+ self._n_urls = 10
+ file_name = os.path.join(self._folder, 'test_inage_stack_file.h5')
+ with h5py.File(file_name, 'w') as h5f:
+ for i in range(self._n_urls):
+ width = numpy.random.randint(10, 40)
+ height = numpy.random.randint(10, 40)
+ raw_data = numpy.random.random((width, height))
+ self._raw_data[i] = raw_data
+ h5f[str(i)] = raw_data
+ self.urls[i] = DataUrl(file_path=file_name,
+ data_path=str(i),
+ scheme='silx')
+ self.widget = ImageStack()
+
+ self.urlLoadedListener = SignalListener()
+ self.widget.sigLoaded.connect(self.urlLoadedListener)
+
+ self.currentUrlChangedListener = SignalListener()
+ self.widget.sigCurrentUrlChanged.connect(self.currentUrlChangedListener)
+
+ def tearDown(self):
+ shutil.rmtree(self._folder)
+ self.widget.setAttribute(qt.Qt.WA_DeleteOnClose, True)
+ self.widget.close()
+ TestCaseQt.setUp(self)
+
+ def testControls(self):
+ """Test that selection using the url table and the slider are working
+ """
+ self.widget.show()
+ self.assertEqual(self.widget.getCurrentUrl(), None)
+ self.assertEqual(self.widget.getCurrentUrlIndex(), None)
+ self.widget.setUrls(list(self.urls.values()))
+
+ # wait for image to be loaded
+ self._waitUntilUrlLoaded()
+
+ self.assertEqual(self.widget.getCurrentUrl(), self.urls[0])
+
+ # make sure all image are loaded
+ self.assertEqual(self.urlLoadedListener.callCount(), self._n_urls)
+ numpy.testing.assert_array_equal(
+ self.widget.getPlotWidget().getActiveImage(just_legend=False).getData(),
+ self._raw_data[0])
+ self.assertEqual(self.widget._slider.value(), 0)
+
+ self.widget._urlsTable.setUrl(self.urls[4])
+ numpy.testing.assert_array_equal(
+ self.widget.getPlotWidget().getActiveImage(just_legend=False).getData(),
+ self._raw_data[4])
+ self.assertEqual(self.widget._slider.value(), 4)
+ self.assertEqual(self.widget.getCurrentUrl(), self.urls[4])
+ self.assertEqual(self.widget.getCurrentUrlIndex(), 4)
+
+ self.widget._slider.setUrlIndex(6)
+ numpy.testing.assert_array_equal(
+ self.widget.getPlotWidget().getActiveImage(just_legend=False).getData(),
+ self._raw_data[6])
+ self.assertEqual(self.widget._urlsTable.currentItem().text(),
+ self.urls[6].path())
+
+ def testCurrentUrlSignals(self):
+ """Test emission of 'currentUrlChangedListener'"""
+ # check initialization
+ self.assertEqual(self.currentUrlChangedListener.callCount(), 0)
+ self.widget.setUrls(list(self.urls.values()))
+ self.qapp.processEvents()
+ time.sleep(0.5)
+ self.qapp.processEvents()
+ # once loaded the two signals should have been sended
+ self.assertEqual(self.currentUrlChangedListener.callCount(), 1)
+ # if the slider is stuck to the same position no signal should be
+ # emitted
+ self.qapp.processEvents()
+ time.sleep(0.5)
+ self.qapp.processEvents()
+ self.assertEqual(self.widget._slider.value(), 0)
+ self.assertEqual(self.currentUrlChangedListener.callCount(), 1)
+ # if slider position is changed, one of each signal should have been
+ # emitted
+ self.widget._urlsTable.setUrl(self.urls[4])
+ self.qapp.processEvents()
+ time.sleep(1.5)
+ self.qapp.processEvents()
+ self.assertEqual(self.currentUrlChangedListener.callCount(), 2)
+
+ def testUtils(self):
+ """Test that some utils functions are working"""
+ self.widget.show()
+ self.widget.setUrls(list(self.urls.values()))
+ self.assertEqual(len(self.widget.getUrls()), len(self.urls))
+
+ # wait for image to be loaded
+ self._waitUntilUrlLoaded()
+
+ urls_values = list(self.urls.values())
+ self.assertEqual(urls_values[0], self.urls[0])
+ self.assertEqual(urls_values[7], self.urls[7])
+
+ self.assertEqual(self.widget._getNextUrl(urls_values[2]).path(),
+ urls_values[3].path())
+ self.assertEqual(self.widget._getPreviousUrl(urls_values[0]), None)
+ self.assertEqual(self.widget._getPreviousUrl(urls_values[6]).path(),
+ urls_values[5].path())
+
+ self.assertEqual(self.widget._getNNextUrls(2, urls_values[0]),
+ urls_values[1:3])
+ self.assertEqual(self.widget._getNNextUrls(5, urls_values[7]),
+ urls_values[8:])
+ self.assertEqual(self.widget._getNPreviousUrls(3, urls_values[2]),
+ urls_values[:2])
+ self.assertEqual(self.widget._getNPreviousUrls(5, urls_values[8]),
+ urls_values[3:8])
+
+ def _waitUntilUrlLoaded(self, timeout=2.0):
+ """Wait until all image urls are loaded"""
+ loop_duration = 0.2
+ remaining_duration = timeout
+ while(len(self.widget._loadingThreads) > 0 and remaining_duration > 0):
+ remaining_duration -= loop_duration
+ time.sleep(loop_duration)
+ self.qapp.processEvents()
+
+ if remaining_duration <= 0.0:
+ remaining_urls = []
+ for thread_ in self.widget._loadingThreads:
+ remaining_urls.append(thread_.url.path())
+ mess = 'All images are not loaded after the time out. ' \
+ 'Remaining urls are: ' + str(remaining_urls)
+ raise TimeoutError(mess)
+ return True
+
+
+def suite():
+ test_suite = unittest.TestSuite()
+ test_suite.addTest(
+ unittest.defaultTestLoader.loadTestsFromTestCase(TestImageStack))
+ return test_suite
+
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='suite')
diff --git a/silx/gui/plot/test/testInteraction.py b/silx/gui/plot/test/testInteraction.py
index 074a7cd..a47337e 100644
--- a/silx/gui/plot/test/testInteraction.py
+++ b/silx/gui/plot/test/testInteraction.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016 European Synchrotron Radiation Facility
+# Copyright (c) 2016-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
@@ -43,14 +43,14 @@ class TestInteraction(unittest.TestCase):
def click(self, x, y, btn):
events.append(('click', x, y, btn))
- def beginDrag(self, x, y):
- events.append(('beginDrag', x, y))
+ def beginDrag(self, x, y, btn):
+ events.append(('beginDrag', x, y, btn))
- def drag(self, x, y):
- events.append(('drag', x, y))
+ def drag(self, x, y, btn):
+ events.append(('drag', x, y, btn))
- def endDrag(self, x, y):
- events.append(('endDrag', x, y))
+ def endDrag(self, start, end, btn):
+ events.append(('endDrag', start, end, btn))
clickOrDrag = TestClickOrDrag()
@@ -68,14 +68,14 @@ class TestInteraction(unittest.TestCase):
self.assertEqual(len(events), 0)
clickOrDrag.handleEvent('move', 15, 10)
self.assertEqual(len(events), 2) # Received beginDrag and drag
- self.assertEqual(events[0], ('beginDrag', 10, 10))
- self.assertEqual(events[1], ('drag', 15, 10))
+ self.assertEqual(events[0], ('beginDrag', 10, 10, Interaction.LEFT_BTN))
+ self.assertEqual(events[1], ('drag', 15, 10, Interaction.LEFT_BTN))
clickOrDrag.handleEvent('move', 20, 10)
self.assertEqual(len(events), 3)
- self.assertEqual(events[-1], ('drag', 20, 10))
+ self.assertEqual(events[-1], ('drag', 20, 10, Interaction.LEFT_BTN))
clickOrDrag.handleEvent('release', 20, 10, Interaction.LEFT_BTN)
self.assertEqual(len(events), 4)
- self.assertEqual(events[-1], ('endDrag', (10, 10), (20, 10)))
+ self.assertEqual(events[-1], ('endDrag', (10, 10), (20, 10), Interaction.LEFT_BTN))
def suite():
diff --git a/silx/gui/plot/test/testItem.py b/silx/gui/plot/test/testItem.py
index c864545..ad739a2 100644
--- a/silx/gui/plot/test/testItem.py
+++ b/silx/gui/plot/test/testItem.py
@@ -131,6 +131,7 @@ class TestSigItemChangedSignal(PlotWidgetTestCase):
ItemChangedType.COLORMAP,
ItemChangedType.POSITION,
ItemChangedType.SCALE,
+ ItemChangedType.COLORMAP,
ItemChangedType.DATA])
def testImageRgbaChanged(self):
@@ -203,13 +204,14 @@ class TestSigItemChangedSignal(PlotWidgetTestCase):
self.assertEqual(listener.arguments(),
[(ItemChangedType.COLORMAP,),
+ (ItemChangedType.COLORMAP,),
(ItemChangedType.DATA,),
(ItemChangedType.VISUALIZATION_MODE,)])
def testShapeChanged(self):
"""Test sigItemChanged for shape"""
data = numpy.array((1., 10.))
- self.plot.addItem(data, data, legend='test', shape='rectangle')
+ self.plot.addShape(data, data, legend='test', shape='rectangle')
shape = self.plot._getItem(kind='item', legend='test')
listener = SignalListener()
diff --git a/silx/gui/plot/test/testPixelIntensityHistoAction.py b/silx/gui/plot/test/testPixelIntensityHistoAction.py
index 20d1ea2..882f496 100644
--- a/silx/gui/plot/test/testPixelIntensityHistoAction.py
+++ b/silx/gui/plot/test/testPixelIntensityHistoAction.py
@@ -43,7 +43,7 @@ class TestPixelIntensitiesHisto(TestCaseQt, ParametricTestCase):
def setUp(self):
super(TestPixelIntensitiesHisto, self).setUp()
- self.image = numpy.random.rand(100, 100)
+ self.image = numpy.random.rand(10, 10)
self.plotImage = Plot2D()
self.plotImage.getIntensityHistogramAction().setVisible(True)
@@ -91,6 +91,59 @@ class TestPixelIntensitiesHisto(TestCaseQt, ParametricTestCase):
self.plotImage.addImage(self.image.astype(typeToTest),
origin=(0, 0), legend='sino')
+ def testScatter(self):
+ """Test that an histogram from a scatter is displayed"""
+ xx = numpy.arange(10)
+ yy = numpy.arange(10)
+ value = numpy.sin(xx)
+ self.plotImage.addScatter(xx, yy, value)
+ self.plotImage.show()
+
+ histoAction = self.plotImage.getIntensityHistogramAction()
+
+ # test the pixel intensity diagram is showing
+ button = getQToolButtonFromAction(histoAction)
+ self.assertIsNot(button, None)
+ self.mouseMove(button)
+ self.mouseClick(button, qt.Qt.LeftButton)
+ self.qapp.processEvents()
+
+ plot = histoAction.getHistogramPlotWidget()
+ self.assertTrue(plot.isVisible())
+ items = plot.getItems()
+ self.assertEqual(len(items), 1)
+
+ def testChangeItem(self):
+ """Test that histogram changes it the item changes"""
+ xx = numpy.arange(10)
+ yy = numpy.arange(10)
+ value = numpy.sin(xx)
+ self.plotImage.addScatter(xx, yy, value)
+ self.plotImage.show()
+
+ histoAction = self.plotImage.getIntensityHistogramAction()
+
+ # test the pixel intensity diagram is showing
+ button = getQToolButtonFromAction(histoAction)
+ self.assertIsNot(button, None)
+ self.mouseMove(button)
+ self.mouseClick(button, qt.Qt.LeftButton)
+ self.qapp.processEvents()
+
+ # Reach histogram from the first item
+ plot = histoAction.getHistogramPlotWidget()
+ self.assertTrue(plot.isVisible())
+ items = plot.getItems()
+ data1 = items[0].getValueData(copy=False)
+
+ # Set another item to the plot
+ self.plotImage.addImage(self.image, origin=(0, 0), legend='sino')
+ self.qapp.processEvents()
+ data2 = items[0].getValueData(copy=False)
+
+ # Histogram is not the same
+ self.assertFalse(numpy.array_equal(data1, data2))
+
def suite():
test_suite = unittest.TestSuite()
diff --git a/silx/gui/plot/test/testPlotWidget.py b/silx/gui/plot/test/testPlotWidget.py
index 9724ec6..4ef6a72 100755
--- a/silx/gui/plot/test/testPlotWidget.py
+++ b/silx/gui/plot/test/testPlotWidget.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2019 European Synchrotron Radiation Facility
+# Copyright (c) 2016-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
@@ -43,7 +43,7 @@ from silx.test.utils import test_options
from silx.gui import qt
from silx.gui.plot import PlotWidget
from silx.gui.plot.items.curve import CurveStyle
-from silx.gui.plot.items.shape import BoundingRect
+from silx.gui.plot.items import BoundingRect, XAxisExtent, YAxisExtent
from silx.gui.colors import Colormap
from .utils import PlotWidgetTestCase
@@ -186,7 +186,7 @@ class TestPlotWidget(PlotWidgetTestCase, ParametricTestCase):
self.plot.addMarker(*marker_pos)
marker_x = 6
self.plot.addXMarker(marker_x)
- self.plot.addItem((0, 5), (2, 10), shape='rectangle')
+ self.plot.addShape((0, 5), (2, 10), shape='rectangle')
items = self.plot.getItems()
self.assertEqual(len(items), 6)
@@ -273,11 +273,20 @@ class TestPlotImage(PlotWidgetTestCase, ParametricTestCase):
rgb = numpy.array(
(((0, 0, 0), (128, 0, 0), (255, 0, 0)),
- ((0, 128, 0), (0, 128, 128), (0, 128, 256))),
+ ((0, 128, 0), (0, 128, 128), (0, 128, 255))),
dtype=numpy.uint8)
- self.plot.addImage(rgb, legend="rgb",
- origin=(0, 0), scale=(10, 10),
+ self.plot.addImage(rgb, legend="rgb_uint8",
+ origin=(0, 0), scale=(1, 1),
+ resetzoom=False)
+
+ rgb = numpy.array(
+ (((0, 0, 0), (32768, 0, 0), (65535, 0, 0)),
+ ((0, 32768, 0), (0, 32768, 32768), (0, 32768, 65535))),
+ dtype=numpy.uint16)
+
+ self.plot.addImage(rgb, legend="rgb_uint16",
+ origin=(3, 2), scale=(2, 2),
resetzoom=False)
rgba = numpy.array(
@@ -285,8 +294,8 @@ class TestPlotImage(PlotWidgetTestCase, ParametricTestCase):
((0, .5, 0, 1), (0, .5, .5, 1), (0, 1, 1, .5))),
dtype=numpy.float32)
- self.plot.addImage(rgba, legend="rgba",
- origin=(5, 5), scale=(10, 10),
+ self.plot.addImage(rgba, legend="rgba_float32",
+ origin=(9, 6), scale=(1, 1),
resetzoom=False)
self.plot.resetZoom()
@@ -561,9 +570,13 @@ class TestPlotScatter(PlotWidgetTestCase, ParametricTestCase):
for visualization in ('solid',
'points',
'regular_grid',
+ 'irregular_grid',
+ 'binned_statistic',
scatter.Visualization.SOLID,
scatter.Visualization.POINTS,
- scatter.Visualization.REGULAR_GRID):
+ scatter.Visualization.REGULAR_GRID,
+ scatter.Visualization.IRREGULAR_GRID,
+ scatter.Visualization.BINNED_STATISTIC):
with self.subTest(visualization=visualization):
scatter.setVisualization(visualization)
self.qapp.processEvents()
@@ -622,13 +635,37 @@ class TestPlotScatter(PlotWidgetTestCase, ParametricTestCase):
for index, position in enumerate(zip(x, y)):
xpixel, ypixel = self.plot.dataToPixel(*position)
result = scatter.pick(xpixel, ypixel)
- if (visualization is scatter.Visualization.IRREGULAR_GRID and
- (shape[0] < 2 or shape[1] < 2)):
- self.assertIsNone(result)
- else:
- self.assertIsNotNone(result)
- self.assertIs(result.getItem(), scatter)
- self.assertEqual(result.getIndices()[0], (index,))
+ self.assertIsNotNone(result)
+ self.assertIs(result.getItem(), scatter)
+ self.assertEqual(result.getIndices(), (index,))
+
+ def testBinnedStatisticVisualization(self):
+ """Test binned display"""
+ self.plot.addScatter((), (), ())
+ scatter = self.plot.getItems()[0]
+ scatter.setVisualization(scatter.Visualization.BINNED_STATISTIC)
+ self.assertIs(scatter.getVisualization(),
+ scatter.Visualization.BINNED_STATISTIC)
+ self.assertEqual(
+ scatter.getVisualizationParameter(
+ scatter.VisualizationParameter.BINNED_STATISTIC_FUNCTION),
+ 'mean')
+
+ self.qapp.processEvents()
+
+ scatter.setData(*numpy.random.random(3000).reshape(3, -1))
+
+ for reduction in ('count', 'sum', 'mean'):
+ with self.subTest(reduction=reduction):
+ scatter.setVisualizationParameter(
+ scatter.VisualizationParameter.BINNED_STATISTIC_FUNCTION,
+ reduction)
+ self.assertEqual(
+ scatter.getVisualizationParameter(
+ scatter.VisualizationParameter.BINNED_STATISTIC_FUNCTION),
+ reduction)
+
+ self.qapp.processEvents()
class TestPlotMarker(PlotWidgetTestCase):
@@ -799,36 +836,36 @@ class TestPlotItem(PlotWidgetTestCase):
self.plot.setGraphTitle('Item Fill')
for legend, xList, yList, color in self.polygons:
- self.plot.addItem(xList, yList, legend=legend,
- replace=False,
- shape="polygon", fill=True, color=color)
+ self.plot.addShape(xList, yList, legend=legend,
+ replace=False,
+ shape="polygon", fill=True, color=color)
self.plot.resetZoom()
def testPlotItemPolygonNoFill(self):
self.plot.setGraphTitle('Item No Fill')
for legend, xList, yList, color in self.polygons:
- self.plot.addItem(xList, yList, legend=legend,
- replace=False,
- shape="polygon", fill=False, color=color)
+ self.plot.addShape(xList, yList, legend=legend,
+ replace=False,
+ shape="polygon", fill=False, color=color)
self.plot.resetZoom()
def testPlotItemRectangleFill(self):
self.plot.setGraphTitle('Rectangle Fill')
for legend, xList, yList, color in self.rectangles:
- self.plot.addItem(xList, yList, legend=legend,
- replace=False,
- shape="rectangle", fill=True, color=color)
+ self.plot.addShape(xList, yList, legend=legend,
+ replace=False,
+ shape="rectangle", fill=True, color=color)
self.plot.resetZoom()
def testPlotItemRectangleNoFill(self):
self.plot.setGraphTitle('Rectangle No Fill')
for legend, xList, yList, color in self.rectangles:
- self.plot.addItem(xList, yList, legend=legend,
- replace=False,
- shape="rectangle", fill=False, color=color)
+ self.plot.addShape(xList, yList, legend=legend,
+ replace=False,
+ shape="rectangle", fill=False, color=color)
self.plot.resetZoom()
@@ -1350,7 +1387,7 @@ class TestPlotAxes(TestCaseQt, ParametricTestCase):
def testBoundingRectItem(self):
item = BoundingRect()
item.setBounds((-1000, 1000, -2000, 2000))
- self.plot._add(item)
+ self.plot.addItem(item)
self.plot.resetZoom()
limits = numpy.array(self.plot.getXAxis().getLimits())
numpy.testing.assert_almost_equal(limits, numpy.array([-1000, 1000]))
@@ -1361,7 +1398,7 @@ class TestPlotAxes(TestCaseQt, ParametricTestCase):
item = BoundingRect()
item.setYAxis("right")
item.setBounds((-1000, 1000, -2000, 2000))
- self.plot._add(item)
+ self.plot.addItem(item)
self.plot.resetZoom()
limits = numpy.array(self.plot.getXAxis().getLimits())
numpy.testing.assert_almost_equal(limits, numpy.array([-1000, 1000]))
@@ -1377,7 +1414,7 @@ class TestPlotAxes(TestCaseQt, ParametricTestCase):
def testBoundingRectWithLog(self):
item = BoundingRect()
- self.plot._add(item)
+ self.plot.addItem(item)
item.setBounds((-1000, 1000, -2000, 2000))
self.plot.getXAxis()._setLogarithmic(True)
@@ -1394,6 +1431,28 @@ class TestPlotAxes(TestCaseQt, ParametricTestCase):
self.plot.getYAxis()._setLogarithmic(False)
self.assertIsNone(item.getBounds())
+ def testAxisExtent(self):
+ """Test XAxisExtent and yAxisExtent"""
+ for cls, axis in ((XAxisExtent, self.plot.getXAxis()),
+ (YAxisExtent, self.plot.getYAxis())):
+ for range_, logRange in (((2, 3), (2, 3)),
+ ((-2, -1), (1, 100)),
+ ((-1, 3), (3. * 0.9, 3. * 1.1))):
+ extent = cls()
+ extent.setRange(*range_)
+ self.plot.addItem(extent)
+
+ for isLog, plotRange in ((False, range_), (True, logRange)):
+ with self.subTest(
+ cls=cls.__name__, range=range_, isLog=isLog):
+ axis._setLogarithmic(isLog)
+ self.plot.resetZoom()
+ self.qapp.processEvents()
+ self.assertEqual(axis.getLimits(), plotRange)
+
+ axis._setLogarithmic(False)
+ self.plot.clear()
+
class TestPlotCurveLog(PlotWidgetTestCase, ParametricTestCase):
"""Basic tests for addCurve with log scale axes"""
@@ -1736,36 +1795,36 @@ class TestPlotItemLog(PlotWidgetTestCase):
self.plot.setGraphTitle('Item Fill Log')
for legend, xList, yList, color in self.polygons:
- self.plot.addItem(xList, yList, legend=legend,
- replace=False,
- shape="polygon", fill=True, color=color)
+ self.plot.addShape(xList, yList, legend=legend,
+ replace=False,
+ shape="polygon", fill=True, color=color)
self.plot.resetZoom()
def testPlotItemPolygonLogNoFill(self):
self.plot.setGraphTitle('Item No Fill Log')
for legend, xList, yList, color in self.polygons:
- self.plot.addItem(xList, yList, legend=legend,
- replace=False,
- shape="polygon", fill=False, color=color)
+ self.plot.addShape(xList, yList, legend=legend,
+ replace=False,
+ shape="polygon", fill=False, color=color)
self.plot.resetZoom()
def testPlotItemRectangleLogFill(self):
self.plot.setGraphTitle('Rectangle Fill Log')
for legend, xList, yList, color in self.rectangles:
- self.plot.addItem(xList, yList, legend=legend,
- replace=False,
- shape="rectangle", fill=True, color=color)
+ self.plot.addShape(xList, yList, legend=legend,
+ replace=False,
+ shape="rectangle", fill=True, color=color)
self.plot.resetZoom()
def testPlotItemRectangleLogNoFill(self):
self.plot.setGraphTitle('Rectangle No Fill Log')
for legend, xList, yList, color in self.rectangles:
- self.plot.addItem(xList, yList, legend=legend,
- replace=False,
- shape="rectangle", fill=False, color=color)
+ self.plot.addShape(xList, yList, legend=legend,
+ replace=False,
+ shape="rectangle", fill=False, color=color)
self.plot.resetZoom()
diff --git a/silx/gui/plot/test/testPlotWidgetNoBackend.py b/silx/gui/plot/test/testPlotWidgetNoBackend.py
index cd7cbb3..edd3cd7 100644
--- a/silx/gui/plot/test/testPlotWidgetNoBackend.py
+++ b/silx/gui/plot/test/testPlotWidgetNoBackend.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
+# Copyright (c) 2016-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
@@ -62,8 +62,9 @@ class TestPlot(unittest.TestCase):
plot = PlotWidget(backend='none')
plot.addCurve(x=(1, 2, 3), y=(3, 2, 1))
plot.addImage(numpy.arange(100.).reshape(10, -1))
- plot.addItem(
- numpy.array((1., 10.)), numpy.array((10., 10.)), shape="rectangle")
+ plot.addShape(numpy.array((1., 10.)),
+ numpy.array((10., 10.)),
+ shape="rectangle")
plot.addXMarker(10.)
@@ -400,21 +401,21 @@ class TestPlotGetCurveImage(unittest.TestCase):
# Active curve
active = plot.getActiveCurve()
- self.assertEqual(active.getLegend(), 'curve 0')
+ self.assertEqual(active.getName(), 'curve 0')
curve = plot.getCurve()
- self.assertEqual(curve.getLegend(), 'curve 0')
+ self.assertEqual(curve.getName(), 'curve 0')
# No active curve and curves
plot.setActiveCurveHandling(False)
active = plot.getActiveCurve()
self.assertIsNone(active) # No active curve
curve = plot.getCurve()
- self.assertEqual(curve.getLegend(), 'curve 2') # Last added curve
+ self.assertEqual(curve.getName(), 'curve 2') # Last added curve
# Last curve hidden
plot.hideCurve('curve 2', True)
curve = plot.getCurve()
- self.assertEqual(curve.getLegend(), 'curve 1') # Last added curve
+ self.assertEqual(curve.getName(), 'curve 1') # Last added curve
# All curves hidden
plot.hideCurve('curve 1', True)
@@ -465,9 +466,9 @@ class TestPlotGetCurveImage(unittest.TestCase):
# Active image
active = plot.getActiveImage()
- self.assertEqual(active.getLegend(), 'image 0')
+ self.assertEqual(active.getName(), 'image 0')
image = plot.getImage()
- self.assertEqual(image.getLegend(), 'image 0')
+ self.assertEqual(image.getName(), 'image 0')
# No active image
plot.addImage(((0, 1), (2, 3)), legend='image 2')
@@ -475,14 +476,14 @@ class TestPlotGetCurveImage(unittest.TestCase):
active = plot.getActiveImage()
self.assertIsNone(active)
image = plot.getImage()
- self.assertEqual(image.getLegend(), 'image 2')
+ self.assertEqual(image.getName(), 'image 2')
# Active image
plot.setActiveImage('image 1')
active = plot.getActiveImage()
- self.assertEqual(active.getLegend(), 'image 1')
+ self.assertEqual(active.getName(), 'image 1')
image = plot.getImage()
- self.assertEqual(image.getLegend(), 'image 1')
+ self.assertEqual(image.getName(), 'image 1')
def testGetImageOldApi(self):
"""PlotWidget.getImage and PlotWidget.getActiveImage old API tests"""
@@ -521,8 +522,8 @@ class TestPlotGetCurveImage(unittest.TestCase):
self.assertEqual(list(images), ['1', '2'])
images = plot.getAllImages(just_legend=False)
self.assertEqual(len(images), 2)
- self.assertEqual(images[0].getLegend(), '1')
- self.assertEqual(images[1].getLegend(), '2')
+ self.assertEqual(images[0].getName(), '1')
+ self.assertEqual(images[1].getName(), '2')
class TestPlotAddScatter(unittest.TestCase):
@@ -543,7 +544,7 @@ class TestPlotAddScatter(unittest.TestCase):
# Active scatter
active = plot._getActiveItem(kind='scatter')
- self.assertEqual(active.getLegend(), 'scatter 0')
+ self.assertEqual(active.getName(), 'scatter 0')
# check default values
self.assertAlmostEqual(active.getSymbolSize(), active._DEFAULT_SYMBOL_SIZE)
@@ -562,28 +563,25 @@ class TestPlotAddScatter(unittest.TestCase):
self.assertAlmostEqual(s0.getAlpha(), 0.777)
scatter1 = plot._getItem(kind='scatter', legend='scatter 1')
- self.assertEqual(scatter1.getLegend(), 'scatter 1')
+ self.assertEqual(scatter1.getName(), 'scatter 1')
def testGetAllScatters(self):
"""PlotWidget.getAllImages test"""
plot = PlotWidget(backend='none')
- scatters = plot._getItems(kind='scatter')
- self.assertEqual(len(scatters), 0)
+ items = plot.getItems()
+ self.assertEqual(len(items), 0)
plot.addScatter(x=(0, 1), y=(0, 1), value=(0, 1), legend='scatter 0')
plot.addScatter(x=(0, 1), y=(0, 1), value=(0, 1), legend='scatter 1')
plot.addScatter(x=(0, 1), y=(0, 1), value=(0, 1), legend='scatter 2')
- scatters = plot._getItems(kind='scatter')
- self.assertEqual(len(scatters), 3)
- self.assertEqual(scatters[0].getLegend(), 'scatter 0')
- self.assertEqual(scatters[2].getLegend(), 'scatter 2')
-
- scatters = plot._getItems(kind='scatter', just_legend=True)
- self.assertEqual(len(scatters), 3)
- self.assertEqual(list(scatters), ['scatter 0', 'scatter 1', 'scatter 2'])
+ items = plot.getItems()
+ self.assertEqual(len(items), 3)
+ self.assertEqual(items[0].getName(), 'scatter 0')
+ self.assertEqual(items[1].getName(), 'scatter 1')
+ self.assertEqual(items[2].getName(), 'scatter 2')
class TestPlotHistogram(unittest.TestCase):
diff --git a/silx/gui/plot/test/testPlotWindow.py b/silx/gui/plot/test/testPlotWindow.py
index 0a7d108..8e7b35c 100644
--- a/silx/gui/plot/test/testPlotWindow.py
+++ b/silx/gui/plot/test/testPlotWindow.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2019 European Synchrotron Radiation Facility
+# Copyright (c) 2016-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
@@ -29,13 +29,14 @@ __license__ = "MIT"
__date__ = "27/06/2017"
-import doctest
import unittest
+import numpy
from silx.gui.utils.testutils import TestCaseQt, getQToolButtonFromAction
from silx.gui import qt
from silx.gui.plot import PlotWindow
+from silx.gui.colors import Colormap
class TestPlotWindow(TestCaseQt):
@@ -85,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()
@@ -99,6 +123,37 @@ class TestPlotWindow(TestCaseQt):
self.plot.yAxisInvertedButton.setYAxisDownward()
self.assertTrue(self.plot.getYAxis().isInverted())
+ def testColormapAutoscaleCache(self):
+ # Test that the min/max cache is not computed twice
+
+ old = Colormap._computeAutoscaleRange
+ self._count = 0
+ def _computeAutoscaleRange(colormap, data):
+ self._count = self._count + 1
+ return 10, 20
+ Colormap._computeAutoscaleRange = _computeAutoscaleRange
+ try:
+ colormap = Colormap(name='red')
+ self.plot.setVisible(True)
+
+ # Add an image
+ data = numpy.arange(8**2).reshape(8, 8)
+ self.plot.addImage(data, legend="foo", colormap=colormap)
+ self.plot.setActiveImage("foo")
+
+ # Use the colorbar
+ self.plot.getColorBarWidget().setVisible(True)
+ self.qWait(50)
+
+ # Remove and add again the same item
+ image = self.plot.getImage("foo")
+ self.plot.removeImage("foo")
+ self.plot.addItem(image)
+ self.qWait(50)
+ finally:
+ Colormap._computeAutoscaleRange = old
+ self.assertEqual(self._count, 1)
+ del self._count
def suite():
test_suite = unittest.TestSuite()
diff --git a/silx/gui/plot/test/testProfile.py b/silx/gui/plot/test/testProfile.py
deleted file mode 100644
index cf40f76..0000000
--- a/silx/gui/plot/test/testProfile.py
+++ /dev/null
@@ -1,287 +0,0 @@
-# coding: utf-8
-# /*##########################################################################
-#
-# Copyright (c) 2016-2019 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
-# 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.
-#
-# ###########################################################################*/
-"""Basic tests for Profile"""
-
-__authors__ = ["T. Vincent", "P. Knobel"]
-__license__ = "MIT"
-__date__ = "17/01/2018"
-
-import numpy
-import unittest
-
-from silx.utils.testutils import ParametricTestCase
-from silx.gui.utils.testutils import (
- TestCaseQt, getQToolButtonFromAction)
-from silx.gui import qt
-from silx.gui.plot import PlotWindow, Plot1D, Plot2D, Profile
-from silx.gui.plot.StackView import StackView
-
-
-class TestProfileToolBar(TestCaseQt, ParametricTestCase):
- """Tests for ProfileToolBar widget."""
-
- def setUp(self):
- super(TestProfileToolBar, self).setUp()
- profileWindow = PlotWindow()
- self.plot = PlotWindow()
- self.toolBar = Profile.ProfileToolBar(
- plot=self.plot, profileWindow=profileWindow)
- self.plot.addToolBar(self.toolBar)
-
- self.plot.show()
- self.qWaitForWindowExposed(self.plot)
- profileWindow.show()
- self.qWaitForWindowExposed(profileWindow)
-
- self.mouseMove(self.plot) # Move to center
- self.qapp.processEvents()
-
- def tearDown(self):
- self.qapp.processEvents()
- self.plot.setAttribute(qt.Qt.WA_DeleteOnClose)
- self.plot.close()
- del self.plot
- del self.toolBar
-
- super(TestProfileToolBar, self).tearDown()
-
- def testAlignedProfile(self):
- """Test horizontal and vertical profile, without and with image"""
- # Use Plot backend widget to submit mouse events
- widget = self.plot.getWidgetHandle()
- for method in ('sum', 'mean'):
- with self.subTest(method=method):
- # 2 positions to use for mouse events
- pos1 = widget.width() * 0.4, widget.height() * 0.4
- pos2 = widget.width() * 0.6, widget.height() * 0.6
-
- for action in (self.toolBar.hLineAction, self.toolBar.vLineAction):
- with self.subTest(mode=action.text()):
- # Trigger tool button for mode
- toolButton = getQToolButtonFromAction(action)
- self.assertIsNot(toolButton, None)
- self.mouseMove(toolButton)
- self.mouseClick(toolButton, qt.Qt.LeftButton)
-
- # Without image
- self.mouseMove(widget, pos=pos1)
- self.mouseClick(widget, qt.Qt.LeftButton, pos=pos1)
-
- # with image
- self.plot.addImage(
- numpy.arange(100 * 100).reshape(100, -1))
- self.mousePress(widget, qt.Qt.LeftButton, pos=pos1)
- self.mouseMove(widget, pos=pos2)
- self.mouseRelease(widget, qt.Qt.LeftButton, pos=pos2)
-
- self.mouseMove(widget)
- self.mouseClick(widget, qt.Qt.LeftButton)
-
- def testDiagonalProfile(self):
- """Test diagonal profile, without and with image"""
- # Use Plot backend widget to submit mouse events
- widget = self.plot.getWidgetHandle()
-
- for method in ('sum', 'mean'):
- with self.subTest(method=method):
- self.toolBar.setProfileMethod(method)
-
- # 2 positions to use for mouse events
- pos1 = widget.width() * 0.4, widget.height() * 0.4
- pos2 = widget.width() * 0.6, widget.height() * 0.6
-
- for image in (False, True):
- with self.subTest(image=image):
- if image:
- self.plot.addImage(
- numpy.arange(100 * 100).reshape(100, -1))
-
- # Trigger tool button for diagonal profile mode
- toolButton = getQToolButtonFromAction(
- self.toolBar.lineAction)
- self.assertIsNot(toolButton, None)
- self.mouseMove(toolButton)
- self.mouseClick(toolButton, qt.Qt.LeftButton)
- self.toolBar.lineWidthSpinBox.setValue(3)
-
- # draw profile line
- self.mouseMove(widget, pos=pos1)
- self.mousePress(widget, qt.Qt.LeftButton, pos=pos1)
- self.mouseMove(widget, pos=pos2)
- self.mouseRelease(widget, qt.Qt.LeftButton, pos=pos2)
-
- if image is True:
- profileCurve = self.toolBar.getProfilePlot().getAllCurves()[0]
- if method == 'sum':
- self.assertTrue(profileCurve.getData()[1].max() > 10000)
- elif method == 'mean':
- self.assertTrue(profileCurve.getData()[1].max() < 10000)
- self.plot.clear()
-
-
-class TestProfile3DToolBar(TestCaseQt):
- """Tests for Profile3DToolBar widget.
- """
- def setUp(self):
- super(TestProfile3DToolBar, self).setUp()
- self.plot = StackView()
- self.plot.show()
- self.qWaitForWindowExposed(self.plot)
-
- self.plot.setStack(numpy.array([
- [[0, 1, 2], [3, 4, 5]],
- [[6, 7, 8], [9, 10, 11]],
- [[12, 13, 14], [15, 16, 17]]
- ]))
-
- def tearDown(self):
- self.plot.setAttribute(qt.Qt.WA_DeleteOnClose)
- self.plot.close()
- self.plot = None
-
- super(TestProfile3DToolBar, self).tearDown()
-
- def testMethodProfile1DAnd2D(self):
- """Test that the profile can have a different method if we want to
- compute then in 1D or in 2D"""
-
- _3DProfileToolbar = self.plot.getProfileToolbar()
- _2DProfilePlot = _3DProfileToolbar.getProfilePlot()
- self.plot.getProfileToolbar().setProfileMethod('mean')
- self.plot.getProfileToolbar().lineWidthSpinBox.setValue(3)
- self.assertTrue(_3DProfileToolbar.getProfileMethod() == 'mean')
-
- # check 2D 'mean' profile
- _3DProfileToolbar.profile3dAction.computeProfileIn2D()
- toolButton = getQToolButtonFromAction(_3DProfileToolbar.vLineAction)
- self.assertIsNot(toolButton, None)
- self.mouseMove(toolButton)
- self.mouseClick(toolButton, qt.Qt.LeftButton)
- plot2D = self.plot.getPlot().getWidgetHandle()
- pos1 = plot2D.width() * 0.5, plot2D.height() * 0.5
- self.mouseClick(plot2D, qt.Qt.LeftButton, pos=pos1)
- self.assertTrue(numpy.array_equal(
- _2DProfilePlot.getActiveImage().getData(),
- numpy.array([[1, 4], [7, 10], [13, 16]])
- ))
-
- # check 1D 'sum' profile
- _2DProfileToolbar = _2DProfilePlot.getProfileToolbar()
- _2DProfileToolbar.setProfileMethod('sum')
- self.assertTrue(_2DProfileToolbar.getProfileMethod() == 'sum')
- _1DProfilePlot = _2DProfileToolbar.getProfilePlot()
-
- _2DProfileToolbar.lineWidthSpinBox.setValue(3)
- toolButton = getQToolButtonFromAction(_2DProfileToolbar.vLineAction)
- self.assertIsNot(toolButton, None)
- self.mouseMove(toolButton)
- self.mouseClick(toolButton, qt.Qt.LeftButton)
- plot1D = _2DProfilePlot.getWidgetHandle()
- pos1 = plot1D.width() * 0.5, plot1D.height() * 0.5
- self.mouseClick(plot1D, qt.Qt.LeftButton, pos=pos1)
- self.assertTrue(numpy.array_equal(
- _1DProfilePlot.getAllCurves()[0].getData()[1],
- numpy.array([5, 17, 29])
- ))
-
- def testMethodSumLine(self):
- """Simple interaction test to make sure the sum is correctly computed
- """
- _3DProfileToolbar = self.plot.getProfileToolbar()
- _2DProfilePlot = _3DProfileToolbar.getProfilePlot()
- self.plot.getProfileToolbar().setProfileMethod('sum')
- self.plot.getProfileToolbar().lineWidthSpinBox.setValue(3)
- self.assertTrue(_3DProfileToolbar.getProfileMethod() == 'sum')
-
- # check 2D 'mean' profile
- _3DProfileToolbar.profile3dAction.computeProfileIn2D()
- toolButton = getQToolButtonFromAction(_3DProfileToolbar.lineAction)
- self.assertIsNot(toolButton, None)
- self.mouseMove(toolButton)
- self.mouseClick(toolButton, qt.Qt.LeftButton)
- plot2D = self.plot.getPlot().getWidgetHandle()
- pos1 = plot2D.width() * 0.5, plot2D.height() * 0.2
- pos2 = plot2D.width() * 0.5, plot2D.height() * 0.8
-
- self.mouseMove(plot2D, pos=pos1)
- self.mousePress(plot2D, qt.Qt.LeftButton, pos=pos1)
- self.mouseMove(plot2D, pos=pos2)
- self.mouseRelease(plot2D, qt.Qt.LeftButton, pos=pos2)
- self.assertTrue(numpy.array_equal(
- _2DProfilePlot.getActiveImage().getData(),
- numpy.array([[3, 12], [21, 30], [39, 48]])
- ))
-
-
-class TestGetProfilePlot(TestCaseQt):
-
- def testProfile1D(self):
- plot = Plot2D()
- plot.show()
- self.qWaitForWindowExposed(plot)
- plot.addImage([[0, 1], [2, 3]])
- self.assertIsInstance(plot.getProfileToolbar().getProfileMainWindow(),
- qt.QMainWindow)
- self.assertIsInstance(plot.getProfilePlot(),
- Plot1D)
- plot.setAttribute(qt.Qt.WA_DeleteOnClose)
- plot.close()
- del plot
-
- def testProfile2D(self):
- """Test that the profile plot associated to a stack view is either a
- Plot1D or a plot 2D instance."""
- plot = StackView()
- plot.show()
- self.qWaitForWindowExposed(plot)
-
- plot.setStack(numpy.array([[[0, 1], [2, 3]],
- [[4, 5], [6, 7]]]))
-
- self.assertIsInstance(plot.getProfileToolbar().getProfileMainWindow(),
- qt.QMainWindow)
-
- self.assertIsInstance(plot.getProfileToolbar().getProfilePlot(),
- Plot2D)
- plot.getProfileToolbar().profile3dAction.computeProfileIn1D()
- self.assertIsInstance(plot.getProfileToolbar().getProfilePlot(),
- Plot1D)
-
- plot.setAttribute(qt.Qt.WA_DeleteOnClose)
- plot.close()
- del plot
-
-
-def suite():
- test_suite = unittest.TestSuite()
- for testClass in (TestProfileToolBar, TestGetProfilePlot,
- TestProfile3DToolBar):
- test_suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase(
- testClass))
- return test_suite
-
-
-if __name__ == '__main__':
- unittest.main(defaultTest='suite')
diff --git a/silx/gui/plot/test/testStats.py b/silx/gui/plot/test/testStats.py
index 185e79c..8db8cc9 100644
--- a/silx/gui/plot/test/testStats.py
+++ b/silx/gui/plot/test/testStats.py
@@ -1,7 +1,7 @@
# coding: utf-8
# /*##########################################################################
#
-# Copyright (c) 2016-2019 European Synchrotron Radiation Facility
+# Copyright (c) 2016-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
@@ -56,10 +56,14 @@ class TestStats(TestCaseQt):
def tearDown(self):
self.plot1d.setAttribute(qt.Qt.WA_DeleteOnClose)
self.plot1d.close()
+ del self.plot1d
self.plot2d.setAttribute(qt.Qt.WA_DeleteOnClose)
self.plot2d.close()
+ del self.plot2d
self.scatterPlot.setAttribute(qt.Qt.WA_DeleteOnClose)
self.scatterPlot.close()
+ del self.scatterPlot
+ TestCaseQt.tearDown(self)
def createCurveContext(self):
self.plot1d = Plot1D()
@@ -242,6 +246,7 @@ class TestStats(TestCaseQt):
class TestStatsFormatter(TestCaseQt):
"""Simple test to check usage of the :class:`StatsFormatter`"""
def setUp(self):
+ TestCaseQt.setUp(self)
self.plot1d = Plot1D()
x = range(20)
y = range(20)
@@ -257,6 +262,8 @@ class TestStatsFormatter(TestCaseQt):
def tearDown(self):
self.plot1d.setAttribute(qt.Qt.WA_DeleteOnClose)
self.plot1d.close()
+ del self.plot1d
+ TestCaseQt.tearDown(self)
def testEmptyFormatter(self):
"""Make sure a formatter with no formatter definition will return a
@@ -402,10 +409,10 @@ class TestStatsWidgetWithCurves(TestCaseQt, ParametricTestCase):
def check_display_only_active_item(only_active):
# check internal value
- self.assertTrue(widget._statsTable._displayOnlyActItem is only_active)
+ self.assertIs(widget._statsTable._displayOnlyActItem, only_active)
# self.assertTrue(table._displayOnlyActItem is only_active)
# check gui display
- self.assertTrue(widget._options.isActiveItemMode() is only_active)
+ self.assertEqual(widget._options.isActiveItemMode(), only_active)
for displayOnlyActiveItems in (True, False):
with self.subTest(displayOnlyActiveItems=displayOnlyActiveItems):
@@ -479,7 +486,7 @@ class TestStatsWidgetWithCurves(TestCaseQt, ParametricTestCase):
self.widget.setUpdateMode(StatsWidget.UpdateMode.AUTO)
update_stats_action = self.widget._options.getUpdateStatsAction()
# test from api
- self.assertTrue(self.widget.getUpdateMode() is StatsWidget.UpdateMode.AUTO)
+ self.assertEqual(self.widget.getUpdateMode(), StatsWidget.UpdateMode.AUTO)
self.widget.show()
# check stats change in auto mode
self.plot.getCurve('curve0').setData(x=range(4), y=range(-1, 3))
@@ -497,7 +504,7 @@ class TestStatsWidgetWithCurves(TestCaseQt, ParametricTestCase):
# check stats change in manual mode only if requested
self.widget.setUpdateMode(StatsWidget.UpdateMode.MANUAL)
- self.assertTrue(self.widget.getUpdateMode() is StatsWidget.UpdateMode.MANUAL)
+ self.assertEqual(self.widget.getUpdateMode(), StatsWidget.UpdateMode.MANUAL)
self.plot.getCurve('curve0').setData(x=range(4), y=range(2, 6))
self.qapp.processEvents()
@@ -710,7 +717,7 @@ class TestLineWidget(TestCaseQt):
self.qapp.processEvents()
self.assertTrue(self.widget._lineStatsWidget._statQlineEdit['min'].text() == '14.000')
self.plot.setActiveCurve(None)
- self.assertTrue(self.plot.getActiveCurve() is None)
+ self.assertIsNone(self.plot.getActiveCurve())
self.widget.setStatsOnVisibleData(False)
self.qapp.processEvents()
self.assertFalse(self.widget._lineStatsWidget._statQlineEdit['min'].text() == '14.000')
@@ -780,23 +787,23 @@ class TestUpdateModeWidget(TestCaseQt):
self.widget.sigUpdateModeChanged.connect(modeChangedListener)
self.widget.sigUpdateRequested.connect(manualUpdateListener)
self.widget.setUpdateMode(StatsWidget.UpdateMode.AUTO)
- self.assertTrue(self.widget.getUpdateMode() is StatsWidget.UpdateMode.AUTO)
- self.assertTrue(modeChangedListener.callCount() is 0)
+ self.assertEqual(self.widget.getUpdateMode(), StatsWidget.UpdateMode.AUTO)
+ self.assertEqual(modeChangedListener.callCount(), 0)
self.qapp.processEvents()
self.widget.setUpdateMode(StatsWidget.UpdateMode.MANUAL)
- self.assertTrue(self.widget.getUpdateMode() is StatsWidget.UpdateMode.MANUAL)
+ self.assertEqual(self.widget.getUpdateMode(), StatsWidget.UpdateMode.MANUAL)
self.qapp.processEvents()
- self.assertTrue(modeChangedListener.callCount() is 1)
- self.assertTrue(manualUpdateListener.callCount() is 0)
+ self.assertEqual(modeChangedListener.callCount(), 1)
+ self.assertEqual(manualUpdateListener.callCount(), 0)
self.widget._updatePB.click()
self.widget._updatePB.click()
- self.assertTrue(manualUpdateListener.callCount() is 2)
+ self.assertEqual(manualUpdateListener.callCount(), 2)
self.widget._autoRB.setChecked(True)
- self.assertTrue(modeChangedListener.callCount() is 2)
+ self.assertEqual(modeChangedListener.callCount(), 2)
self.widget._updatePB.click()
- self.assertTrue(manualUpdateListener.callCount() is 2)
+ self.assertEqual(manualUpdateListener.callCount(), 2)
def suite():