diff options
author | Alexandre Marie <alexandre.marie@synchrotron-soleil.fr> | 2020-07-21 14:45:14 +0200 |
---|---|---|
committer | Alexandre Marie <alexandre.marie@synchrotron-soleil.fr> | 2020-07-21 14:45:14 +0200 |
commit | 328032e2317e3ac4859196bbf12bdb71795302fe (patch) | |
tree | 8cd13462beab109e3cb53410c42335b6d1e00ee6 /silx/gui/plot/test | |
parent | 33ed2a64c92b0311ae35456c016eb284e426afc2 (diff) |
New upstream version 0.13.0+dfsg
Diffstat (limited to 'silx/gui/plot/test')
-rw-r--r-- | silx/gui/plot/test/__init__.py | 8 | ||||
-rw-r--r-- | silx/gui/plot/test/testColorBar.py | 19 | ||||
-rw-r--r-- | silx/gui/plot/test/testCurvesROIWidget.py | 37 | ||||
-rw-r--r-- | silx/gui/plot/test/testImageStack.py | 197 | ||||
-rw-r--r-- | silx/gui/plot/test/testInteraction.py | 22 | ||||
-rw-r--r-- | silx/gui/plot/test/testItem.py | 4 | ||||
-rw-r--r-- | silx/gui/plot/test/testPixelIntensityHistoAction.py | 55 | ||||
-rwxr-xr-x | silx/gui/plot/test/testPlotWidget.py | 145 | ||||
-rw-r--r-- | silx/gui/plot/test/testPlotWidgetNoBackend.py | 50 | ||||
-rw-r--r-- | silx/gui/plot/test/testPlotWindow.py | 59 | ||||
-rw-r--r-- | silx/gui/plot/test/testProfile.py | 287 | ||||
-rw-r--r-- | silx/gui/plot/test/testStats.py | 35 |
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(): |