diff options
Diffstat (limited to 'silx/gui/plot/test')
26 files changed, 0 insertions, 8419 deletions
diff --git a/silx/gui/plot/test/__init__.py b/silx/gui/plot/test/__init__.py deleted file mode 100644 index dfb7c2e..0000000 --- a/silx/gui/plot/test/__init__.py +++ /dev/null @@ -1,92 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# -# Copyright (c) 2016-2018 European Synchrotron Radiation Facility -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# 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. -# -# ###########################################################################*/ -__authors__ = ["T. Vincent"] -__license__ = "MIT" -__date__ = "23/07/2018" - - -import unittest - -from .._utils import test -from . import testColorBar -from . import testCurvesROIWidget -from . import testStats -from . import testAlphaSlider -from . import testInteraction -from . import testLegendSelector -from . import testMaskToolsWidget -from . import testScatterMaskToolsWidget -from . import testPlotInteraction -from . import testPlotWidgetNoBackend -from . import testPlotWidget -from . import testPlotWindow -from . import testStackView -from . import testImageStack -from . import testItem -from . import testUtilsAxis -from . import testLimitConstraints -from . import testComplexImageView -from . import testImageView -from . import testSaveAction -from . import testScatterView -from . import testPixelIntensityHistoAction -from . import testCompareImages -from . import testRoiStatsWidget - - -def suite(): - # Lazy-loading to avoid cyclic reference - from ..tools import test as testTools - - test_suite = unittest.TestSuite() - test_suite.addTests( - [test.suite(), - testTools.suite(), - testColorBar.suite(), - testCurvesROIWidget.suite(), - testStats.suite(), - testAlphaSlider.suite(), - testInteraction.suite(), - testLegendSelector.suite(), - testMaskToolsWidget.suite(), - testScatterMaskToolsWidget.suite(), - testPlotInteraction.suite(), - testPlotWidgetNoBackend.suite(), - testPlotWidget.suite(), - testPlotWindow.suite(), - testStackView.suite(), - testImageStack.suite(), - testItem.suite(), - testUtilsAxis.suite(), - testLimitConstraints.suite(), - testComplexImageView.suite(), - testImageView.suite(), - testSaveAction.suite(), - testScatterView.suite(), - testPixelIntensityHistoAction.suite(), - testCompareImages.suite(), - testRoiStatsWidget.suite(), - ]) - return test_suite diff --git a/silx/gui/plot/test/testAlphaSlider.py b/silx/gui/plot/test/testAlphaSlider.py deleted file mode 100644 index 01e6969..0000000 --- a/silx/gui/plot/test/testAlphaSlider.py +++ /dev/null @@ -1,218 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# -# Copyright (c) 2017-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. -# -# ###########################################################################*/ -"""Tests for ImageAlphaSlider""" - - -__authors__ = ["P. Knobel"] -__license__ = "MIT" -__date__ = "28/03/2017" - -import numpy -import unittest - -from silx.gui import qt -from silx.gui.utils.testutils import TestCaseQt -from silx.gui.plot import PlotWidget -from silx.gui.plot import AlphaSlider - - -class TestActiveImageAlphaSlider(TestCaseQt): - def setUp(self): - super(TestActiveImageAlphaSlider, self).setUp() - self.plot = PlotWidget() - self.aslider = AlphaSlider.ActiveImageAlphaSlider(plot=self.plot) - self.aslider.setOrientation(qt.Qt.Horizontal) - - toolbar = qt.QToolBar("plot", self.plot) - toolbar.addWidget(self.aslider) - self.plot.addToolBar(toolbar) - - self.plot.show() - self.qWaitForWindowExposed(self.plot) - - 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.aslider - - super(TestActiveImageAlphaSlider, self).tearDown() - - def testWidgetEnabled(self): - # no active image initially, slider must be deactivate - self.assertFalse(self.aslider.isEnabled()) - - self.plot.addImage(numpy.array([[0, 1, 2], [3, 4, 5]])) - # now we have an active image - self.assertTrue(self.aslider.isEnabled()) - - self.plot.setActiveImage(None) - self.assertFalse(self.aslider.isEnabled()) - - def testGetImage(self): - self.plot.addImage(numpy.array([[0, 1, 2], [3, 4, 5]])) - self.assertEqual(self.plot.getActiveImage(), - self.aslider.getItem()) - - self.plot.addImage(numpy.array([[0, 1, 3], [2, 4, 6]]), legend="2") - self.plot.setActiveImage("2") - self.assertEqual(self.plot.getImage("2"), - self.aslider.getItem()) - - def testGetAlpha(self): - self.plot.addImage(numpy.array([[0, 1, 2], [3, 4, 5]]), legend="1") - self.aslider.setValue(137) - self.assertAlmostEqual(self.aslider.getAlpha(), - 137. / 255) - - -class TestNamedImageAlphaSlider(TestCaseQt): - def setUp(self): - super(TestNamedImageAlphaSlider, self).setUp() - self.plot = PlotWidget() - self.aslider = AlphaSlider.NamedImageAlphaSlider(plot=self.plot) - self.aslider.setOrientation(qt.Qt.Horizontal) - - toolbar = qt.QToolBar("plot", self.plot) - toolbar.addWidget(self.aslider) - self.plot.addToolBar(toolbar) - - self.plot.show() - self.qWaitForWindowExposed(self.plot) - - 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.aslider - - super(TestNamedImageAlphaSlider, self).tearDown() - - def testWidgetEnabled(self): - # no image set initially, slider must be deactivate - self.assertFalse(self.aslider.isEnabled()) - - self.plot.addImage(numpy.array([[0, 1, 2], [3, 4, 5]]), legend="1") - self.aslider.setLegend("1") - # now we have an image set - self.assertTrue(self.aslider.isEnabled()) - - def testGetImage(self): - self.plot.addImage(numpy.array([[0, 1, 2], [3, 4, 5]]), legend="1") - self.plot.addImage(numpy.array([[0, 1, 3], [2, 4, 6]]), legend="2") - self.aslider.setLegend("1") - self.assertEqual(self.plot.getImage("1"), - self.aslider.getItem()) - - self.aslider.setLegend("2") - self.assertEqual(self.plot.getImage("2"), - self.aslider.getItem()) - - def testGetAlpha(self): - self.plot.addImage(numpy.array([[0, 1, 2], [3, 4, 5]]), legend="1") - self.aslider.setLegend("1") - self.aslider.setValue(128) - self.assertAlmostEqual(self.aslider.getAlpha(), - 128. / 255) - - -class TestNamedScatterAlphaSlider(TestCaseQt): - def setUp(self): - super(TestNamedScatterAlphaSlider, self).setUp() - self.plot = PlotWidget() - self.aslider = AlphaSlider.NamedScatterAlphaSlider(plot=self.plot) - self.aslider.setOrientation(qt.Qt.Horizontal) - - toolbar = qt.QToolBar("plot", self.plot) - toolbar.addWidget(self.aslider) - self.plot.addToolBar(toolbar) - - self.plot.show() - self.qWaitForWindowExposed(self.plot) - - 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.aslider - - super(TestNamedScatterAlphaSlider, self).tearDown() - - def testWidgetEnabled(self): - # no Scatter set initially, slider must be deactivate - self.assertFalse(self.aslider.isEnabled()) - - self.plot.addScatter([0, 1, 2], [2, 3, 4], [5, 6, 7], - legend="1") - self.aslider.setLegend("1") - # now we have an image set - self.assertTrue(self.aslider.isEnabled()) - - def testGetScatter(self): - self.plot.addScatter([0, 1, 2], [2, 3, 4], [5, 6, 7], - legend="1") - self.plot.addScatter([0, 10, 20], [20, 30, 40], [50, 60, 70], - legend="2") - self.aslider.setLegend("1") - self.assertEqual(self.plot.getScatter("1"), - self.aslider.getItem()) - - self.aslider.setLegend("2") - self.assertEqual(self.plot.getScatter("2"), - self.aslider.getItem()) - - def testGetAlpha(self): - self.plot.addScatter([0, 10, 20], [20, 30, 40], [50, 60, 70], - legend="1") - self.aslider.setLegend("1") - self.aslider.setValue(128) - self.assertAlmostEqual(self.aslider.getAlpha(), - 128. / 255) - - -def suite(): - test_suite = unittest.TestSuite() - # test_suite.addTest(positionInfoTestSuite) - for testClass in (TestActiveImageAlphaSlider, TestNamedImageAlphaSlider, - TestNamedScatterAlphaSlider): - test_suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase( - testClass)) - return test_suite - - -if __name__ == '__main__': - unittest.main(defaultTest='suite') diff --git a/silx/gui/plot/test/testColorBar.py b/silx/gui/plot/test/testColorBar.py deleted file mode 100644 index a6f141c..0000000 --- a/silx/gui/plot/test/testColorBar.py +++ /dev/null @@ -1,354 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# -# 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 -# 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 ColorBar featues and sub widgets of Colorbar module""" - -__authors__ = ["H. Payno"] -__license__ = "MIT" -__date__ = "24/04/2018" - -import unittest -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 - - -class TestColorScale(TestCaseQt): - """Test that interaction with the colorScale is correct""" - def setUp(self): - super(TestColorScale, self).setUp() - self.colorScaleWidget = _ColorScale(colormap=None, parent=None) - self.colorScaleWidget.show() - self.qWaitForWindowExposed(self.colorScaleWidget) - - def tearDown(self): - self.qapp.processEvents() - self.colorScaleWidget.setAttribute(qt.Qt.WA_DeleteOnClose) - self.colorScaleWidget.close() - del self.colorScaleWidget - super(TestColorScale, self).tearDown() - - def testNoColormap(self): - """Test _ColorScale without a colormap""" - colormap = self.colorScaleWidget.getColormap() - self.assertIsNone(colormap) - - def testRelativePositionLinear(self): - self.colorMapLin1 = Colormap(name='gray', - normalization=Colormap.LINEAR, - vmin=0.0, - vmax=1.0) - self.colorScaleWidget.setColormap(self.colorMapLin1) - - self.assertTrue( - self.colorScaleWidget.getValueFromRelativePosition(0.25) == 0.25) - self.assertTrue( - self.colorScaleWidget.getValueFromRelativePosition(0.5) == 0.5) - self.assertTrue( - self.colorScaleWidget.getValueFromRelativePosition(1.0) == 1.0) - - self.colorMapLin2 = Colormap(name='viridis', - normalization=Colormap.LINEAR, - vmin=-10, - vmax=0) - self.colorScaleWidget.setColormap(self.colorMapLin2) - - self.assertTrue( - self.colorScaleWidget.getValueFromRelativePosition(0.25) == -7.5) - self.assertTrue( - self.colorScaleWidget.getValueFromRelativePosition(0.5) == -5.0) - self.assertTrue( - self.colorScaleWidget.getValueFromRelativePosition(1.0) == 0.0) - - def testRelativePositionLog(self): - self.colorMapLog1 = Colormap(name='temperature', - normalization=Colormap.LOGARITHM, - vmin=1.0, - vmax=100.0) - - self.colorScaleWidget.setColormap(self.colorMapLog1) - - val = self.colorScaleWidget.getValueFromRelativePosition(1.0) - self.assertAlmostEqual(val, 100.0) - - val = self.colorScaleWidget.getValueFromRelativePosition(0.5) - self.assertAlmostEqual(val, 10.0) - - val = self.colorScaleWidget.getValueFromRelativePosition(0.0) - self.assertTrue(val == 1.0) - - -class TestNoAutoscale(TestCaseQt): - """Test that ticks and color displayed are correct in the case of a colormap - with no autoscale - """ - - def setUp(self): - super(TestNoAutoscale, self).setUp() - self.plot = Plot2D() - self.colorBar = self.plot.getColorBarWidget() - self.colorBar.setVisible(True) # Makes sure the colormap is visible - self.tickBar = self.colorBar.getColorScaleBar().getTickBar() - self.colorScale = self.colorBar.getColorScaleBar().getColorScale() - - self.plot.show() - self.qWaitForWindowExposed(self.plot) - - def tearDown(self): - self.qapp.processEvents() - self.tickBar = None - self.colorScale = None - del self.colorBar - self.plot.setAttribute(qt.Qt.WA_DeleteOnClose) - self.plot.close() - del self.plot - super(TestNoAutoscale, self).tearDown() - - def testLogNormNoAutoscale(self): - colormapLog = Colormap(name='gray', - normalization=Colormap.LOGARITHM, - vmin=1.0, - vmax=100.0) - - data = numpy.linspace(10, 1e10, 9).reshape(3, 3) - self.plot.addImage(data=data, colormap=colormapLog, legend='toto') - self.plot.setActiveImage('toto') - - # test Ticks - self.tickBar.setTicksNumber(10) - self.tickBar.computeTicks() - - ticksTh = numpy.linspace(1.0, 100.0, 10) - ticksTh = 10**ticksTh - numpy.array_equal(self.tickBar.ticks, ticksTh) - - # test ColorScale - val = self.colorScale.getValueFromRelativePosition(1.0) - self.assertAlmostEqual(val, 100.0) - - val = self.colorScale.getValueFromRelativePosition(0.0) - self.assertTrue(val == 1.0) - - def testLinearNormNoAutoscale(self): - colormapLog = Colormap(name='gray', - normalization=Colormap.LINEAR, - vmin=-4, - vmax=5) - - data = numpy.linspace(1, 9, 9).reshape(3, 3) - self.plot.addImage(data=data, colormap=colormapLog, legend='toto') - self.plot.setActiveImage('toto') - - # test Ticks - self.tickBar.setTicksNumber(10) - self.tickBar.computeTicks() - - numpy.array_equal(self.tickBar.ticks, numpy.linspace(-4, 5, 10)) - - # test ColorScale - val = self.colorScale.getValueFromRelativePosition(1.0) - self.assertTrue(val == 5.0) - - val = self.colorScale.getValueFromRelativePosition(0.0) - self.assertTrue(val == -4.0) - - -class TestColorBarWidget(TestCaseQt): - """Test interaction with the ColorBarWidget""" - - def setUp(self): - super(TestColorBarWidget, self).setUp() - self.plot = Plot2D() - self.colorBar = self.plot.getColorBarWidget() - self.colorBar.setVisible(True) # Makes sure the colormap is visible - - self.plot.show() - self.qWaitForWindowExposed(self.plot) - - def tearDown(self): - self.qapp.processEvents() - del self.colorBar - self.plot.setAttribute(qt.Qt.WA_DeleteOnClose) - self.plot.close() - del self.plot - super(TestColorBarWidget, self).tearDown() - - def testEmptyColorBar(self): - colorBar = ColorBarWidget(parent=None) - colorBar.show() - self.qWaitForWindowExposed(colorBar) - - def testNegativeColormaps(self): - """test the behavior of the ColorBarWidget in the case of negative - values - - Note : colorbar is modified by the Plot directly not ColorBarWidget - """ - colormapLog = Colormap(name='gray', - normalization=Colormap.LOGARITHM, - vmin=None, - vmax=None) - - data = numpy.array([-5, -4, 0, 2, 3, 5, 10, 20, 30]) - data = data.reshape(3, 3) - self.plot.addImage(data=data, colormap=colormapLog, legend='toto') - self.plot.setActiveImage('toto') - - # default behavior when with log and negative values: should set vmin - # to 1 and vmax to 10 - self.assertTrue(self.colorBar.getColorScaleBar().minVal == 2) - self.assertTrue(self.colorBar.getColorScaleBar().maxVal == 30) - - # if data is positive - data[data < 1] = data.max() - self.plot.addImage(data=data, - colormap=colormapLog, - legend='toto', - replace=True) - self.plot.setActiveImage('toto') - - self.assertTrue(self.colorBar.getColorScaleBar().minVal == data.min()) - self.assertTrue(self.colorBar.getColorScaleBar().maxVal == data.max()) - - def testPlotAssocation(self): - """Make sure the ColorBarWidget is properly connected with the plot""" - colormap = Colormap(name='gray', - normalization=Colormap.LINEAR, - vmin=None, - vmax=None) - - # make sure that default settings are the same (but a copy of the - self.colorBar.setPlot(self.plot) - self.assertTrue( - self.colorBar.getColormap() is self.plot.getDefaultColormap()) - - data = numpy.linspace(0, 10, 100).reshape(10, 10) - self.plot.addImage(data=data, colormap=colormap, legend='toto') - self.plot.setActiveImage('toto') - - # make sure the modification of the colormap has been done - self.assertFalse( - self.colorBar.getColormap() is self.plot.getDefaultColormap()) - self.assertTrue( - self.colorBar.getColormap() is colormap) - - # test that colorbar is updated when default plot colormap changes - self.plot.clear() - plotColormap = Colormap(name='gray', - normalization=Colormap.LOGARITHM, - vmin=None, - vmax=None) - self.plot.setDefaultColormap(plotColormap) - self.assertTrue(self.colorBar.getColormap() is plotColormap) - - def testColormapWithoutRange(self): - """Test with a colormap with vmin==vmax""" - colormap = Colormap(name='gray', - normalization=Colormap.LINEAR, - vmin=1.0, - vmax=1.0) - self.colorBar.setColormap(colormap) - - -class TestColorBarUpdate(TestCaseQt): - """Test that the ColorBar is correctly updated when the signal 'sigChanged' - of the colormap is emitted - """ - - def setUp(self): - super(TestColorBarUpdate, self).setUp() - self.plot = Plot2D() - self.colorBar = self.plot.getColorBarWidget() - self.colorBar.setVisible(True) # Makes sure the colormap is visible - self.colorBar.setPlot(self.plot) - - self.plot.show() - self.qWaitForWindowExposed(self.plot) - self.data = numpy.random.rand(9).reshape(3, 3) - - def tearDown(self): - self.qapp.processEvents() - del self.colorBar - self.plot.setAttribute(qt.Qt.WA_DeleteOnClose) - self.plot.close() - del self.plot - super(TestColorBarUpdate, self).tearDown() - - def testUpdateColorMap(self): - colormap = Colormap(name='gray', - normalization='linear', - vmin=0, - vmax=1) - - # check inital state - self.plot.addImage(data=self.data, colormap=colormap, legend='toto') - self.plot.setActiveImage('toto') - - self.assertTrue(self.colorBar.getColorScaleBar().minVal == 0) - self.assertTrue(self.colorBar.getColorScaleBar().maxVal == 1) - self.assertTrue( - self.colorBar.getColorScaleBar().getTickBar()._vmin == 0) - self.assertTrue( - self.colorBar.getColorScaleBar().getTickBar()._vmax == 1) - self.assertIsInstance( - self.colorBar.getColorScaleBar().getTickBar()._normalizer, - colors._LinearNormalization) - - # update colormap - colormap.setVMin(0.5) - self.assertTrue(self.colorBar.getColorScaleBar().minVal == 0.5) - self.assertTrue( - self.colorBar.getColorScaleBar().getTickBar()._vmin == 0.5) - - colormap.setVMax(0.8) - self.assertTrue(self.colorBar.getColorScaleBar().maxVal == 0.8) - self.assertTrue( - self.colorBar.getColorScaleBar().getTickBar()._vmax == 0.8) - - colormap.setNormalization('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 - - -def suite(): - test_suite = unittest.TestSuite() - for ui in (TestColorScale, TestNoAutoscale, TestColorBarWidget, - TestColorBarUpdate): - test_suite.addTest( - unittest.defaultTestLoader.loadTestsFromTestCase(ui)) - - return test_suite - - -if __name__ == '__main__': - unittest.main(defaultTest='suite') diff --git a/silx/gui/plot/test/testCompareImages.py b/silx/gui/plot/test/testCompareImages.py deleted file mode 100644 index ed6942a..0000000 --- a/silx/gui/plot/test/testCompareImages.py +++ /dev/null @@ -1,117 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# -# Copyright (c) 2016-2017 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. -# -# ###########################################################################*/ -"""Tests for CompareImages widget""" - -__authors__ = ["H. Payno"] -__license__ = "MIT" -__date__ = "23/07/2018" - -import unittest -import numpy -import weakref - -from silx.gui.utils.testutils import TestCaseQt -from silx.gui.plot.CompareImages import CompareImages - - -class TestCompareImages(TestCaseQt): - """Test that CompareImages widget is working in some cases""" - - def setUp(self): - super(TestCompareImages, self).setUp() - self.widget = CompareImages() - - def tearDown(self): - ref = weakref.ref(self.widget) - self.widget = None - self.qWaitForDestroy(ref) - super(TestCompareImages, self).tearDown() - - def testIntensityImage(self): - image1 = numpy.random.rand(10, 10) - image2 = numpy.random.rand(10, 10) - self.widget.setData(image1, image2) - - def testRgbImage(self): - image1 = numpy.random.randint(0, 255, size=(10, 10, 3)) - image2 = numpy.random.randint(0, 255, size=(10, 10, 3)) - self.widget.setData(image1, image2) - - def testRgbaImage(self): - image1 = numpy.random.randint(0, 255, size=(10, 10, 4)) - image2 = numpy.random.randint(0, 255, size=(10, 10, 4)) - self.widget.setData(image1, image2) - - def testVizualisations(self): - image1 = numpy.random.rand(10, 10) - image2 = numpy.random.rand(10, 10) - self.widget.setData(image1, image2) - for mode in CompareImages.VisualizationMode: - self.widget.setVisualizationMode(mode) - - def testAlignemnt(self): - image1 = numpy.random.rand(10, 10) - image2 = numpy.random.rand(5, 5) - self.widget.setData(image1, image2) - for mode in CompareImages.AlignmentMode: - self.widget.setAlignmentMode(mode) - - def testGetPixel(self): - image1 = numpy.random.rand(11, 11) - image2 = numpy.random.rand(5, 5) - image1[5, 5] = 111.111 - image2[2, 2] = 222.222 - self.widget.setData(image1, image2) - expectedValue = {} - expectedValue[CompareImages.AlignmentMode.CENTER] = 222.222 - expectedValue[CompareImages.AlignmentMode.STRETCH] = 222.222 - expectedValue[CompareImages.AlignmentMode.ORIGIN] = None - for mode in expectedValue.keys(): - self.widget.setAlignmentMode(mode) - data = self.widget.getRawPixelData(11 / 2.0, 11 / 2.0) - data1, data2 = data - self.assertEqual(data1, 111.111) - self.assertEqual(data2, expectedValue[mode]) - - def testImageEmpty(self): - self.widget.setData(image1=None, image2=None) - self.assertTrue(self.widget.getRawPixelData(11 / 2.0, 11 / 2.0) == (None, None)) - - def testSetImageSeparately(self): - self.widget.setImage1(numpy.random.rand(10, 10)) - self.widget.setImage2(numpy.random.rand(10, 10)) - for mode in CompareImages.VisualizationMode: - self.widget.setVisualizationMode(mode) - - -def suite(): - test_suite = unittest.TestSuite() - loadTests = unittest.defaultTestLoader.loadTestsFromTestCase - test_suite.addTest(loadTests(TestCompareImages)) - return test_suite - - -if __name__ == '__main__': - unittest.main(defaultTest='suite') diff --git a/silx/gui/plot/test/testComplexImageView.py b/silx/gui/plot/test/testComplexImageView.py deleted file mode 100644 index 4ac3488..0000000 --- a/silx/gui/plot/test/testComplexImageView.py +++ /dev/null @@ -1,95 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# -# Copyright (c) 2017-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. -# -# ###########################################################################*/ -"""Test suite for :class:`ComplexImageView`""" - -__authors__ = ["T. Vincent"] -__license__ = "MIT" -__date__ = "17/01/2018" - - -import unittest -import logging -import numpy - -from silx.utils.testutils import ParametricTestCase -from silx.gui.plot import ComplexImageView - -from .utils import PlotWidgetTestCase - - -logger = logging.getLogger(__name__) - - -class TestComplexImageView(PlotWidgetTestCase, ParametricTestCase): - """Test suite of ComplexImageView widget""" - - def _createPlot(self): - return ComplexImageView.ComplexImageView() - - def testPlot2DComplex(self): - """Test API of ComplexImageView widget""" - data = numpy.array(((0, 1j), (1, 1 + 1j)), dtype=numpy.complex64) - self.plot.setData(data) - self.plot.setKeepDataAspectRatio(True) - self.plot.getPlot().resetZoom() - self.qWait(100) - - # Test colormap API - colormap = self.plot.getColormap().copy() - colormap.setName('magma') - self.plot.setColormap(colormap) - self.qWait(100) - - # Test all modes - modes = self.plot.supportedComplexModes() - for mode in modes: - with self.subTest(mode=mode): - self.plot.setComplexMode(mode) - self.qWait(100) - - # Test origin and scale API - self.plot.setScale((2, 1)) - self.qWait(100) - self.plot.setOrigin((1, 1)) - self.qWait(100) - - # Test no data - self.plot.setData(numpy.zeros((0, 0), dtype=numpy.complex64)) - self.qWait(100) - - # Test float data - self.plot.setData(numpy.arange(100, dtype=numpy.float64).reshape(10, 10)) - self.qWait(100) - - -def suite(): - test_suite = unittest.TestSuite() - test_suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase( - TestComplexImageView)) - return test_suite - - -if __name__ == '__main__': - unittest.main(defaultTest='suite') diff --git a/silx/gui/plot/test/testCurvesROIWidget.py b/silx/gui/plot/test/testCurvesROIWidget.py deleted file mode 100644 index 6a0ab8c..0000000 --- a/silx/gui/plot/test/testCurvesROIWidget.py +++ /dev/null @@ -1,469 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# -# 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 -# 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 CurvesROIWidget""" - -__authors__ = ["T. Vincent", "P. Knobel", "H. Payno"] -__license__ = "MIT" -__date__ = "16/11/2017" - - -import logging -import os.path -import unittest -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 -from silx.gui.plot import PlotWindow, CurvesROIWidget -from silx.gui.plot.CurvesROIWidget import ROITable -from silx.gui.utils.testutils import getQToolButtonFromAction -from silx.gui.plot.PlotInteraction import ItemsInteraction - -_logger = logging.getLogger(__name__) - - -class TestCurvesROIWidget(TestCaseQt): - """Basic test for CurvesROIWidget""" - - def setUp(self): - super(TestCurvesROIWidget, self).setUp() - self.plot = PlotWindow() - self.plot.show() - self.qWaitForWindowExposed(self.plot) - - self.widget = self.plot.getCurvesRoiDockWidget() - - self.widget.show() - self.qWaitForWindowExposed(self.widget) - - def tearDown(self): - self.plot.setAttribute(qt.Qt.WA_DeleteOnClose) - self.plot.close() - del self.plot - - self.widget.setAttribute(qt.Qt.WA_DeleteOnClose) - self.widget.close() - del self.widget - - super(TestCurvesROIWidget, self).tearDown() - - def testDummyAPI(self): - """Simple test of the getRois and setRois API""" - roi_neg = CurvesROIWidget.ROI(name='negative', fromdata=-20, - todata=-10, type_='X') - roi_pos = CurvesROIWidget.ROI(name='positive', fromdata=10, - todata=20, type_='X') - - self.widget.roiWidget.setRois((roi_pos, roi_neg)) - - rois_defs = self.widget.roiWidget.getRois() - self.widget.roiWidget.setRois(rois=rois_defs) - - def testWithCurves(self): - """Plot with curves: test all ROI widget buttons""" - for offset in range(2): - self.plot.addCurve(numpy.arange(1000), - offset + numpy.random.random(1000), - legend=str(offset)) - - # Add two ROI - self.mouseClick(self.widget.roiWidget.addButton, qt.Qt.LeftButton) - self.qWait(200) - self.mouseClick(self.widget.roiWidget.addButton, qt.Qt.LeftButton) - self.qWait(200) - - # Change active curve - self.plot.setActiveCurve(str(1)) - - # Delete a ROI - self.mouseClick(self.widget.roiWidget.delButton, qt.Qt.LeftButton) - self.qWait(200) - - with temp_dir() as tmpDir: - self.tmpFile = os.path.join(tmpDir, 'test.ini') - - # Save ROIs - self.widget.roiWidget.save(self.tmpFile) - self.assertTrue(os.path.isfile(self.tmpFile)) - 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.assertEqual(len(rois), 1) - roiID = list(rois.keys())[0] - self.assertEqual(rois[roiID].getName(), 'ICR') - - # Load ROIs - self.widget.roiWidget.load(self.tmpFile) - self.assertEqual(len(self.widget.getRois()), 2) - - del self.tmpFile - - def testMiddleMarker(self): - """Test with middle marker enabled""" - self.widget.roiWidget.roiTable.setMiddleROIMarkerFlag(True) - - # Add a ROI - self.mouseClick(self.widget.roiWidget.addButton, qt.Qt.LeftButton) - - for roiID in self.widget.roiWidget.roiTable._markersHandler._roiMarkerHandlers: - handler = self.widget.roiWidget.roiTable._markersHandler._roiMarkerHandlers[roiID] - assert handler.getMarker('min') - xleftMarker = handler.getMarker('min').getXPosition() - xMiddleMarker = handler.getMarker('middle').getXPosition() - xRightMarker = handler.getMarker('max').getXPosition() - thValue = xleftMarker + (xRightMarker - xleftMarker) / 2. - self.assertAlmostEqual(xMiddleMarker, thValue) - - def testAreaCalculation(self): - """Test result of area calculation""" - x = numpy.arange(100.) - y = numpy.arange(100.) - - # Add two curves - self.plot.addCurve(x, y, legend="positive") - self.plot.addCurve(-x, y, legend="negative") - - # Make sure there is an active curve and it is the positive one - self.plot.setActiveCurve("positive") - - # Add two ROIs - roi_neg = CurvesROIWidget.ROI(name='negative', fromdata=-20, - todata=-10, type_='X') - roi_pos = CurvesROIWidget.ROI(name='positive', fromdata=10, - todata=20, type_='X') - - self.widget.roiWidget.setRois((roi_pos, roi_neg)) - - posCurve = self.plot.getCurve('positive') - negCurve = self.plot.getCurve('negative') - - self.assertEqual(roi_pos.computeRawAndNetArea(posCurve), - (numpy.trapz(y=[10, 20], x=[10, 20]), - 0.0)) - self.assertEqual(roi_pos.computeRawAndNetArea(negCurve), - (0.0, 0.0)) - self.assertEqual(roi_neg.computeRawAndNetArea(posCurve), - ((0.0), 0.0)) - self.assertEqual(roi_neg.computeRawAndNetArea(negCurve), - ((-150.0), 0.0)) - - def testCountsCalculation(self): - """Test result of count calculation""" - x = numpy.arange(100.) - y = numpy.arange(100.) - - # Add two curves - self.plot.addCurve(x, y, legend="positive") - self.plot.addCurve(-x, y, legend="negative") - - # Make sure there is an active curve and it is the positive one - self.plot.setActiveCurve("positive") - - # Add two ROIs - roi_neg = CurvesROIWidget.ROI(name='negative', fromdata=-20, - todata=-10, type_='X') - roi_pos = CurvesROIWidget.ROI(name='positive', fromdata=10, - todata=20, type_='X') - - self.widget.roiWidget.setRois((roi_pos, roi_neg)) - - posCurve = self.plot.getCurve('positive') - negCurve = self.plot.getCurve('negative') - - self.assertEqual(roi_pos.computeRawAndNetCounts(posCurve), - (y[10:21].sum(), 0.0)) - self.assertEqual(roi_pos.computeRawAndNetCounts(negCurve), - (0.0, 0.0)) - self.assertEqual(roi_neg.computeRawAndNetCounts(posCurve), - ((0.0), 0.0)) - self.assertEqual(roi_neg.computeRawAndNetCounts(negCurve), - (y[10:21].sum(), 0.0)) - - def testDeferedInit(self): - """Test behavior of the deferedInit""" - x = numpy.arange(100.) - y = numpy.arange(100.) - self.plot.addCurve(x=x, y=y, legend="name", replace="True") - roisDefs = OrderedDict([ - ["range1", - OrderedDict([["from", 20], ["to", 200], ["type", "energy"]])], - ["range2", - OrderedDict([["from", 300], ["to", 500], ["type", "energy"]])] - ]) - - roiWidget = self.plot.getCurvesRoiDockWidget().roiWidget - self.plot.getCurvesRoiDockWidget().setRois(roisDefs) - self.assertEqual(len(roiWidget.getRois()), len(roisDefs)) - self.plot.getCurvesRoiDockWidget().setVisible(True) - 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.assertEqual(roi.toDict(), roiDict) - - def testShowAllROI(self): - """Test the show allROI action""" - x = numpy.arange(100.) - y = numpy.arange(100.) - self.plot.addCurve(x=x, y=y, legend="name", replace="True") - - roisDefsDict = { - "range1": {"from": 20, "to": 200,"type": "energy"}, - "range2": {"from": 300, "to": 500, "type": "energy"} - } - - roisDefsObj = ( - CurvesROIWidget.ROI(name='range3', fromdata=20, todata=200, - type_='energy'), - CurvesROIWidget.ROI(name='range4', fromdata=300, todata=500, - type_='energy') - ) - self.widget.roiWidget.showAllMarkers(True) - roiWidget = self.plot.getCurvesRoiDockWidget().roiWidget - roiWidget.setRois(roisDefsDict) - 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.assertEqual(len(ICRROI), 2) - - roiWidget.showAllMarkers(False) - ICRROI = markersHandler.getVisibleRois() - self.assertEqual(len(ICRROI), 1) - - roiWidget.setRois(roisDefsObj) - self.qapp.processEvents() - 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.assertEqual(len(ICRROI), 2) - - roiWidget.showAllMarkers(False) - ICRROI = markersHandler.getVisibleRois() - self.assertEqual(len(ICRROI), 1) - - def testRoiEdition(self): - """Make sure if the ROI object is edited the ROITable will be updated - """ - roi = CurvesROIWidget.ROI(name='linear', fromdata=0, todata=5) - self.widget.roiWidget.setRois((roi, )) - - x = (0, 1, 1, 2, 2, 3) - y = (1, 1, 2, 2, 1, 1) - self.plot.addCurve(x=x, y=y, legend='linearCurve') - self.plot.setActiveCurve(legend='linearCurve') - self.widget.calculateROIs() - - roiTable = self.widget.roiWidget.roiTable - indexesColumns = CurvesROIWidget.ROITable.COLUMNS_INDEX - itemRawCounts = roiTable.item(0, indexesColumns['Raw Counts']) - itemNetCounts = roiTable.item(0, indexesColumns['Net Counts']) - - self.assertTrue(itemRawCounts.text() == '8.0') - self.assertTrue(itemNetCounts.text() == '2.0') - - itemRawArea = roiTable.item(0, indexesColumns['Raw Area']) - itemNetArea = roiTable.item(0, indexesColumns['Net Area']) - - self.assertTrue(itemRawArea.text() == '4.0') - self.assertTrue(itemNetArea.text() == '1.0') - - roi.setTo(2) - itemRawArea = roiTable.item(0, indexesColumns['Raw Area']) - self.assertTrue(itemRawArea.text() == '3.0') - roi.setFrom(1) - itemRawArea = roiTable.item(0, indexesColumns['Raw Area']) - self.assertTrue(itemRawArea.text() == '2.0') - - def testRemoveActiveROI(self): - """Test widget behavior when removing the active ROI""" - roi = CurvesROIWidget.ROI(name='linear', fromdata=0, todata=5) - self.widget.roiWidget.setRois((roi,)) - - self.widget.roiWidget.roiTable.setActiveRoi(None) - self.assertEqual(len(self.widget.roiWidget.roiTable.selectedItems()), 0) - self.widget.roiWidget.setRois((roi,)) - self.plot.setActiveCurve(legend='linearCurve') - self.widget.calculateROIs() - - def testEmitCurrentROI(self): - """Test behavior of the CurvesROIWidget.sigROISignal""" - roi = CurvesROIWidget.ROI(name='linear', fromdata=0, todata=5) - self.widget.roiWidget.setRois((roi,)) - signalListener = SignalListener() - self.widget.roiWidget.sigROISignal.connect(signalListener.partial()) - self.widget.show() - self.qapp.processEvents() - self.assertEqual(signalListener.callCount(), 0) - self.assertIs(self.widget.roiWidget.roiTable.activeRoi, roi) - roi.setFrom(0.0) - self.qapp.processEvents() - self.assertEqual(signalListener.callCount(), 0) - roi.setFrom(0.3) - self.qapp.processEvents() - self.assertEqual(signalListener.callCount(), 1) - - -class TestRoiWidgetSignals(TestCaseQt): - """Test Signals emitted by the RoiWidgetSignals""" - - def setUp(self): - self.plot = Plot1D() - x = range(20) - y = range(20) - self.plot.addCurve(x, y, legend='curve0') - self.listener = SignalListener() - self.curves_roi_widget = self.plot.getCurvesRoiWidget() - self.curves_roi_widget.sigROISignal.connect(self.listener) - assert self.curves_roi_widget.isVisible() is False - assert self.listener.callCount() == 0 - self.plot.show() - self.qWaitForWindowExposed(self.plot) - - toolButton = getQToolButtonFromAction(self.plot.getRoiAction()) - self.mouseClick(widget=toolButton, button=qt.Qt.LeftButton) - - self.curves_roi_widget.show() - self.qWaitForWindowExposed(self.curves_roi_widget) - - def tearDown(self): - self.plot = None - - def testSigROISignalAddRmRois(self): - """Test SigROISignal when adding and removing ROIS""" - self.assertEqual(self.listener.callCount(), 1) - self.listener.clear() - - roi1 = CurvesROIWidget.ROI(name='linear', fromdata=0, todata=5) - self.curves_roi_widget.roiTable.registerROI(roi1) - self.assertEqual(self.listener.callCount(), 1) - self.assertTrue(self.listener.arguments()[0][0]['current'] == 'linear') - self.listener.clear() - - roi2 = CurvesROIWidget.ROI(name='linear2', fromdata=0, todata=5) - self.curves_roi_widget.roiTable.registerROI(roi2) - self.assertEqual(self.listener.callCount(), 1) - self.assertTrue(self.listener.arguments()[0][0]['current'] == 'linear2') - self.listener.clear() - - self.curves_roi_widget.roiTable.removeROI(roi2) - self.assertEqual(self.listener.callCount(), 1) - self.assertTrue(self.curves_roi_widget.roiTable.activeRoi == roi1) - self.assertTrue(self.listener.arguments()[0][0]['current'] == 'linear') - self.listener.clear() - - self.curves_roi_widget.roiTable.deleteActiveRoi() - self.assertEqual(self.listener.callCount(), 1) - self.assertTrue(self.curves_roi_widget.roiTable.activeRoi is None) - self.assertTrue(self.listener.arguments()[0][0]['current'] is None) - self.listener.clear() - - self.curves_roi_widget.roiTable.registerROI(roi1) - self.assertEqual(self.listener.callCount(), 1) - self.assertTrue(self.listener.arguments()[0][0]['current'] == 'linear') - self.assertTrue(self.curves_roi_widget.roiTable.activeRoi == roi1) - self.listener.clear() - self.qapp.processEvents() - - self.curves_roi_widget.roiTable.removeROI(roi1) - self.qapp.processEvents() - self.assertEqual(self.listener.callCount(), 1) - self.assertTrue(self.listener.arguments()[0][0]['current'] == 'ICR') - self.listener.clear() - - def testSigROISignalModifyROI(self): - """Test SigROISignal when modifying it""" - self.curves_roi_widget.roiTable.setMiddleROIMarkerFlag(True) - roi1 = CurvesROIWidget.ROI(name='linear', fromdata=2, todata=5) - self.curves_roi_widget.roiTable.registerROI(roi1) - self.curves_roi_widget.roiTable.setActiveRoi(roi1) - - # test modify the roi2 object - self.listener.clear() - roi1.setFrom(0.56) - self.assertEqual(self.listener.callCount(), 1) - self.listener.clear() - roi1.setTo(2.56) - self.assertEqual(self.listener.callCount(), 1) - self.listener.clear() - roi1.setName('linear2') - self.assertEqual(self.listener.callCount(), 1) - self.listener.clear() - roi1.setType('new type') - self.assertEqual(self.listener.callCount(), 1) - - # modify roi limits (from the gui) - roi_marker_handler = self.curves_roi_widget.roiTable._markersHandler.getMarkerHandler(roi1.getID()) - for marker_type in ('min', 'max', 'middle'): - with self.subTest(marker_type=marker_type): - self.listener.clear() - marker = roi_marker_handler.getMarker(marker_type) - self.qapp.processEvents() - items_interaction = ItemsInteraction(plot=self.plot) - x_pix, y_pix = self.plot.dataToPixel(marker.getXPosition(), 1) - items_interaction.beginDrag(x_pix, y_pix) - self.qapp.processEvents() - items_interaction.endDrag(x_pix+10, y_pix) - self.qapp.processEvents() - self.assertEqual(self.listener.callCount(), 1) - - def testSetActiveCurve(self): - """Test sigRoiSignal when set an active curve""" - roi1 = CurvesROIWidget.ROI(name='linear', fromdata=2, todata=5) - self.curves_roi_widget.roiTable.registerROI(roi1) - self.curves_roi_widget.roiTable.setActiveRoi(roi1) - self.listener.clear() - self.plot.setActiveCurve('curve0') - self.assertEqual(self.listener.callCount(), 0) - - -def suite(): - test_suite = unittest.TestSuite() - for TestClass in (TestCurvesROIWidget,): - test_suite.addTest( - unittest.defaultTestLoader.loadTestsFromTestCase(TestClass)) - return test_suite - - -if __name__ == '__main__': - unittest.main(defaultTest='suite') diff --git a/silx/gui/plot/test/testImageStack.py b/silx/gui/plot/test/testImageStack.py deleted file mode 100644 index 9c21469..0000000 --- a/silx/gui/plot/test/testImageStack.py +++ /dev/null @@ -1,197 +0,0 @@ -# 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/testImageView.py b/silx/gui/plot/test/testImageView.py deleted file mode 100644 index 3c8d84c..0000000 --- a/silx/gui/plot/test/testImageView.py +++ /dev/null @@ -1,136 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# -# Copyright (c) 2017 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 PlotWindow""" - -__authors__ = ["T. Vincent"] -__license__ = "MIT" -__date__ = "24/04/2018" - - -import unittest -import numpy - -from silx.gui import qt -from silx.gui.utils.testutils import TestCaseQt - -from silx.gui.plot import ImageView -from silx.gui.colors import Colormap - - -class TestImageView(TestCaseQt): - """Tests of ImageView widget.""" - - def setUp(self): - super(TestImageView, self).setUp() - self.plot = ImageView() - self.plot.show() - self.qWaitForWindowExposed(self.plot) - - def tearDown(self): - self.qapp.processEvents() - self.plot.setAttribute(qt.Qt.WA_DeleteOnClose) - self.plot.close() - del self.plot - self.qapp.processEvents() - super(TestImageView, self).tearDown() - - def testSetImage(self): - """Test setImage""" - image = numpy.arange(100).reshape(10, 10) - - self.plot.setImage(image, reset=True) - self.qWait(100) - self.assertEqual(self.plot.getXAxis().getLimits(), (0, 10)) - self.assertEqual(self.plot.getYAxis().getLimits(), (0, 10)) - - # With reset=False - self.plot.setImage(image[::2, ::2], reset=False) - self.qWait(100) - self.assertEqual(self.plot.getXAxis().getLimits(), (0, 10)) - self.assertEqual(self.plot.getYAxis().getLimits(), (0, 10)) - - self.plot.setImage(image, origin=(10, 20), scale=(2, 4), reset=False) - self.qWait(100) - self.assertEqual(self.plot.getXAxis().getLimits(), (0, 10)) - self.assertEqual(self.plot.getYAxis().getLimits(), (0, 10)) - - # With reset=True - self.plot.setImage(image, origin=(1, 2), scale=(1, 0.5), reset=True) - self.qWait(100) - self.assertEqual(self.plot.getXAxis().getLimits(), (1, 11)) - self.assertEqual(self.plot.getYAxis().getLimits(), (2, 7)) - - self.plot.setImage(image[::2, ::2], reset=True) - self.qWait(100) - self.assertEqual(self.plot.getXAxis().getLimits(), (0, 5)) - self.assertEqual(self.plot.getYAxis().getLimits(), (0, 5)) - - def testColormap(self): - """Test get|setColormap""" - image = numpy.arange(100).reshape(10, 10) - self.plot.setImage(image) - - # Colormap as dict - self.plot.setColormap({'name': 'viridis', - 'normalization': 'log', - 'autoscale': False, - 'vmin': 0, - 'vmax': 1}) - colormap = self.plot.getColormap() - self.assertEqual(colormap.getName(), 'viridis') - self.assertEqual(colormap.getNormalization(), 'log') - self.assertEqual(colormap.getVMin(), 0) - self.assertEqual(colormap.getVMax(), 1) - - # Colormap as keyword arguments - self.plot.setColormap(colormap='magma', - normalization='linear', - autoscale=True, - vmin=1, - vmax=2) - self.assertEqual(colormap.getName(), 'magma') - self.assertEqual(colormap.getNormalization(), 'linear') - self.assertEqual(colormap.getVMin(), None) - self.assertEqual(colormap.getVMax(), None) - - # Update colormap with keyword argument - self.plot.setColormap(normalization='log') - self.assertEqual(colormap.getNormalization(), 'log') - - # Colormap as Colormap object - cmap = Colormap() - self.plot.setColormap(cmap) - self.assertIs(self.plot.getColormap(), cmap) - - -def suite(): - test_suite = unittest.TestSuite() - test_suite.addTest( - unittest.defaultTestLoader.loadTestsFromTestCase(TestImageView)) - 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 deleted file mode 100644 index a47337e..0000000 --- a/silx/gui/plot/test/testInteraction.py +++ /dev/null @@ -1,89 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# -# 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 -# 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. -# -# ###########################################################################*/ -"""Tests from interaction state machines""" - -__authors__ = ["T. Vincent"] -__license__ = "MIT" -__date__ = "18/02/2016" - - -import unittest - -from silx.gui.plot import Interaction - - -class TestInteraction(unittest.TestCase): - def testClickOrDrag(self): - """Minimalistic test for click or drag state machine.""" - events = [] - - class TestClickOrDrag(Interaction.ClickOrDrag): - def click(self, x, y, btn): - events.append(('click', x, y, btn)) - - def beginDrag(self, x, y, btn): - events.append(('beginDrag', x, y, btn)) - - def drag(self, x, y, btn): - events.append(('drag', x, y, btn)) - - def endDrag(self, start, end, btn): - events.append(('endDrag', start, end, btn)) - - clickOrDrag = TestClickOrDrag() - - # click - clickOrDrag.handleEvent('press', 10, 10, Interaction.LEFT_BTN) - self.assertEqual(len(events), 0) - - clickOrDrag.handleEvent('release', 10, 10, Interaction.LEFT_BTN) - self.assertEqual(len(events), 1) - self.assertEqual(events[0], ('click', 10, 10, Interaction.LEFT_BTN)) - - # drag - events = [] - clickOrDrag.handleEvent('press', 10, 10, Interaction.LEFT_BTN) - 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, 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, 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), Interaction.LEFT_BTN)) - - -def suite(): - test_suite = unittest.TestSuite() - test_suite.addTest( - unittest.defaultTestLoader.loadTestsFromTestCase(TestInteraction)) - return test_suite - - -if __name__ == '__main__': - unittest.main(defaultTest='suite') diff --git a/silx/gui/plot/test/testItem.py b/silx/gui/plot/test/testItem.py deleted file mode 100644 index 8dacdea..0000000 --- a/silx/gui/plot/test/testItem.py +++ /dev/null @@ -1,340 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# -# Copyright (c) 2017-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. -# -# ###########################################################################*/ -"""Tests for PlotWidget items.""" - -__authors__ = ["T. Vincent"] -__license__ = "MIT" -__date__ = "01/09/2017" - - -import unittest - -import numpy - -from silx.gui.utils.testutils import SignalListener -from silx.gui.plot.items import ItemChangedType -from silx.gui.plot import items -from .utils import PlotWidgetTestCase - - -class TestSigItemChangedSignal(PlotWidgetTestCase): - """Test item's sigItemChanged signal""" - - def testCurveChanged(self): - """Test sigItemChanged for curve""" - self.plot.addCurve(numpy.arange(10), numpy.arange(10), legend='test') - curve = self.plot.getCurve('test') - - listener = SignalListener() - curve.sigItemChanged.connect(listener) - - # Test for signal in Item class - curve.setVisible(False) - curve.setVisible(True) - curve.setZValue(100) - - # Test for signals in PointsBase class - curve.setData(numpy.arange(100), numpy.arange(100)) - - # SymbolMixIn - curve.setSymbol('Circle') - curve.setSymbol('d') - curve.setSymbolSize(20) - - # AlphaMixIn - curve.setAlpha(0.5) - - # Test for signals in Curve class - # ColorMixIn - curve.setColor('yellow') - # YAxisMixIn - curve.setYAxis('right') - # FillMixIn - curve.setFill(True) - # LineMixIn - curve.setLineStyle(':') - curve.setLineStyle(':') # Not sending event - curve.setLineWidth(2) - - self.assertEqual(listener.arguments(argumentIndex=0), - [ItemChangedType.VISIBLE, - ItemChangedType.VISIBLE, - ItemChangedType.ZVALUE, - ItemChangedType.DATA, - ItemChangedType.SYMBOL, - ItemChangedType.SYMBOL, - ItemChangedType.SYMBOL_SIZE, - ItemChangedType.ALPHA, - ItemChangedType.COLOR, - ItemChangedType.YAXIS, - ItemChangedType.FILL, - ItemChangedType.LINE_STYLE, - ItemChangedType.LINE_WIDTH]) - - def testHistogramChanged(self): - """Test sigItemChanged for Histogram""" - self.plot.addHistogram( - numpy.arange(10), edges=numpy.arange(11), legend='test') - histogram = self.plot.getHistogram('test') - listener = SignalListener() - histogram.sigItemChanged.connect(listener) - - # Test signals in Histogram class - histogram.setData(numpy.zeros(10), numpy.arange(11)) - - self.assertEqual(listener.arguments(argumentIndex=0), - [ItemChangedType.DATA]) - - def testImageDataChanged(self): - """Test sigItemChanged for ImageData""" - self.plot.addImage(numpy.arange(100).reshape(10, 10), legend='test') - image = self.plot.getImage('test') - - listener = SignalListener() - image.sigItemChanged.connect(listener) - - # ColormapMixIn - colormap = self.plot.getDefaultColormap().copy() - image.setColormap(colormap) - image.getColormap().setName('viridis') - - # Test of signals in ImageBase class - image.setOrigin(10) - image.setScale(2) - - # Test of signals in ImageData class - image.setData(numpy.ones((10, 10))) - - self.assertEqual(listener.arguments(argumentIndex=0), - [ItemChangedType.COLORMAP, - ItemChangedType.COLORMAP, - ItemChangedType.POSITION, - ItemChangedType.SCALE, - ItemChangedType.COLORMAP, - ItemChangedType.DATA]) - - def testImageRgbaChanged(self): - """Test sigItemChanged for ImageRgba""" - self.plot.addImage(numpy.ones((10, 10, 3)), legend='rgb') - image = self.plot.getImage('rgb') - - listener = SignalListener() - image.sigItemChanged.connect(listener) - - # Test of signals in ImageRgba class - image.setData(numpy.zeros((10, 10, 3))) - - self.assertEqual(listener.arguments(argumentIndex=0), - [ItemChangedType.DATA]) - - def testMarkerChanged(self): - """Test sigItemChanged for markers""" - self.plot.addMarker(10, 20, legend='test') - marker = self.plot._getMarker('test') - - listener = SignalListener() - marker.sigItemChanged.connect(listener) - - # Test signals in _BaseMarker - marker.setPosition(10, 10) - marker.setPosition(10, 10) # Not sending event - marker.setText('toto') - self.assertEqual(listener.arguments(argumentIndex=0), - [ItemChangedType.POSITION, - ItemChangedType.TEXT]) - - # XMarker - self.plot.addXMarker(10, legend='x') - marker = self.plot._getMarker('x') - - listener = SignalListener() - marker.sigItemChanged.connect(listener) - marker.setPosition(20, 20) - self.assertEqual(listener.arguments(argumentIndex=0), - [ItemChangedType.POSITION]) - - # YMarker - self.plot.addYMarker(10, legend='x') - marker = self.plot._getMarker('x') - - listener = SignalListener() - marker.sigItemChanged.connect(listener) - marker.setPosition(20, 20) - self.assertEqual(listener.arguments(argumentIndex=0), - [ItemChangedType.POSITION]) - - def testScatterChanged(self): - """Test sigItemChanged for scatter""" - data = numpy.arange(10) - self.plot.addScatter(data, data, data, legend='test') - scatter = self.plot.getScatter('test') - - listener = SignalListener() - scatter.sigItemChanged.connect(listener) - - # ColormapMixIn - scatter.getColormap().setName('viridis') - - # Test of signals in Scatter class - scatter.setData((0, 1, 2), (1, 0, 2), (0, 1, 2)) - - # Visualization mode changed - scatter.setVisualization(scatter.Visualization.SOLID) - - 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.addShape(data, data, legend='test', shape='rectangle') - shape = self.plot._getItem(kind='item', legend='test') - - listener = SignalListener() - shape.sigItemChanged.connect(listener) - - shape.setOverlay(True) - shape.setPoints(((2., 2.), (3., 3.))) - - self.assertEqual(listener.arguments(), - [(ItemChangedType.OVERLAY,), - (ItemChangedType.DATA,)]) - - -class TestSymbol(PlotWidgetTestCase): - """Test item's symbol """ - - def test(self): - """Test sigItemChanged for curve""" - self.plot.addCurve(numpy.arange(10), numpy.arange(10), legend='test') - curve = self.plot.getCurve('test') - - # SymbolMixIn - curve.setSymbol('o') - name = curve.getSymbolName() - self.assertEqual('Circle', name) - - name = curve.getSymbolName('d') - self.assertEqual('Diamond', name) - - -class TestVisibleExtent(PlotWidgetTestCase): - """Test item's visible extent feature""" - - def testGetVisibleBounds(self): - """Test Item.getVisibleBounds""" - - # Create test items (with a bounding box of x: [1,3], y: [0,2]) - curve = items.Curve() - curve.setData((1, 2, 3), (0, 1, 2)) - - histogram = items.Histogram() - histogram.setData((0, 1, 2), (1, 5/3, 7/3, 3)) - - image = items.ImageData() - image.setOrigin((1, 0)) - image.setData(numpy.arange(4).reshape(2, 2)) - - scatter = items.Scatter() - scatter.setData((1, 2, 3), (0, 1, 2), (1, 2, 3)) - - bbox = items.BoundingRect() - bbox.setBounds((1, 3, 0, 2)) - - xaxis, yaxis = self.plot.getXAxis(), self.plot.getYAxis() - for item in (curve, histogram, image, scatter, bbox): - with self.subTest(item=item): - xaxis.setLimits(0, 100) - yaxis.setLimits(0, 100) - self.plot.addItem(item) - self.assertEqual(item.getVisibleBounds(), (1., 3., 0., 2.)) - - xaxis.setLimits(0.5, 2.5) - self.assertEqual(item.getVisibleBounds(), (1, 2.5, 0., 2.)) - - yaxis.setLimits(0.5, 1.5) - self.assertEqual(item.getVisibleBounds(), (1, 2.5, 0.5, 1.5)) - - item.setVisible(False) - self.assertIsNone(item.getVisibleBounds()) - - self.plot.clear() - - def testVisibleExtentTracking(self): - """Test Item's visible extent tracking""" - image = items.ImageData() - image.setData(numpy.arange(6).reshape(2, 3)) - - listener = SignalListener() - image._sigVisibleBoundsChanged.connect(listener) - image._setVisibleBoundsTracking(True) - self.assertTrue(image._isVisibleBoundsTracking()) - - self.plot.addItem(image) - self.assertEqual(listener.callCount(), 1) - - self.plot.getXAxis().setLimits(0, 1) - self.assertEqual(listener.callCount(), 2) - - self.plot.hide() - self.qapp.processEvents() - # No event here - self.assertEqual(listener.callCount(), 2) - - self.plot.getXAxis().setLimits(1, 2) - # No event since PlotWidget is hidden, delayed to PlotWidget show - self.assertEqual(listener.callCount(), 2) - - self.plot.show() - self.qapp.processEvents() - # Receives delayed event now - self.assertEqual(listener.callCount(), 3) - - image.setOrigin((-1, -1)) - self.assertEqual(listener.callCount(), 4) - - image.setVisible(False) - image.setOrigin((0, 0)) - # No event since item is not visible - self.assertEqual(listener.callCount(), 4) - - image.setVisible(True) - # Receives delayed event now - self.assertEqual(listener.callCount(), 5) - - -def suite(): - test_suite = unittest.TestSuite() - loadTests = unittest.defaultTestLoader.loadTestsFromTestCase - for klass in (TestSigItemChangedSignal, TestSymbol, TestVisibleExtent): - test_suite.addTest(loadTests(klass)) - return test_suite - - -if __name__ == '__main__': - unittest.main(defaultTest='suite') diff --git a/silx/gui/plot/test/testLegendSelector.py b/silx/gui/plot/test/testLegendSelector.py deleted file mode 100644 index de5ffde..0000000 --- a/silx/gui/plot/test/testLegendSelector.py +++ /dev/null @@ -1,142 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# -# Copyright (c) 2004-2016 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 PlotWidget""" - -__authors__ = ["T. Rueter", "T. Vincent"] -__license__ = "MIT" -__date__ = "15/05/2017" - - -import logging -import unittest - -from silx.gui import qt -from silx.gui.utils.testutils import TestCaseQt -from silx.gui.plot import LegendSelector - - -_logger = logging.getLogger(__name__) - - -class TestLegendSelector(TestCaseQt): - """Basic test for LegendSelector""" - - def testLegendSelector(self): - """Test copied from __main__ of LegendSelector in PyMca""" - class Notifier(qt.QObject): - def __init__(self): - qt.QObject.__init__(self) - self.chk = True - - def signalReceived(self, **kw): - obj = self.sender() - _logger.info('NOTIFIER -- signal received\n\tsender: %s', - str(obj)) - - notifier = Notifier() - - legends = ['Legend0', - 'Legend1', - 'Long Legend 2', - 'Foo Legend 3', - 'Even Longer Legend 4', - 'Short Leg 5', - 'Dot symbol 6', - 'Comma symbol 7'] - colors = [qt.Qt.darkRed, qt.Qt.green, qt.Qt.yellow, qt.Qt.darkCyan, - qt.Qt.blue, qt.Qt.darkBlue, qt.Qt.red, qt.Qt.darkYellow] - symbols = ['o', 't', '+', 'x', 's', 'd', '.', ','] - - win = LegendSelector.LegendListView() - # win = LegendListContextMenu() - # win = qt.QWidget() - # layout = qt.QVBoxLayout() - # layout.setContentsMargins(0,0,0,0) - llist = [] - - for _idx, (l, c, s) in enumerate(zip(legends, colors, symbols)): - ddict = { - 'color': qt.QColor(c), - 'linewidth': 4, - 'symbol': s, - } - legend = l - llist.append((legend, ddict)) - # item = qt.QListWidgetItem(win) - # legendWidget = LegendListItemWidget(l) - # legendWidget.icon.setSymbol(s) - # legendWidget.icon.setColor(qt.QColor(c)) - # layout.addWidget(legendWidget) - # win.setItemWidget(item, legendWidget) - - # win = LegendListItemWidget('Some Legend 1') - # print(llist) - model = LegendSelector.LegendModel(legendList=llist) - win.setModel(model) - win.setSelectionModel(qt.QItemSelectionModel(model)) - win.setContextMenu() - # print('Edit triggers: %d'%win.editTriggers()) - - # win = LegendListWidget(None, legends) - # win[0].updateItem(ddict) - # win.setLayout(layout) - win.sigLegendSignal.connect(notifier.signalReceived) - win.show() - - win.clear() - win.setLegendList(llist) - - self.qWaitForWindowExposed(win) - - -class TestRenameCurveDialog(TestCaseQt): - """Basic test for RenameCurveDialog""" - - def testDialog(self): - """Create dialog, change name and press OK""" - self.dialog = LegendSelector.RenameCurveDialog( - None, 'curve1', ['curve1', 'curve2', 'curve3']) - self.dialog.open() - self.qWaitForWindowExposed(self.dialog) - self.keyClicks(self.dialog.lineEdit, 'changed') - self.mouseClick(self.dialog.okButton, qt.Qt.LeftButton) - self.qapp.processEvents() - ret = self.dialog.result() - self.assertEqual(ret, qt.QDialog.Accepted) - newName = self.dialog.getText() - self.assertEqual(newName, 'curve1changed') - del self.dialog - - -def suite(): - test_suite = unittest.TestSuite() - for TestClass in (TestLegendSelector, TestRenameCurveDialog): - test_suite.addTest( - unittest.defaultTestLoader.loadTestsFromTestCase(TestClass)) - return test_suite - - -if __name__ == '__main__': - unittest.main(defaultTest='suite') diff --git a/silx/gui/plot/test/testLimitConstraints.py b/silx/gui/plot/test/testLimitConstraints.py deleted file mode 100644 index 5e7e0b1..0000000 --- a/silx/gui/plot/test/testLimitConstraints.py +++ /dev/null @@ -1,125 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# -# Copyright (c) 2016-2018 European Synchrotron Radiation Facility -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# 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. -# -# ###########################################################################*/ -"""Test setLimitConstaints on the PlotWidget""" - -__authors__ = ["V. Valls"] -__license__ = "MIT" -__date__ = "30/08/2017" - - -import unittest -from silx.gui.plot import PlotWidget - - -class TestLimitConstaints(unittest.TestCase): - """Tests setLimitConstaints class""" - - def setUp(self): - self.plot = PlotWidget() - - def tearDown(self): - self.plot = None - - def testApi(self): - """Test availability of the API""" - self.plot.getXAxis().setLimitsConstraints(minPos=1, maxPos=10) - self.plot.getXAxis().setRangeConstraints(minRange=1, maxRange=1) - self.plot.getYAxis().setLimitsConstraints(minPos=1, maxPos=10) - self.plot.getYAxis().setRangeConstraints(minRange=1, maxRange=1) - - def testXMinMax(self): - """Test limit constains on x-axis""" - self.plot.getXAxis().setLimitsConstraints(minPos=0, maxPos=100) - self.plot.setLimits(xmin=-1, xmax=101, ymin=-1, ymax=101) - self.assertEqual(self.plot.getXAxis().getLimits(), (0, 100)) - self.assertEqual(self.plot.getYAxis().getLimits(), (-1, 101)) - - def testYMinMax(self): - """Test limit constains on y-axis""" - self.plot.getYAxis().setLimitsConstraints(minPos=0, maxPos=100) - self.plot.setLimits(xmin=-1, xmax=101, ymin=-1, ymax=101) - self.assertEqual(self.plot.getXAxis().getLimits(), (-1, 101)) - self.assertEqual(self.plot.getYAxis().getLimits(), (0, 100)) - - def testMinXRange(self): - """Test min range constains on x-axis""" - self.plot.getXAxis().setRangeConstraints(minRange=100) - self.plot.setLimits(xmin=1, xmax=99, ymin=1, ymax=99) - limits = self.plot.getXAxis().getLimits() - self.assertEqual(limits[1] - limits[0], 100) - limits = self.plot.getYAxis().getLimits() - self.assertNotEqual(limits[1] - limits[0], 100) - - def testMaxXRange(self): - """Test max range constains on x-axis""" - self.plot.getXAxis().setRangeConstraints(maxRange=100) - self.plot.setLimits(xmin=-1, xmax=101, ymin=-1, ymax=101) - limits = self.plot.getXAxis().getLimits() - self.assertEqual(limits[1] - limits[0], 100) - limits = self.plot.getYAxis().getLimits() - self.assertNotEqual(limits[1] - limits[0], 100) - - def testMinYRange(self): - """Test min range constains on y-axis""" - self.plot.getYAxis().setRangeConstraints(minRange=100) - self.plot.setLimits(xmin=1, xmax=99, ymin=1, ymax=99) - limits = self.plot.getXAxis().getLimits() - self.assertNotEqual(limits[1] - limits[0], 100) - limits = self.plot.getYAxis().getLimits() - self.assertEqual(limits[1] - limits[0], 100) - - def testMaxYRange(self): - """Test max range constains on y-axis""" - self.plot.getYAxis().setRangeConstraints(maxRange=100) - self.plot.setLimits(xmin=-1, xmax=101, ymin=-1, ymax=101) - limits = self.plot.getXAxis().getLimits() - self.assertNotEqual(limits[1] - limits[0], 100) - limits = self.plot.getYAxis().getLimits() - self.assertEqual(limits[1] - limits[0], 100) - - def testChangeOfConstraints(self): - """Test changing of the constraints""" - self.plot.getXAxis().setRangeConstraints(minRange=10, maxRange=10) - # There is no more constraints on the range - self.plot.getXAxis().setRangeConstraints(minRange=None, maxRange=None) - self.plot.setLimits(xmin=-1, xmax=101, ymin=-1, ymax=101) - self.assertEqual(self.plot.getXAxis().getLimits(), (-1, 101)) - - def testSettingConstraints(self): - """Test setting a constaint (setLimits first then the constaint)""" - self.plot.setLimits(xmin=-1, xmax=101, ymin=-1, ymax=101) - self.plot.getXAxis().setLimitsConstraints(minPos=0, maxPos=100) - self.assertEqual(self.plot.getXAxis().getLimits(), (0, 100)) - - -def suite(): - test_suite = unittest.TestSuite() - loadTests = unittest.defaultTestLoader.loadTestsFromTestCase - test_suite.addTest(loadTests(TestLimitConstaints)) - return test_suite - - -if __name__ == '__main__': - unittest.main(defaultTest='suite') diff --git a/silx/gui/plot/test/testMaskToolsWidget.py b/silx/gui/plot/test/testMaskToolsWidget.py deleted file mode 100644 index c22975f..0000000 --- a/silx/gui/plot/test/testMaskToolsWidget.py +++ /dev/null @@ -1,316 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# -# Copyright (c) 2016-2017 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 MaskToolsWidget""" - -__authors__ = ["T. Vincent"] -__license__ = "MIT" -__date__ = "17/01/2018" - - -import logging -import os.path -import unittest - -import numpy - -from silx.gui import qt -from silx.test.utils import temp_dir -from silx.utils.testutils import ParametricTestCase -from silx.gui.utils.testutils import getQToolButtonFromAction -from silx.gui.plot import PlotWindow, MaskToolsWidget -from .utils import PlotWidgetTestCase - -import fabio - - -_logger = logging.getLogger(__name__) - - -class TestMaskToolsWidget(PlotWidgetTestCase, ParametricTestCase): - """Basic test for MaskToolsWidget""" - - def _createPlot(self): - return PlotWindow() - - def setUp(self): - super(TestMaskToolsWidget, self).setUp() - self.widget = MaskToolsWidget.MaskToolsDockWidget(plot=self.plot, name='TEST') - self.plot.addDockWidget(qt.Qt.BottomDockWidgetArea, self.widget) - self.maskWidget = self.widget.widget() - - def tearDown(self): - del self.maskWidget - del self.widget - super(TestMaskToolsWidget, self).tearDown() - - def testEmptyPlot(self): - """Empty plot, display MaskToolsDockWidget, toggle multiple masks""" - self.maskWidget.setMultipleMasks('single') - self.qapp.processEvents() - - self.maskWidget.setMultipleMasks('exclusive') - self.qapp.processEvents() - - def _drag(self): - """Drag from plot center to offset position""" - plot = self.plot.getWidgetHandle() - xCenter, yCenter = plot.width() // 2, plot.height() // 2 - offset = min(plot.width(), plot.height()) // 10 - - pos0 = xCenter, yCenter - pos1 = xCenter + offset, yCenter + offset - - self.mouseMove(plot, pos=(0, 0)) - self.mouseMove(plot, pos=pos0) - self.qapp.processEvents() - self.mousePress(plot, qt.Qt.LeftButton, pos=pos0) - self.qapp.processEvents() - self.mouseMove(plot, pos=(pos0[0] + offset // 2, pos0[1] + offset // 2)) - self.mouseMove(plot, pos=pos1) - self.qapp.processEvents() - self.mouseRelease(plot, qt.Qt.LeftButton, pos=pos1) - self.qapp.processEvents() - self.mouseMove(plot, pos=(0, 0)) - - def _drawPolygon(self): - """Draw a star polygon in the plot""" - plot = self.plot.getWidgetHandle() - x, y = plot.width() // 2, plot.height() // 2 - offset = min(plot.width(), plot.height()) // 10 - - star = [(x, y + offset), - (x - offset, y - offset), - (x + offset, y), - (x - offset, y), - (x + offset, y - offset), - (x, y + offset)] # Close polygon - - self.mouseMove(plot, pos=(0, 0)) - for pos in star: - self.mouseMove(plot, pos=pos) - self.qapp.processEvents() - self.mousePress(plot, qt.Qt.LeftButton, pos=pos) - self.qapp.processEvents() - self.mouseRelease(plot, qt.Qt.LeftButton, pos=pos) - self.qapp.processEvents() - - def _drawPencil(self): - """Draw a star polygon in the plot""" - plot = self.plot.getWidgetHandle() - x, y = plot.width() // 2, plot.height() // 2 - offset = min(plot.width(), plot.height()) // 10 - - star = [(x, y + offset), - (x - offset, y - offset), - (x + offset, y), - (x - offset, y), - (x + offset, y - offset)] - - self.mouseMove(plot, pos=(0, 0)) - self.mouseMove(plot, pos=star[0]) - self.mousePress(plot, qt.Qt.LeftButton, pos=star[0]) - for pos in star[1:]: - self.mouseMove(plot, pos=pos) - self.mouseRelease( - plot, qt.Qt.LeftButton, pos=star[-1]) - - def _isMaskItemSync(self): - """Check if masks from item and tools are sync or not""" - if self.maskWidget.isItemMaskUpdated(): - return numpy.all(numpy.equal( - self.maskWidget.getSelectionMask(), - self.plot.getActiveImage().getMaskData(copy=False))) - else: - return True - - def testWithAnImage(self): - """Plot with an image: test MaskToolsWidget interactions""" - - # Add and remove a image (this should enable/disable GUI + change mask) - self.plot.addImage(numpy.random.random(1024**2).reshape(1024, 1024), - legend='test') - self.qapp.processEvents() - - self.plot.remove('test', kind='image') - self.qapp.processEvents() - - tests = [((0, 0), (1, 1)), - ((1000, 1000), (1, 1)), - ((0, 0), (-1, -1)), - ((1000, 1000), (-1, -1))] - - for itemMaskUpdated in (False, True): - for origin, scale in tests: - with self.subTest(origin=origin, scale=scale): - self.maskWidget.setItemMaskUpdated(itemMaskUpdated) - self.plot.addImage(numpy.arange(1024**2).reshape(1024, 1024), - legend='test', - origin=origin, - scale=scale) - self.qapp.processEvents() - - self.assertEqual( - self.maskWidget.isItemMaskUpdated(), itemMaskUpdated) - - # Test draw rectangle # - toolButton = getQToolButtonFromAction(self.maskWidget.rectAction) - self.assertIsNot(toolButton, None) - self.mouseClick(toolButton, qt.Qt.LeftButton) - - # mask - self.maskWidget.maskStateGroup.button(1).click() - self.qapp.processEvents() - self._drag() - self.assertFalse( - numpy.all(numpy.equal(self.maskWidget.getSelectionMask(), 0))) - self.assertTrue(self._isMaskItemSync()) - - # unmask same region - self.maskWidget.maskStateGroup.button(0).click() - self.qapp.processEvents() - self._drag() - self.assertTrue( - numpy.all(numpy.equal(self.maskWidget.getSelectionMask(), 0))) - self.assertTrue(self._isMaskItemSync()) - - # Test draw polygon # - toolButton = getQToolButtonFromAction(self.maskWidget.polygonAction) - self.assertIsNot(toolButton, None) - self.mouseClick(toolButton, qt.Qt.LeftButton) - - # mask - self.maskWidget.maskStateGroup.button(1).click() - self.qapp.processEvents() - self._drawPolygon() - self.assertFalse( - numpy.all(numpy.equal(self.maskWidget.getSelectionMask(), 0))) - self.assertTrue(self._isMaskItemSync()) - - # unmask same region - self.maskWidget.maskStateGroup.button(0).click() - self.qapp.processEvents() - self._drawPolygon() - self.assertTrue( - numpy.all(numpy.equal(self.maskWidget.getSelectionMask(), 0))) - self.assertTrue(self._isMaskItemSync()) - - # Test draw pencil # - toolButton = getQToolButtonFromAction(self.maskWidget.pencilAction) - self.assertIsNot(toolButton, None) - self.mouseClick(toolButton, qt.Qt.LeftButton) - - self.maskWidget.pencilSpinBox.setValue(30) - self.qapp.processEvents() - - # mask - self.maskWidget.maskStateGroup.button(1).click() - self.qapp.processEvents() - self._drawPencil() - self.assertFalse( - numpy.all(numpy.equal(self.maskWidget.getSelectionMask(), 0))) - self.assertTrue(self._isMaskItemSync()) - - # unmask same region - self.maskWidget.maskStateGroup.button(0).click() - self.qapp.processEvents() - self._drawPencil() - self.assertTrue( - numpy.all(numpy.equal(self.maskWidget.getSelectionMask(), 0))) - self.assertTrue(self._isMaskItemSync()) - - # Test no draw tool # - toolButton = getQToolButtonFromAction(self.maskWidget.browseAction) - self.assertIsNot(toolButton, None) - self.mouseClick(toolButton, qt.Qt.LeftButton) - - self.plot.clear() - - def __loadSave(self, file_format): - """Plot with an image: test MaskToolsWidget operations""" - self.plot.addImage(numpy.arange(1024**2).reshape(1024, 1024), - legend='test') - self.qapp.processEvents() - - # Draw a polygon mask - toolButton = getQToolButtonFromAction(self.maskWidget.polygonAction) - self.assertIsNot(toolButton, None) - self.mouseClick(toolButton, qt.Qt.LeftButton) - self._drawPolygon() - - ref_mask = self.maskWidget.getSelectionMask() - self.assertFalse(numpy.all(numpy.equal(ref_mask, 0))) - - with temp_dir() as tmp: - mask_filename = os.path.join(tmp, 'mask.' + file_format) - self.maskWidget.save(mask_filename, file_format) - - self.maskWidget.resetSelectionMask() - self.assertTrue( - numpy.all(numpy.equal(self.maskWidget.getSelectionMask(), 0))) - - self.maskWidget.load(mask_filename) - self.assertTrue(numpy.all(numpy.equal( - self.maskWidget.getSelectionMask(), ref_mask))) - - def testLoadSaveNpy(self): - self.__loadSave("npy") - - def testLoadSaveFit2D(self): - self.__loadSave("msk") - - def testSigMaskChangedEmitted(self): - self.plot.addImage(numpy.arange(512**2).reshape(512, 512), - legend='test') - self.plot.resetZoom() - self.qapp.processEvents() - - l = [] - - def slot(): - l.append(1) - - self.maskWidget.sigMaskChanged.connect(slot) - - # rectangle mask - toolButton = getQToolButtonFromAction(self.maskWidget.rectAction) - self.assertIsNot(toolButton, None) - self.mouseClick(toolButton, qt.Qt.LeftButton) - self.maskWidget.maskStateGroup.button(1).click() - self.qapp.processEvents() - self._drag() - - self.assertGreater(len(l), 0) - - -def suite(): - test_suite = unittest.TestSuite() - for TestClass in (TestMaskToolsWidget,): - test_suite.addTest( - unittest.defaultTestLoader.loadTestsFromTestCase(TestClass)) - return test_suite - - -if __name__ == '__main__': - unittest.main(defaultTest='suite') diff --git a/silx/gui/plot/test/testPixelIntensityHistoAction.py b/silx/gui/plot/test/testPixelIntensityHistoAction.py deleted file mode 100644 index ac29952..0000000 --- a/silx/gui/plot/test/testPixelIntensityHistoAction.py +++ /dev/null @@ -1,157 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# -# Copyright (c) 2016-2018 European Synchrotron Radiation Facility -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# 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 PixelIntensitiesHistoAction""" - -__authors__ = ["T. Vincent"] -__license__ = "MIT" -__date__ = "02/03/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 Plot2D - - -class TestPixelIntensitiesHisto(TestCaseQt, ParametricTestCase): - """Tests for PixelIntensitiesHistoAction widget.""" - - def setUp(self): - super(TestPixelIntensitiesHisto, self).setUp() - self.image = numpy.random.rand(10, 10) - self.plotImage = Plot2D() - self.plotImage.getIntensityHistogramAction().setVisible(True) - - def tearDown(self): - del self.plotImage - super(TestPixelIntensitiesHisto, self).tearDown() - - def testShowAndHide(self): - """Simple test that the plot is showing and hiding when activating the - action""" - self.plotImage.addImage(self.image, origin=(0, 0), legend='sino') - 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() - self.assertTrue(histoAction.getHistogramWidget().isVisible()) - - # test the pixel intensity diagram is hiding - self.qapp.setActiveWindow(self.plotImage) - self.qapp.processEvents() - self.mouseMove(button) - self.mouseClick(button, qt.Qt.LeftButton) - self.qapp.processEvents() - self.assertFalse(histoAction.getHistogramWidget().isVisible()) - - def testImageFormatInput(self): - """Test multiple type as image input""" - typesToTest = [numpy.uint8, numpy.int8, numpy.int16, numpy.int32, - numpy.float32, numpy.float64] - self.plotImage.addImage(self.image, origin=(0, 0), legend='sino') - self.plotImage.show() - button = getQToolButtonFromAction( - self.plotImage.getIntensityHistogramAction()) - self.mouseMove(button) - self.mouseClick(button, qt.Qt.LeftButton) - self.qapp.processEvents() - for typeToTest in typesToTest: - with self.subTest(typeToTest=typeToTest): - 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() - - widget = histoAction.getHistogramWidget() - self.assertTrue(widget.isVisible()) - items = widget.getPlotWidget().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 - widget = histoAction.getHistogramWidget() - self.assertTrue(widget.isVisible()) - items = widget.getPlotWidget().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() - test_suite.addTest( - unittest.defaultTestLoader.loadTestsFromTestCase( - TestPixelIntensitiesHisto)) - return test_suite - - -if __name__ == '__main__': - unittest.main(defaultTest='suite') diff --git a/silx/gui/plot/test/testPlotInteraction.py b/silx/gui/plot/test/testPlotInteraction.py deleted file mode 100644 index 7a30434..0000000 --- a/silx/gui/plot/test/testPlotInteraction.py +++ /dev/null @@ -1,172 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# -# Copyright (c) 2016=2017 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. -# -# ###########################################################################*/ -"""Tests of plot interaction, through a PlotWidget""" - -__authors__ = ["T. Vincent"] -__license__ = "MIT" -__date__ = "01/09/2017" - - -import unittest -from silx.gui import qt -from .utils import PlotWidgetTestCase - - -class _SignalDump(object): - """Callable object that store passed arguments in a list""" - - def __init__(self): - self._received = [] - - def __call__(self, *args): - self._received.append(args) - - @property - def received(self): - """Return a shallow copy of the list of received arguments""" - return list(self._received) - - -class TestSelectPolygon(PlotWidgetTestCase): - """Test polygon selection interaction""" - - def _interactionModeChanged(self, source): - """Check that source received in event is the correct one""" - self.assertEqual(source, self) - - def _draw(self, polygon): - """Draw a polygon in the plot - - :param polygon: List of points (x, y) of the polygon (closed) - """ - plot = self.plot.getWidgetHandle() - - dump = _SignalDump() - self.plot.sigPlotSignal.connect(dump) - - for pos in polygon: - self.mouseMove(plot, pos=pos) - self.qapp.processEvents() - self.mousePress(plot, qt.Qt.LeftButton, pos=pos) - self.qapp.processEvents() - self.mouseRelease(plot, qt.Qt.LeftButton, pos=pos) - self.qapp.processEvents() - - self.plot.sigPlotSignal.disconnect(dump) - return [args[0] for args in dump.received] - - def test(self): - """Test draw polygons + events""" - self.plot.sigInteractiveModeChanged.connect( - self._interactionModeChanged) - - self.plot.setInteractiveMode( - 'draw', shape='polygon', label='test', source=self) - interaction = self.plot.getInteractiveMode() - - self.assertEqual(interaction['mode'], 'draw') - self.assertEqual(interaction['shape'], 'polygon') - - self.plot.sigInteractiveModeChanged.disconnect( - self._interactionModeChanged) - - plot = self.plot.getWidgetHandle() - xCenter, yCenter = plot.width() // 2, plot.height() // 2 - offset = min(plot.width(), plot.height()) // 10 - - # Star polygon - star = [(xCenter, yCenter + offset), - (xCenter - offset, yCenter - offset), - (xCenter + offset, yCenter), - (xCenter - offset, yCenter), - (xCenter + offset, yCenter - offset), - (xCenter, yCenter + offset)] # Close polygon - - # Draw while dumping signals - events = self._draw(star) - - # Test last event - drawEvents = [event for event in events - if event['event'].startswith('drawing')] - self.assertEqual(drawEvents[-1]['event'], 'drawingFinished') - self.assertEqual(len(drawEvents[-1]['points']), 6) - - # Large square - largeSquare = [(xCenter - offset, yCenter - offset), - (xCenter + offset, yCenter - offset), - (xCenter + offset, yCenter + offset), - (xCenter - offset, yCenter + offset), - (xCenter - offset, yCenter - offset)] # Close polygon - - # Draw while dumping signals - events = self._draw(largeSquare) - - # Test last event - drawEvents = [event for event in events - if event['event'].startswith('drawing')] - self.assertEqual(drawEvents[-1]['event'], 'drawingFinished') - self.assertEqual(len(drawEvents[-1]['points']), 5) - - # Rectangle too thin along X: Some points are ignored - thinRectX = [(xCenter, yCenter - offset), - (xCenter, yCenter + offset), - (xCenter + 1, yCenter + offset), - (xCenter + 1, yCenter - offset)] # Close polygon - - # Draw while dumping signals - events = self._draw(thinRectX) - - # Test last event - drawEvents = [event for event in events - if event['event'].startswith('drawing')] - self.assertEqual(drawEvents[-1]['event'], 'drawingFinished') - self.assertEqual(len(drawEvents[-1]['points']), 3) - - # Rectangle too thin along Y: Some points are ignored - thinRectY = [(xCenter - offset, yCenter), - (xCenter + offset, yCenter), - (xCenter + offset, yCenter + 1), - (xCenter - offset, yCenter + 1)] # Close polygon - - # Draw while dumping signals - events = self._draw(thinRectY) - - # Test last event - drawEvents = [event for event in events - if event['event'].startswith('drawing')] - self.assertEqual(drawEvents[-1]['event'], 'drawingFinished') - self.assertEqual(len(drawEvents[-1]['points']), 3) - - -def suite(): - test_suite = unittest.TestSuite() - for TestClass in (TestSelectPolygon,): - test_suite.addTest( - unittest.defaultTestLoader.loadTestsFromTestCase(TestClass)) - return test_suite - - -if __name__ == '__main__': - unittest.main(defaultTest='suite') diff --git a/silx/gui/plot/test/testPlotWidget.py b/silx/gui/plot/test/testPlotWidget.py deleted file mode 100755 index b55260e..0000000 --- a/silx/gui/plot/test/testPlotWidget.py +++ /dev/null @@ -1,2072 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# -# Copyright (c) 2016-2021 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 PlotWidget""" - -__authors__ = ["T. Vincent"] -__license__ = "MIT" -__date__ = "03/01/2019" - - -import unittest -import logging -import numpy -import sys - -from silx.utils.testutils import ParametricTestCase, parameterize -from silx.gui.utils.testutils import SignalListener -from silx.gui.utils.testutils import TestCaseQt - -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 import BoundingRect, XAxisExtent, YAxisExtent, Axis -from silx.gui.colors import Colormap - -from .utils import PlotWidgetTestCase - - -SIZE = 1024 -"""Size of the test image""" - -DATA_2D = numpy.arange(SIZE ** 2).reshape(SIZE, SIZE) -"""Image data set""" - - -logger = logging.getLogger(__name__) - - -class TestSpecialBackend(PlotWidgetTestCase, ParametricTestCase): - - def __init__(self, methodName='runTest', backend=None): - TestCaseQt.__init__(self, methodName=methodName) - self.__backend = backend - - def _createPlot(self): - return PlotWidget(backend=self.__backend) - - def testPlot(self): - self.assertIsNotNone(self.plot) - - -class TestPlotWidget(PlotWidgetTestCase, ParametricTestCase): - """Basic tests for PlotWidget""" - - def testShow(self): - """Most basic test""" - pass - - def testSetTitleLabels(self): - """Set title and axes labels""" - - title, xlabel, ylabel = 'the title', 'x label', 'y label' - self.plot.setGraphTitle(title) - self.plot.getXAxis().setLabel(xlabel) - self.plot.getYAxis().setLabel(ylabel) - self.qapp.processEvents() - - self.assertEqual(self.plot.getGraphTitle(), title) - self.assertEqual(self.plot.getXAxis().getLabel(), xlabel) - self.assertEqual(self.plot.getYAxis().getLabel(), ylabel) - - def _checkLimits(self, - expectedXLim=None, - expectedYLim=None, - expectedRatio=None): - """Assert that limits are as expected""" - xlim = self.plot.getXAxis().getLimits() - ylim = self.plot.getYAxis().getLimits() - ratio = abs(xlim[1] - xlim[0]) / abs(ylim[1] - ylim[0]) - - if expectedXLim is not None: - self.assertEqual(expectedXLim, xlim) - - if expectedYLim is not None: - self.assertEqual(expectedYLim, ylim) - - if expectedRatio is not None: - self.assertTrue( - numpy.allclose(expectedRatio, ratio, atol=0.01)) - - def testChangeLimitsWithAspectRatio(self): - self.plot.setKeepDataAspectRatio() - self.qapp.processEvents() - xlim = self.plot.getXAxis().getLimits() - ylim = self.plot.getYAxis().getLimits() - defaultRatio = abs(xlim[1] - xlim[0]) / abs(ylim[1] - ylim[0]) - - self.plot.getXAxis().setLimits(1., 10.) - self._checkLimits(expectedXLim=(1., 10.), expectedRatio=defaultRatio) - self.qapp.processEvents() - self._checkLimits(expectedXLim=(1., 10.), expectedRatio=defaultRatio) - - self.plot.getYAxis().setLimits(1., 10.) - self._checkLimits(expectedYLim=(1., 10.), expectedRatio=defaultRatio) - self.qapp.processEvents() - self._checkLimits(expectedYLim=(1., 10.), expectedRatio=defaultRatio) - - def testResizeWidget(self): - """Test resizing the widget and receiving limitsChanged events""" - self.plot.resize(200, 200) - self.qapp.processEvents() - self.qWait(100) - - xlim = self.plot.getXAxis().getLimits() - ylim = self.plot.getYAxis().getLimits() - - listener = SignalListener() - self.plot.getXAxis().sigLimitsChanged.connect(listener.partial('x')) - self.plot.getYAxis().sigLimitsChanged.connect(listener.partial('y')) - - # Resize without aspect ratio - self.plot.resize(200, 300) - self.qapp.processEvents() - self.qWait(100) - self._checkLimits(expectedXLim=xlim, expectedYLim=ylim) - self.assertEqual(listener.callCount(), 0) - - # Resize with aspect ratio - self.plot.setKeepDataAspectRatio(True) - self.qapp.processEvents() - self.qWait(1000) - listener.clear() # Clean-up received signal - - self.plot.resize(200, 200) - self.qapp.processEvents() - self.qWait(100) - self.assertNotEqual(listener.callCount(), 0) - - def testAddRemoveItemSignals(self): - """Test sigItemAdded and sigItemAboutToBeRemoved""" - listener = SignalListener() - self.plot.sigItemAdded.connect(listener.partial('add')) - self.plot.sigItemAboutToBeRemoved.connect(listener.partial('remove')) - - self.plot.addCurve((1, 2, 3), (3, 2, 1), legend='curve') - self.assertEqual(listener.callCount(), 1) - - curve = self.plot.getCurve('curve') - self.plot.remove('curve') - self.assertEqual(listener.callCount(), 2) - self.assertEqual(listener.arguments(callIndex=0), ('add', curve)) - self.assertEqual(listener.arguments(callIndex=1), ('remove', curve)) - - def testGetItems(self): - """Test getItems method""" - curve_x = 1, 2 - self.plot.addCurve(curve_x, (3, 4)) - image = (0, 1), (2, 3) - self.plot.addImage(image) - scatter_x = 10, 11 - self.plot.addScatter(scatter_x, (12, 13), (0, 1)) - marker_pos = 5, 5 - self.plot.addMarker(*marker_pos) - marker_x = 6 - self.plot.addXMarker(marker_x) - self.plot.addShape((0, 5), (2, 10), shape='rectangle') - - items = self.plot.getItems() - self.assertEqual(len(items), 6) - self.assertTrue(numpy.all(numpy.equal(items[0].getXData(), curve_x))) - self.assertTrue(numpy.all(numpy.equal(items[1].getData(), image))) - self.assertTrue(numpy.all(numpy.equal(items[2].getXData(), scatter_x))) - self.assertTrue(numpy.all(numpy.equal(items[3].getPosition(), marker_pos))) - self.assertTrue(numpy.all(numpy.equal(items[4].getPosition()[0], marker_x))) - self.assertEqual(items[5].getType(), 'rectangle') - - def testRemoveDiscardItem(self): - """Test removeItem and discardItem""" - self.plot.addCurve((1, 2, 3), (1, 2, 3)) - curve = self.plot.getItems()[0] - self.plot.removeItem(curve) - with self.assertRaises(ValueError): - self.plot.removeItem(curve) - - self.plot.addCurve((1, 2, 3), (1, 2, 3)) - curve = self.plot.getItems()[0] - result = self.plot.discardItem(curve) - self.assertTrue(result) - result = self.plot.discardItem(curve) - self.assertFalse(result) - - def testBackGroundColors(self): - self.plot.setVisible(True) - self.qWaitForWindowExposed(self.plot) - self.qapp.processEvents() - - # Custom the full background - color = self.plot.getBackgroundColor() - self.assertTrue(color.isValid()) - self.assertEqual(color, qt.QColor(255, 255, 255)) - self.plot.setBackgroundColor("red") - color = self.plot.getBackgroundColor() - self.assertTrue(color.isValid()) - self.qapp.processEvents() - - # Custom the data background - color = self.plot.getDataBackgroundColor() - self.assertFalse(color.isValid()) - self.plot.setDataBackgroundColor("red") - color = self.plot.getDataBackgroundColor() - self.assertTrue(color.isValid()) - self.qapp.processEvents() - - # Back to default - self.plot.setBackgroundColor('white') - self.plot.setDataBackgroundColor(None) - color = self.plot.getBackgroundColor() - self.assertTrue(color.isValid()) - self.assertEqual(color, qt.QColor(255, 255, 255)) - color = self.plot.getDataBackgroundColor() - self.assertFalse(color.isValid()) - self.qapp.processEvents() - - -class TestPlotImage(PlotWidgetTestCase, ParametricTestCase): - """Basic tests for addImage""" - - def setUp(self): - super(TestPlotImage, self).setUp() - - self.plot.getYAxis().setLabel('Rows') - self.plot.getXAxis().setLabel('Columns') - - def testPlotColormapTemperature(self): - self.plot.setGraphTitle('Temp. Linear') - - colormap = Colormap(name='temperature', - normalization='linear', - vmin=None, - vmax=None) - self.plot.addImage(DATA_2D, legend="image 1", colormap=colormap) - - def testPlotColormapGray(self): - self.plot.setKeepDataAspectRatio(False) - self.plot.setGraphTitle('Gray Linear') - - colormap = Colormap(name='gray', - normalization='linear', - vmin=None, - vmax=None) - self.plot.addImage(DATA_2D, legend="image 1", colormap=colormap) - - def testPlotColormapTemperatureLog(self): - self.plot.setGraphTitle('Temp. Log') - - colormap = Colormap(name='temperature', - normalization=Colormap.LOGARITHM, - vmin=None, - vmax=None) - self.plot.addImage(DATA_2D, legend="image 1", colormap=colormap) - - def testPlotRgbRgba(self): - self.plot.setKeepDataAspectRatio(False) - self.plot.setGraphTitle('RGB + RGBA') - - rgb = numpy.array( - (((0, 0, 0), (128, 0, 0), (255, 0, 0)), - ((0, 128, 0), (0, 128, 128), (0, 128, 255))), - dtype=numpy.uint8) - - 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( - (((0, 0, 0, .5), (.5, 0, 0, 1), (1, 0, 0, .5)), - ((0, .5, 0, 1), (0, .5, .5, 1), (0, 1, 1, .5))), - dtype=numpy.float32) - - self.plot.addImage(rgba, legend="rgba_float32", - origin=(9, 6), scale=(1, 1), - resetzoom=False) - - self.plot.resetZoom() - - def testPlotColormapCustom(self): - self.plot.setKeepDataAspectRatio(False) - self.plot.setGraphTitle('Custom colormap') - - colormap = Colormap(name=None, - normalization=Colormap.LINEAR, - vmin=None, - vmax=None, - colors=((0., 0., 0.), (1., 0., 0.), - (0., 1., 0.), (0., 0., 1.))) - self.plot.addImage(DATA_2D, legend="image 1", colormap=colormap, - resetzoom=False) - - colormap = Colormap(name=None, - normalization=Colormap.LINEAR, - vmin=None, - vmax=None, - colors=numpy.array( - ((0, 0, 0, 0), (0, 0, 0, 128), - (128, 128, 128, 128), (255, 255, 255, 255)), - dtype=numpy.uint8)) - self.plot.addImage(DATA_2D, legend="image 2", colormap=colormap, - origin=(DATA_2D.shape[0], 0), - resetzoom=False) - self.plot.resetZoom() - - def testPlotColormapNaNColor(self): - self.plot.setKeepDataAspectRatio(False) - self.plot.setGraphTitle('Colormap with NaN color') - - colormap = Colormap() - colormap.setNaNColor('red') - self.assertEqual(colormap.getNaNColor(), qt.QColor(255, 0, 0)) - data = DATA_2D.astype(numpy.float32) - data[len(data)//2:] = numpy.nan - self.plot.addImage(data, legend="image 1", colormap=colormap, - resetzoom=False) - self.plot.resetZoom() - - colormap.setNaNColor((0., 1., 0., 1.)) - self.assertEqual(colormap.getNaNColor(), qt.QColor(0, 255, 0)) - self.qapp.processEvents() - - def testImageOriginScale(self): - """Test of image with different origin and scale""" - self.plot.setGraphTitle('origin and scale') - - tests = [ # (origin, scale) - ((10, 20), (1, 1)), - ((10, 20), (-1, -1)), - ((-10, 20), (2, 1)), - ((10, -20), (-1, -2)), - (100, 2), - (-100, (1, 1)), - ((10, 20), 2), - ] - - for origin, scale in tests: - with self.subTest(origin=origin, scale=scale): - self.plot.addImage(DATA_2D, origin=origin, scale=scale) - - try: - ox, oy = origin - except TypeError: - ox, oy = origin, origin - try: - sx, sy = scale - except TypeError: - sx, sy = scale, scale - xbounds = ox, ox + DATA_2D.shape[1] * sx - ybounds = oy, oy + DATA_2D.shape[0] * sy - - # Check limits without aspect ratio - xmin, xmax = self.plot.getXAxis().getLimits() - ymin, ymax = self.plot.getYAxis().getLimits() - self.assertEqual(xmin, min(xbounds)) - self.assertEqual(xmax, max(xbounds)) - self.assertEqual(ymin, min(ybounds)) - self.assertEqual(ymax, max(ybounds)) - - # Check limits with aspect ratio - self.plot.setKeepDataAspectRatio(True) - xmin, xmax = self.plot.getXAxis().getLimits() - ymin, ymax = self.plot.getYAxis().getLimits() - self.assertTrue(round(xmin, 7) <= min(xbounds)) - self.assertTrue(round(xmax, 7) >= max(xbounds)) - self.assertTrue(round(ymin, 7) <= min(ybounds)) - self.assertTrue(round(ymax, 7) >= max(ybounds)) - - self.plot.setKeepDataAspectRatio(False) # Reset aspect ratio - self.plot.clear() - self.plot.resetZoom() - - def testPlotColormapDictAPI(self): - """Test that the addImage API using a colormap dictionary is still - working""" - self.plot.setGraphTitle('Temp. Log') - - colormap = { - 'name': 'temperature', - 'normalization': 'log', - 'vmin': None, - 'vmax': None - } - self.plot.addImage(DATA_2D, legend="image 1", colormap=colormap) - - def testPlotComplexImage(self): - """Test that a complex image is displayed as its absolute value.""" - data = numpy.linspace(1, 1j, 100).reshape(10, 10) - self.plot.addImage(data, legend='complex') - - image = self.plot.getActiveImage() - retrievedData = image.getData(copy=False) - self.assertTrue( - numpy.all(numpy.equal(retrievedData, numpy.absolute(data)))) - - def testPlotBooleanImage(self): - """Test that a boolean image is displayed and converted to int8.""" - data = numpy.zeros((10, 10), dtype=bool) - data[::2, ::2] = True - self.plot.addImage(data, legend='boolean') - - image = self.plot.getActiveImage() - retrievedData = image.getData(copy=False) - self.assertTrue(numpy.all(numpy.equal(retrievedData, data))) - self.assertIs(retrievedData.dtype.type, numpy.int8) - - def testPlotAlphaImage(self): - """Test with an alpha image layer""" - data = numpy.random.random((10, 10)) - alpha = numpy.linspace(0, 1, 100).reshape(10, 10) - self.plot.addImage(data, legend='image') - image = self.plot.getActiveImage() - image.setData(data, alpha=alpha) - self.qapp.processEvents() - self.assertTrue(numpy.array_equal(alpha, image.getAlphaData())) - - -class TestPlotCurve(PlotWidgetTestCase): - """Basic tests for addCurve.""" - - # Test data sets - xData = numpy.arange(1000) - yData = -500 + 100 * numpy.sin(xData) - xData2 = xData + 1000 - yData2 = xData - 1000 + 200 * numpy.random.random(1000) - - def setUp(self): - super(TestPlotCurve, self).setUp() - self.plot.setGraphTitle('Curve') - self.plot.getYAxis().setLabel('Rows') - self.plot.getXAxis().setLabel('Columns') - - self.plot.setActiveCurveHandling(False) - - def testPlotCurveInfinite(self): - """Test plot curves with not finite data""" - tests = { - 'y all not finite': ([0, 1, 2], [numpy.inf, numpy.nan, -numpy.inf]), - 'x all not finite': ([numpy.inf, numpy.nan, -numpy.inf], [0, 1, 2]), - 'x some inf': ([0, numpy.inf, 2], [0, 1, 2]), - 'y some inf': ([0, 1, 2], [0, numpy.inf, 2]) - } - for name, args in tests.items(): - with self.subTest(name): - self.plot.addCurve(*args) - self.plot.resetZoom() - self.qapp.processEvents() - self.plot.clear() - - def testPlotCurveColorFloat(self): - color = numpy.array(numpy.random.random(3 * 1000), - dtype=numpy.float32).reshape(1000, 3) - - self.plot.addCurve(self.xData, self.yData, - legend="curve 1", - replace=False, resetzoom=False, - color=color, - linestyle="", symbol="s") - self.plot.addCurve(self.xData2, self.yData2, - legend="curve 2", - replace=False, resetzoom=False, - color='green', linestyle="-", symbol='o') - self.plot.resetZoom() - - def testPlotCurveColorByte(self): - color = numpy.array(255 * numpy.random.random(3 * 1000), - dtype=numpy.uint8).reshape(1000, 3) - - self.plot.addCurve(self.xData, self.yData, - legend="curve 1", - replace=False, resetzoom=False, - color=color, - linestyle="", symbol="s") - self.plot.addCurve(self.xData2, self.yData2, - legend="curve 2", - replace=False, resetzoom=False, - color='green', linestyle="-", symbol='o') - self.plot.resetZoom() - - def testPlotCurveColors(self): - color = numpy.array(numpy.random.random(3 * 1000), - dtype=numpy.float32).reshape(1000, 3) - - self.plot.addCurve(self.xData, self.yData, - legend="curve 2", - replace=False, resetzoom=False, - color=color, linestyle="-", symbol='o') - self.plot.resetZoom() - - # Test updating color array - - # From array to array - newColors = numpy.ones((len(self.xData), 3), dtype=numpy.float32) - self.plot.addCurve(self.xData, self.yData, - legend="curve 2", - replace=False, resetzoom=False, - color=newColors, symbol='o') - - # Array to single color - self.plot.addCurve(self.xData, self.yData, - legend="curve 2", - replace=False, resetzoom=False, - color='green', symbol='o') - - # single color to array - self.plot.addCurve(self.xData, self.yData, - legend="curve 2", - replace=False, resetzoom=False, - color=color, symbol='o') - - def testPlotBaselineNumpyArray(self): - """simple test of the API with baseline as a numpy array""" - x = numpy.arange(0, 10, step=0.1) - my_sin = numpy.sin(x) - y = numpy.arange(-4, 6, step=0.1) + my_sin - baseline = y - 1.0 - - self.plot.addCurve(x=x, y=y, color='grey', legend='curve1', fill=True, - baseline=baseline) - - def testPlotBaselineScalar(self): - """simple test of the API with baseline as an int""" - x = numpy.arange(0, 10, step=0.1) - my_sin = numpy.sin(x) - y = numpy.arange(-4, 6, step=0.1) + my_sin - - self.plot.addCurve(x=x, y=y, color='grey', legend='curve1', fill=True, - baseline=0) - - def testPlotBaselineList(self): - """simple test of the API with baseline as an int""" - x = numpy.arange(0, 10, step=0.1) - my_sin = numpy.sin(x) - y = numpy.arange(-4, 6, step=0.1) + my_sin - - self.plot.addCurve(x=x, y=y, color='grey', legend='curve1', fill=True, - baseline=list(range(0, 100, 1))) - - def testPlotCurveComplexData(self): - """Test curve with complex data""" - data = numpy.arange(100.) + 1j - self.plot.addCurve(x=data, y=data, xerror=data, yerror=data) - - -class TestPlotHistogram(PlotWidgetTestCase): - """Basic tests for add Histogram""" - def setUp(self): - super(TestPlotHistogram, self).setUp() - self.edges = numpy.arange(0, 10, step=1) - self.histogram = numpy.random.random(len(self.edges)) - - def testPlot(self): - self.plot.addHistogram(histogram=self.histogram, - edges=self.edges, - legend='histogram1') - - def testPlotBaseline(self): - self.plot.addHistogram(histogram=self.histogram, - edges=self.edges, - legend='histogram1', - color='blue', - baseline=-2, - z=2, - fill=True) - - -class TestPlotScatter(PlotWidgetTestCase, ParametricTestCase): - """Basic tests for addScatter""" - - def testScatter(self): - x = numpy.arange(100) - y = numpy.arange(100) - value = numpy.arange(100) - self.plot.addScatter(x, y, value) - self.plot.resetZoom() - - def testScatterComplexData(self): - """Test scatter item with complex data""" - data = numpy.arange(100.) + 1j - self.plot.addScatter( - x=data, y=data, value=data, xerror=data, yerror=data) - self.plot.resetZoom() - - def testScatterVisualization(self): - self.plot.addScatter((0, 1, 0, 1), (0, 0, 2, 2), (0, 1, 2, 3)) - self.plot.resetZoom() - self.qapp.processEvents() - - scatter = self.plot.getItems()[0] - - for visualization in ('solid', - 'points', - 'regular_grid', - 'irregular_grid', - 'binned_statistic', - scatter.Visualization.SOLID, - scatter.Visualization.POINTS, - scatter.Visualization.REGULAR_GRID, - scatter.Visualization.IRREGULAR_GRID, - scatter.Visualization.BINNED_STATISTIC): - with self.subTest(visualization=visualization): - scatter.setVisualization(visualization) - self.qapp.processEvents() - - def testGridVisualization(self): - """Test regular and irregular grid mode with different points""" - points = { # name: (x, y, order) - 'single point': ((1.,), (1.,), 'row'), - 'horizontal line': ((0, 1, 2), (0, 0, 0), 'row'), - 'horizontal line backward': ((2, 1, 0), (0, 0, 0), 'row'), - 'vertical line': ((0, 0, 0), (0, 1, 2), 'row'), - 'vertical line backward': ((0, 0, 0), (2, 1, 0), 'row'), - 'grid fast x, +x +y': ((0, 1, 2, 0, 1, 2), (0, 0, 0, 1, 1, 1), 'row'), - 'grid fast x, +x -y': ((0, 1, 2, 0, 1, 2), (1, 1, 1, 0, 0, 0), 'row'), - 'grid fast x, -x -y': ((2, 1, 0, 2, 1, 0), (1, 1, 1, 0, 0, 0), 'row'), - 'grid fast x, -x +y': ((2, 1, 0, 2, 1, 0), (0, 0, 0, 1, 1, 1), 'row'), - 'grid fast y, +x +y': ((0, 0, 0, 1, 1, 1), (0, 1, 2, 0, 1, 2), 'column'), - 'grid fast y, +x -y': ((0, 0, 0, 1, 1, 1), (2, 1, 0, 2, 1, 0), 'column'), - 'grid fast y, -x -y': ((1, 1, 1, 0, 0, 0), (2, 1, 0, 2, 1, 0), 'column'), - 'grid fast y, -x +y': ((1, 1, 1, 0, 0, 0), (0, 1, 2, 0, 1, 2), 'column'), - } - - self.plot.addScatter((), (), ()) - scatter = self.plot.getItems()[0] - - self.qapp.processEvents() - - for visualization in (scatter.Visualization.REGULAR_GRID, - scatter.Visualization.IRREGULAR_GRID): - scatter.setVisualization(visualization) - self.assertIs(scatter.getVisualization(), visualization) - - for name, (x, y, ref_order) in points.items(): - with self.subTest(name=name, visualization=visualization.name): - scatter.setData(x, y, numpy.arange(len(x))) - self.plot.setGraphTitle(name) - self.plot.resetZoom() - self.qapp.processEvents() - - order = scatter.getCurrentVisualizationParameter( - scatter.VisualizationParameter.GRID_MAJOR_ORDER) - self.assertEqual(ref_order, order) - - ref_bounds = (x[0], y[0]), (x[-1], y[-1]) - bounds = scatter.getCurrentVisualizationParameter( - scatter.VisualizationParameter.GRID_BOUNDS) - self.assertEqual(ref_bounds, bounds) - - shape = scatter.getCurrentVisualizationParameter( - scatter.VisualizationParameter.GRID_SHAPE) - - self.plot.getXAxis().setLimits(numpy.min(x) - 1, numpy.max(x) + 1) - self.plot.getYAxis().setLimits(numpy.min(y) - 1, numpy.max(y) + 1) - self.qapp.processEvents() - - for index, position in enumerate(zip(x, y)): - xpixel, ypixel = self.plot.dataToPixel(*position) - result = scatter.pick(xpixel, ypixel) - 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): - """Basic tests for add*Marker""" - - def setUp(self): - super(TestPlotMarker, self).setUp() - self.plot.getYAxis().setLabel('Rows') - self.plot.getXAxis().setLabel('Columns') - - self.plot.getXAxis().setAutoScale(False) - self.plot.getYAxis().setAutoScale(False) - self.plot.setKeepDataAspectRatio(False) - self.plot.setLimits(0., 100., -100., 100.) - - def testPlotMarkerX(self): - self.plot.setGraphTitle('Markers X') - - markers = [ - (10., 'blue', False, False), - (20., 'red', False, False), - (40., 'green', True, False), - (60., 'gray', True, True), - (80., 'black', False, True), - ] - - for x, color, select, drag in markers: - name = str(x) - if select: - name += " sel." - if drag: - name += " drag" - self.plot.addXMarker(x, name, name, color, select, drag) - self.plot.resetZoom() - - def testPlotMarkerY(self): - self.plot.setGraphTitle('Markers Y') - - markers = [ - (-50., 'blue', False, False), - (-30., 'red', False, False), - (0., 'green', True, False), - (10., 'gray', True, True), - (80., 'black', False, True), - ] - - for y, color, select, drag in markers: - name = str(y) - if select: - name += " sel." - if drag: - name += " drag" - self.plot.addYMarker(y, name, name, color, select, drag) - self.plot.resetZoom() - - def testPlotMarkerPt(self): - self.plot.setGraphTitle('Markers Pt') - - markers = [ - (10., -50., 'blue', False, False), - (40., -30., 'red', False, False), - (50., 0., 'green', True, False), - (50., 20., 'gray', True, True), - (70., 50., 'black', False, True), - ] - for x, y, color, select, drag in markers: - name = "{0},{1}".format(x, y) - if select: - name += " sel." - if drag: - name += " drag" - self.plot.addMarker(x, y, name, name, color, select, drag) - - self.plot.resetZoom() - - def testPlotMarkerWithoutLegend(self): - self.plot.setGraphTitle('Markers without legend') - self.plot.getYAxis().setInverted(True) - - # Markers without legend - self.plot.addMarker(10, 10) - self.plot.addMarker(10, 20) - self.plot.addMarker(40, 50, text='test', symbol=None) - self.plot.addMarker(40, 50, text='test', symbol='+') - self.plot.addXMarker(25) - self.plot.addXMarker(35) - self.plot.addXMarker(45, text='test') - self.plot.addYMarker(55) - self.plot.addYMarker(65) - self.plot.addYMarker(75, text='test') - - self.plot.resetZoom() - - def testPlotMarkerYAxis(self): - # Check only the API - - legend = self.plot.addMarker(10, 10) - item = self.plot._getMarker(legend) - self.assertEqual(item.getYAxis(), "left") - - legend = self.plot.addMarker(10, 10, yaxis="right") - item = self.plot._getMarker(legend) - self.assertEqual(item.getYAxis(), "right") - - legend = self.plot.addMarker(10, 10, yaxis="left") - item = self.plot._getMarker(legend) - self.assertEqual(item.getYAxis(), "left") - - legend = self.plot.addXMarker(10, yaxis="right") - item = self.plot._getMarker(legend) - self.assertEqual(item.getYAxis(), "right") - - legend = self.plot.addXMarker(10, yaxis="left") - item = self.plot._getMarker(legend) - self.assertEqual(item.getYAxis(), "left") - - legend = self.plot.addYMarker(10, yaxis="right") - item = self.plot._getMarker(legend) - self.assertEqual(item.getYAxis(), "right") - - legend = self.plot.addYMarker(10, yaxis="left") - item = self.plot._getMarker(legend) - self.assertEqual(item.getYAxis(), "left") - - self.plot.resetZoom() - - -# TestPlotItem ################################################################ - -class TestPlotItem(PlotWidgetTestCase): - """Basic tests for addItem.""" - - # Polygon coordinates and color - POLYGONS = [ # legend, x coords, y coords, color - ('triangle', numpy.array((10, 30, 50)), - numpy.array((55, 70, 55)), 'red'), - ('square', numpy.array((10, 10, 50, 50)), - numpy.array((10, 50, 50, 10)), 'green'), - ('star', numpy.array((60, 70, 80, 60, 80)), - numpy.array((25, 50, 25, 40, 40)), 'blue'), - ('2 triangles-simple', - numpy.array((90., 95., 100., numpy.nan, 90., 95., 100.)), - numpy.array((25., 5., 25., numpy.nan, 30., 50., 30.)), - 'pink'), - ('2 triangles-extra NaN', - numpy.array((numpy.nan, 90., 95., 100., numpy.nan, 0., 90., 95., 100., numpy.nan)), - numpy.array((0., 55., 70., 55., numpy.nan, numpy.nan, 75., 90., 75., numpy.nan)), - 'black'), - ] - - # Rectangle coordinantes and color - RECTANGLES = [ # legend, x coords, y coords, color - ('square 1', numpy.array((1., 10.)), - numpy.array((1., 10.)), 'red'), - ('square 2', numpy.array((10., 20.)), - numpy.array((10., 20.)), 'green'), - ('square 3', numpy.array((20., 30.)), - numpy.array((20., 30.)), 'blue'), - ('rect 1', numpy.array((1., 30.)), - numpy.array((35., 40.)), 'black'), - ('line h', numpy.array((1., 30.)), - numpy.array((45., 45.)), 'darkRed'), - ] - - SCALES = Axis.LINEAR, Axis.LOGARITHMIC - - def setUp(self): - super(TestPlotItem, self).setUp() - - self.plot.getYAxis().setLabel('Rows') - self.plot.getXAxis().setLabel('Columns') - self.plot.getXAxis().setAutoScale(False) - self.plot.getYAxis().setAutoScale(False) - self.plot.setKeepDataAspectRatio(False) - self.plot.setLimits(0., 100., -100., 100.) - - def testPlotItemPolygonFill(self): - for scale in self.SCALES: - with self.subTest(scale=scale): - self.plot.clear() - self.plot.getXAxis().setScale(scale) - self.plot.getYAxis().setScale(scale) - self.plot.setGraphTitle('Item Fill %s' % scale) - - for legend, xList, yList, color in self.POLYGONS: - self.plot.addShape(xList, yList, legend=legend, - replace=False, linestyle='--', - shape="polygon", fill=True, color=color) - self.plot.resetZoom() - - def testPlotItemPolygonNoFill(self): - for scale in self.SCALES: - with self.subTest(scale=scale): - self.plot.clear() - self.plot.getXAxis().setScale(scale) - self.plot.getYAxis().setScale(scale) - self.plot.setGraphTitle('Item No Fill %s' % scale) - - for legend, xList, yList, color in self.POLYGONS: - self.plot.addShape(xList, yList, legend=legend, - replace=False, linestyle='--', - shape="polygon", fill=False, color=color) - self.plot.resetZoom() - - def testPlotItemRectangleFill(self): - for scale in self.SCALES: - with self.subTest(scale=scale): - self.plot.clear() - self.plot.getXAxis().setScale(scale) - self.plot.getYAxis().setScale(scale) - self.plot.setGraphTitle('Rectangle Fill %s' % scale) - - for legend, xList, yList, color in self.RECTANGLES: - self.plot.addShape(xList, yList, legend=legend, - replace=False, - shape="rectangle", fill=True, color=color) - self.plot.resetZoom() - - def testPlotItemRectangleNoFill(self): - for scale in self.SCALES: - with self.subTest(scale=scale): - self.plot.clear() - self.plot.getXAxis().setScale(scale) - self.plot.getYAxis().setScale(scale) - self.plot.setGraphTitle('Rectangle No Fill %s' % scale) - - for legend, xList, yList, color in self.RECTANGLES: - self.plot.addShape(xList, yList, legend=legend, - replace=False, - shape="rectangle", fill=False, color=color) - self.plot.resetZoom() - - -class TestPlotActiveCurveImage(PlotWidgetTestCase): - """Basic tests for active curve and image handling""" - xData = numpy.arange(1000) - yData = -500 + 100 * numpy.sin(xData) - xData2 = xData + 1000 - yData2 = xData - 1000 + 200 * numpy.random.random(1000) - - def tearDown(self): - self.plot.setActiveCurveHandling(False) - super(TestPlotActiveCurveImage, self).tearDown() - - def testActiveCurveAndLabels(self): - # Active curve handling off, no label change - self.plot.setActiveCurveHandling(False) - self.plot.getXAxis().setLabel('XLabel') - self.plot.getYAxis().setLabel('YLabel') - self.plot.addCurve((1, 2), (1, 2)) - self.assertEqual(self.plot.getXAxis().getLabel(), 'XLabel') - self.assertEqual(self.plot.getYAxis().getLabel(), 'YLabel') - - self.plot.addCurve((1, 2), (2, 3), xlabel='x1', ylabel='y1') - self.assertEqual(self.plot.getXAxis().getLabel(), 'XLabel') - self.assertEqual(self.plot.getYAxis().getLabel(), 'YLabel') - - self.plot.clear() - self.assertEqual(self.plot.getXAxis().getLabel(), 'XLabel') - self.assertEqual(self.plot.getYAxis().getLabel(), 'YLabel') - - # Active curve handling on, label changes - self.plot.setActiveCurveHandling(True) - self.plot.getXAxis().setLabel('XLabel') - self.plot.getYAxis().setLabel('YLabel') - - # labels changed as active curve - self.plot.addCurve((1, 2), (1, 2), legend='1', - xlabel='x1', ylabel='y1') - self.plot.setActiveCurve('1') - self.assertEqual(self.plot.getXAxis().getLabel(), 'x1') - self.assertEqual(self.plot.getYAxis().getLabel(), 'y1') - - # labels not changed as not active curve - self.plot.addCurve((1, 2), (2, 3), legend='2') - self.assertEqual(self.plot.getXAxis().getLabel(), 'x1') - self.assertEqual(self.plot.getYAxis().getLabel(), 'y1') - - # labels changed - self.plot.setActiveCurve('2') - self.assertEqual(self.plot.getXAxis().getLabel(), 'XLabel') - self.assertEqual(self.plot.getYAxis().getLabel(), 'YLabel') - - self.plot.setActiveCurve('1') - self.assertEqual(self.plot.getXAxis().getLabel(), 'x1') - self.assertEqual(self.plot.getYAxis().getLabel(), 'y1') - - self.plot.clear() - self.assertEqual(self.plot.getXAxis().getLabel(), 'XLabel') - self.assertEqual(self.plot.getYAxis().getLabel(), 'YLabel') - - def testPlotActiveCurveSelectionMode(self): - self.plot.clear() - self.plot.setActiveCurveHandling(True) - legend = "curve 1" - self.plot.addCurve(self.xData, self.yData, - legend=legend, - color="green") - - # active curve should be None - self.assertEqual(self.plot.getActiveCurve(just_legend=True), None) - - # active curve should be None when None is set as active curve - self.plot.setActiveCurve(legend) - current = self.plot.getActiveCurve(just_legend=True) - self.assertEqual(current, legend) - self.plot.setActiveCurve(None) - current = self.plot.getActiveCurve(just_legend=True) - self.assertEqual(current, None) - - # testing it automatically toggles if there is only one - self.plot.setActiveCurveSelectionMode("legacy") - current = self.plot.getActiveCurve(just_legend=True) - self.assertEqual(current, legend) - - # active curve should not change when None set as active curve - self.assertEqual(self.plot.getActiveCurveSelectionMode(), "legacy") - self.plot.setActiveCurve(None) - current = self.plot.getActiveCurve(just_legend=True) - self.assertEqual(current, legend) - - # situation where no curve is active - self.plot.clear() - self.plot.setActiveCurveHandling(True) - self.assertEqual(self.plot.getActiveCurveSelectionMode(), "atmostone") - self.plot.addCurve(self.xData, self.yData, - legend=legend, - color="green") - self.assertEqual(self.plot.getActiveCurve(just_legend=True), None) - self.plot.addCurve(self.xData2, self.yData2, - legend="curve 2", - color="red") - self.assertEqual(self.plot.getActiveCurve(just_legend=True), None) - self.plot.setActiveCurveSelectionMode("legacy") - self.assertEqual(self.plot.getActiveCurve(just_legend=True), None) - - # the first curve added should be active - self.plot.clear() - self.plot.addCurve(self.xData, self.yData, - legend=legend, - color="green") - self.assertEqual(self.plot.getActiveCurve(just_legend=True), legend) - self.plot.addCurve(self.xData2, self.yData2, - legend="curve 2", - color="red") - self.assertEqual(self.plot.getActiveCurve(just_legend=True), legend) - - def testActiveCurveStyle(self): - """Test change of active curve style""" - self.plot.setActiveCurveHandling(True) - self.plot.setActiveCurveStyle(color='black') - style = self.plot.getActiveCurveStyle() - self.assertEqual(style.getColor(), (0., 0., 0., 1.)) - self.assertIsNone(style.getLineStyle()) - self.assertIsNone(style.getLineWidth()) - self.assertIsNone(style.getSymbol()) - self.assertIsNone(style.getSymbolSize()) - - self.plot.addCurve(x=self.xData, y=self.yData, legend="curve1") - curve = self.plot.getCurve("curve1") - curve.setColor('blue') - curve.setLineStyle('-') - curve.setLineWidth(1) - curve.setSymbol('o') - curve.setSymbolSize(5) - - # Check default current style - defaultStyle = curve.getCurrentStyle() - self.assertEqual(defaultStyle, CurveStyle(color='blue', - linestyle='-', - linewidth=1, - symbol='o', - symbolsize=5)) - - # Activate curve with highlight color=black - self.plot.setActiveCurve("curve1") - style = curve.getCurrentStyle() - self.assertEqual(style.getColor(), (0., 0., 0., 1.)) - self.assertEqual(style.getLineStyle(), '-') - self.assertEqual(style.getLineWidth(), 1) - self.assertEqual(style.getSymbol(), 'o') - self.assertEqual(style.getSymbolSize(), 5) - - # Change highlight to linewidth=2 - self.plot.setActiveCurveStyle(linewidth=2) - style = curve.getCurrentStyle() - self.assertEqual(style.getColor(), (0., 0., 1., 1.)) - self.assertEqual(style.getLineStyle(), '-') - self.assertEqual(style.getLineWidth(), 2) - self.assertEqual(style.getSymbol(), 'o') - self.assertEqual(style.getSymbolSize(), 5) - - self.plot.setActiveCurve(None) - self.assertEqual(curve.getCurrentStyle(), defaultStyle) - - def testActiveImageAndLabels(self): - # Active image handling always on, no API for toggling it - self.plot.getXAxis().setLabel('XLabel') - self.plot.getYAxis().setLabel('YLabel') - - # labels changed as active curve - self.plot.addImage(numpy.arange(100).reshape(10, 10), - legend='1', xlabel='x1', ylabel='y1') - self.assertEqual(self.plot.getXAxis().getLabel(), 'x1') - self.assertEqual(self.plot.getYAxis().getLabel(), 'y1') - - # labels not changed as not active curve - self.plot.addImage(numpy.arange(100).reshape(10, 10), - legend='2') - self.assertEqual(self.plot.getXAxis().getLabel(), 'x1') - self.assertEqual(self.plot.getYAxis().getLabel(), 'y1') - - # labels changed - self.plot.setActiveImage('2') - self.assertEqual(self.plot.getXAxis().getLabel(), 'XLabel') - self.assertEqual(self.plot.getYAxis().getLabel(), 'YLabel') - - self.plot.setActiveImage('1') - self.assertEqual(self.plot.getXAxis().getLabel(), 'x1') - self.assertEqual(self.plot.getYAxis().getLabel(), 'y1') - - self.plot.clear() - self.assertEqual(self.plot.getXAxis().getLabel(), 'XLabel') - self.assertEqual(self.plot.getYAxis().getLabel(), 'YLabel') - - -############################################################################## -# Log -############################################################################## - -class TestPlotEmptyLog(PlotWidgetTestCase): - """Basic tests for log plot""" - def testEmptyPlotTitleLabelsLog(self): - self.plot.setGraphTitle('Empty Log Log') - self.plot.getXAxis().setLabel('X') - self.plot.getYAxis().setLabel('Y') - self.plot.getXAxis()._setLogarithmic(True) - self.plot.getYAxis()._setLogarithmic(True) - self.plot.resetZoom() - - -class TestPlotAxes(TestCaseQt, ParametricTestCase): - - # Test data - xData = numpy.arange(1, 10) - yData = xData ** 2 - - def __init__(self, methodName='runTest', backend=None): - unittest.TestCase.__init__(self, methodName) - self.__backend = backend - - def setUp(self): - super(TestPlotAxes, self).setUp() - self.plot = PlotWidget(backend=self.__backend) - # It is not needed to display the plot - # It saves a lot of time - # self.plot.show() - # self.qWaitForWindowExposed(self.plot) - - def tearDown(self): - self.qapp.processEvents() - self.plot.setAttribute(qt.Qt.WA_DeleteOnClose) - self.plot.close() - del self.plot - super(TestPlotAxes, self).tearDown() - - def testDefaultAxes(self): - axis = self.plot.getXAxis() - self.assertEqual(axis.getScale(), axis.LINEAR) - axis = self.plot.getYAxis() - self.assertEqual(axis.getScale(), axis.LINEAR) - axis = self.plot.getYAxis(axis="right") - self.assertEqual(axis.getScale(), axis.LINEAR) - - def testOldPlotAxis_getterSetter(self): - """Test silx API prior to silx 0.6""" - x = self.plot.getXAxis() - y = self.plot.getYAxis() - p = self.plot - - tests = [ - # setters - (p.setGraphXLimits, (10, 20), x.getLimits, (10, 20)), - (p.setGraphYLimits, (10, 20), y.getLimits, (10, 20)), - (p.setGraphXLabel, "foox", x.getLabel, "foox"), - (p.setGraphYLabel, "fooy", y.getLabel, "fooy"), - (p.setYAxisInverted, True, y.isInverted, True), - (p.setXAxisLogarithmic, True, x.getScale, x.LOGARITHMIC), - (p.setYAxisLogarithmic, True, y.getScale, y.LOGARITHMIC), - (p.setXAxisAutoScale, False, x.isAutoScale, False), - (p.setYAxisAutoScale, False, y.isAutoScale, False), - # getters - (x.setLimits, (11, 20), p.getGraphXLimits, (11, 20)), - (y.setLimits, (11, 20), p.getGraphYLimits, (11, 20)), - (x.setLabel, "fooxx", p.getGraphXLabel, "fooxx"), - (y.setLabel, "fooyy", p.getGraphYLabel, "fooyy"), - (y.setInverted, False, p.isYAxisInverted, False), - (x.setScale, x.LINEAR, p.isXAxisLogarithmic, False), - (y.setScale, y.LINEAR, p.isYAxisLogarithmic, False), - (x.setAutoScale, True, p.isXAxisAutoScale, True), - (y.setAutoScale, True, p.isYAxisAutoScale, True), - ] - for testCase in tests: - setter, value, getter, expected = testCase - with self.subTest(): - if setter is not None: - if not isinstance(value, tuple): - value = (value, ) - setter(*value) - if getter is not None: - self.assertEqual(getter(), expected) - - def testOldPlotAxis_Logarithmic(self): - """Test silx API prior to silx 0.6""" - x = self.plot.getXAxis() - y = self.plot.getYAxis() - yright = self.plot.getYAxis(axis="right") - - self.assertEqual(x.getScale(), x.LINEAR) - self.assertEqual(y.getScale(), x.LINEAR) - self.assertEqual(yright.getScale(), x.LINEAR) - - self.plot.setXAxisLogarithmic(True) - self.assertEqual(x.getScale(), x.LOGARITHMIC) - self.assertEqual(y.getScale(), x.LINEAR) - self.assertEqual(yright.getScale(), x.LINEAR) - self.assertEqual(self.plot.isXAxisLogarithmic(), True) - self.assertEqual(self.plot.isYAxisLogarithmic(), False) - - self.plot.setYAxisLogarithmic(True) - self.assertEqual(x.getScale(), x.LOGARITHMIC) - self.assertEqual(y.getScale(), x.LOGARITHMIC) - self.assertEqual(yright.getScale(), x.LOGARITHMIC) - self.assertEqual(self.plot.isXAxisLogarithmic(), True) - self.assertEqual(self.plot.isYAxisLogarithmic(), True) - - yright.setScale(yright.LINEAR) - self.assertEqual(x.getScale(), x.LOGARITHMIC) - self.assertEqual(y.getScale(), x.LINEAR) - self.assertEqual(yright.getScale(), x.LINEAR) - self.assertEqual(self.plot.isXAxisLogarithmic(), True) - self.assertEqual(self.plot.isYAxisLogarithmic(), False) - - def testOldPlotAxis_AutoScale(self): - """Test silx API prior to silx 0.6""" - x = self.plot.getXAxis() - y = self.plot.getYAxis() - yright = self.plot.getYAxis(axis="right") - - self.assertEqual(x.isAutoScale(), True) - self.assertEqual(y.isAutoScale(), True) - self.assertEqual(yright.isAutoScale(), True) - - self.plot.setXAxisAutoScale(False) - self.assertEqual(x.isAutoScale(), False) - self.assertEqual(y.isAutoScale(), True) - self.assertEqual(yright.isAutoScale(), True) - self.assertEqual(self.plot.isXAxisAutoScale(), False) - self.assertEqual(self.plot.isYAxisAutoScale(), True) - - self.plot.setYAxisAutoScale(False) - self.assertEqual(x.isAutoScale(), False) - self.assertEqual(y.isAutoScale(), False) - self.assertEqual(yright.isAutoScale(), False) - self.assertEqual(self.plot.isXAxisAutoScale(), False) - self.assertEqual(self.plot.isYAxisAutoScale(), False) - - yright.setAutoScale(True) - self.assertEqual(x.isAutoScale(), False) - self.assertEqual(y.isAutoScale(), True) - self.assertEqual(yright.isAutoScale(), True) - self.assertEqual(self.plot.isXAxisAutoScale(), False) - self.assertEqual(self.plot.isYAxisAutoScale(), True) - - def testOldPlotAxis_Inverted(self): - """Test silx API prior to silx 0.6""" - x = self.plot.getXAxis() - y = self.plot.getYAxis() - yright = self.plot.getYAxis(axis="right") - - self.assertEqual(x.isInverted(), False) - self.assertEqual(y.isInverted(), False) - self.assertEqual(yright.isInverted(), False) - - self.plot.setYAxisInverted(True) - self.assertEqual(x.isInverted(), False) - self.assertEqual(y.isInverted(), True) - self.assertEqual(yright.isInverted(), True) - self.assertEqual(self.plot.isYAxisInverted(), True) - - yright.setInverted(False) - self.assertEqual(x.isInverted(), False) - self.assertEqual(y.isInverted(), False) - self.assertEqual(yright.isInverted(), False) - self.assertEqual(self.plot.isYAxisInverted(), False) - - def testLogXWithData(self): - self.plot.setGraphTitle('Curve X: Log Y: Linear') - self.plot.addCurve(self.xData, self.yData, - legend="curve", - replace=False, resetzoom=True, - color='green', linestyle="-", symbol='o') - axis = self.plot.getXAxis() - axis.setScale(axis.LOGARITHMIC) - - self.assertEqual(axis.getScale(), axis.LOGARITHMIC) - - def testLogYWithData(self): - self.plot.setGraphTitle('Curve X: Linear Y: Log') - self.plot.addCurve(self.xData, self.yData, - legend="curve", - replace=False, resetzoom=True, - color='green', linestyle="-", symbol='o') - axis = self.plot.getYAxis() - axis.setScale(axis.LOGARITHMIC) - - self.assertEqual(axis.getScale(), axis.LOGARITHMIC) - axis = self.plot.getYAxis(axis="right") - self.assertEqual(axis.getScale(), axis.LOGARITHMIC) - - def testLogYRightWithData(self): - self.plot.setGraphTitle('Curve X: Linear Y: Log') - self.plot.addCurve(self.xData, self.yData, - legend="curve", - replace=False, resetzoom=True, - color='green', linestyle="-", symbol='o') - axis = self.plot.getYAxis(axis="right") - axis.setScale(axis.LOGARITHMIC) - - self.assertEqual(axis.getScale(), axis.LOGARITHMIC) - axis = self.plot.getYAxis() - self.assertEqual(axis.getScale(), axis.LOGARITHMIC) - - def testLimitsChanged_setLimits(self): - self.plot.addCurve(self.xData, self.yData, - legend="curve", - replace=False, resetzoom=False, - color='green', linestyle="-", symbol='o') - listener = SignalListener() - self.plot.getXAxis().sigLimitsChanged.connect(listener.partial(axis="x")) - self.plot.getYAxis().sigLimitsChanged.connect(listener.partial(axis="y")) - self.plot.getYAxis(axis="right").sigLimitsChanged.connect(listener.partial(axis="y2")) - self.plot.setLimits(0, 1, 0, 1, 0, 1) - # at least one event per axis - self.assertEqual(len(set(listener.karguments(argumentName="axis"))), 3) - - def testLimitsChanged_resetZoom(self): - self.plot.addCurve(self.xData, self.yData, - legend="curve", - replace=False, resetzoom=False, - color='green', linestyle="-", symbol='o') - listener = SignalListener() - self.plot.getXAxis().sigLimitsChanged.connect(listener.partial(axis="x")) - self.plot.getYAxis().sigLimitsChanged.connect(listener.partial(axis="y")) - self.plot.getYAxis(axis="right").sigLimitsChanged.connect(listener.partial(axis="y2")) - self.plot.resetZoom() - # at least one event per axis - self.assertEqual(len(set(listener.karguments(argumentName="axis"))), 3) - - def testLimitsChanged_setXLimit(self): - self.plot.addCurve(self.xData, self.yData, - legend="curve", - replace=False, resetzoom=False, - color='green', linestyle="-", symbol='o') - listener = SignalListener() - axis = self.plot.getXAxis() - axis.sigLimitsChanged.connect(listener) - axis.setLimits(20, 30) - # at least one event per axis - self.assertEqual(listener.arguments(callIndex=-1), (20.0, 30.0)) - self.assertEqual(axis.getLimits(), (20.0, 30.0)) - - def testLimitsChanged_setYLimit(self): - self.plot.addCurve(self.xData, self.yData, - legend="curve", - replace=False, resetzoom=False, - color='green', linestyle="-", symbol='o') - listener = SignalListener() - axis = self.plot.getYAxis() - axis.sigLimitsChanged.connect(listener) - axis.setLimits(20, 30) - # at least one event per axis - self.assertEqual(listener.arguments(callIndex=-1), (20.0, 30.0)) - self.assertEqual(axis.getLimits(), (20.0, 30.0)) - - def testLimitsChanged_setYRightLimit(self): - self.plot.addCurve(self.xData, self.yData, - legend="curve", - replace=False, resetzoom=False, - color='green', linestyle="-", symbol='o') - listener = SignalListener() - axis = self.plot.getYAxis(axis="right") - axis.sigLimitsChanged.connect(listener) - axis.setLimits(20, 30) - # at least one event per axis - self.assertEqual(listener.arguments(callIndex=-1), (20.0, 30.0)) - self.assertEqual(axis.getLimits(), (20.0, 30.0)) - - def testScaleProxy(self): - listener = SignalListener() - y = self.plot.getYAxis() - yright = self.plot.getYAxis(axis="right") - y.sigScaleChanged.connect(listener.partial("left")) - yright.sigScaleChanged.connect(listener.partial("right")) - yright.setScale(yright.LOGARITHMIC) - - self.assertEqual(y.getScale(), y.LOGARITHMIC) - events = listener.arguments() - self.assertEqual(len(events), 2) - self.assertIn(("left", y.LOGARITHMIC), events) - self.assertIn(("right", y.LOGARITHMIC), events) - - def testAutoScaleProxy(self): - listener = SignalListener() - y = self.plot.getYAxis() - yright = self.plot.getYAxis(axis="right") - y.sigAutoScaleChanged.connect(listener.partial("left")) - yright.sigAutoScaleChanged.connect(listener.partial("right")) - yright.setAutoScale(False) - - self.assertEqual(y.isAutoScale(), False) - events = listener.arguments() - self.assertEqual(len(events), 2) - self.assertIn(("left", False), events) - self.assertIn(("right", False), events) - - def testInvertedProxy(self): - listener = SignalListener() - y = self.plot.getYAxis() - yright = self.plot.getYAxis(axis="right") - y.sigInvertedChanged.connect(listener.partial("left")) - yright.sigInvertedChanged.connect(listener.partial("right")) - yright.setInverted(True) - - self.assertEqual(y.isInverted(), True) - events = listener.arguments() - self.assertEqual(len(events), 2) - self.assertIn(("left", True), events) - self.assertIn(("right", True), events) - - def testAxesDisplayedFalse(self): - """Test coverage on setAxesDisplayed(False)""" - self.plot.setAxesDisplayed(False) - - def testAxesDisplayedTrue(self): - """Test coverage on setAxesDisplayed(True)""" - self.plot.setAxesDisplayed(True) - - def testAxesMargins(self): - """Test PlotWidget's getAxesMargins and setAxesMargins""" - self.plot.show() - self.qWaitForWindowExposed(self.plot) - - margins = self.plot.getAxesMargins() - self.assertEqual(margins, (.15, .1, .1, .15)) - - for margins in ((0., 0., 0., 0.), (.15, .1, .1, .15)): - with self.subTest(margins=margins): - self.plot.setAxesMargins(*margins) - self.qapp.processEvents() - self.assertEqual(self.plot.getAxesMargins(), margins) - - def testBoundingRectItem(self): - item = BoundingRect() - item.setBounds((-1000, 1000, -2000, 2000)) - self.plot.addItem(item) - self.plot.resetZoom() - limits = numpy.array(self.plot.getXAxis().getLimits()) - numpy.testing.assert_almost_equal(limits, numpy.array([-1000, 1000])) - limits = numpy.array(self.plot.getYAxis().getLimits()) - numpy.testing.assert_almost_equal(limits, numpy.array([-2000, 2000])) - - def testBoundingRectRightItem(self): - item = BoundingRect() - item.setYAxis("right") - item.setBounds((-1000, 1000, -2000, 2000)) - self.plot.addItem(item) - self.plot.resetZoom() - limits = numpy.array(self.plot.getXAxis().getLimits()) - numpy.testing.assert_almost_equal(limits, numpy.array([-1000, 1000])) - limits = numpy.array(self.plot.getYAxis("right").getLimits()) - numpy.testing.assert_almost_equal(limits, numpy.array([-2000, 2000])) - - def testBoundingRectArguments(self): - item = BoundingRect() - with self.assertRaises(Exception): - item.setBounds((1000, -1000, -2000, 2000)) - with self.assertRaises(Exception): - item.setBounds((-1000, 1000, 2000, -2000)) - - def testBoundingRectWithLog(self): - item = BoundingRect() - self.plot.addItem(item) - - item.setBounds((-1000, 1000, -2000, 2000)) - self.plot.getXAxis()._setLogarithmic(True) - self.plot.getYAxis()._setLogarithmic(False) - self.assertEqual(item.getBounds(), (1000, 1000, -2000, 2000)) - - item.setBounds((-1000, 1000, -2000, 2000)) - self.plot.getXAxis()._setLogarithmic(False) - self.plot.getYAxis()._setLogarithmic(True) - self.assertEqual(item.getBounds(), (-1000, 1000, 2000, 2000)) - - item.setBounds((-1000, 0, -2000, 2000)) - self.plot.getXAxis()._setLogarithmic(True) - 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""" - - # Test data - xData = numpy.arange(1000) + 1 - yData = xData ** 2 - - def _setLabels(self): - self.plot.getXAxis().setLabel('X') - self.plot.getYAxis().setLabel('X * X') - - def testPlotCurveLogX(self): - self._setLabels() - self.plot.getXAxis()._setLogarithmic(True) - self.plot.setGraphTitle('Curve X: Log Y: Linear') - - self.plot.addCurve(self.xData, self.yData, - legend="curve", - replace=False, resetzoom=True, - color='green', linestyle="-", symbol='o') - - def testPlotCurveLogY(self): - self._setLabels() - self.plot.getYAxis()._setLogarithmic(True) - - self.plot.setGraphTitle('Curve X: Linear Y: Log') - - self.plot.addCurve(self.xData, self.yData, - legend="curve", - replace=False, resetzoom=True, - color='green', linestyle="-", symbol='o') - - def testPlotCurveLogXY(self): - self._setLabels() - self.plot.getXAxis()._setLogarithmic(True) - self.plot.getYAxis()._setLogarithmic(True) - - self.plot.setGraphTitle('Curve X: Log Y: Log') - - self.plot.addCurve(self.xData, self.yData, - legend="curve", - replace=False, resetzoom=True, - color='green', linestyle="-", symbol='o') - - def testPlotCurveErrorLogXY(self): - self.plot.getXAxis()._setLogarithmic(True) - self.plot.getYAxis()._setLogarithmic(True) - - # Every second error leads to negative number - errors = numpy.ones_like(self.xData) - errors[::2] = self.xData[::2] + 1 - - tests = [ # name, xerror, yerror - ('xerror=3', 3, None), - ('xerror=N array', errors, None), - ('xerror=Nx1 array', errors.reshape(len(errors), 1), None), - ('xerror=2xN array', numpy.array((errors, errors)), None), - ('yerror=6', None, 6), - ('yerror=N array', None, errors ** 2), - ('yerror=Nx1 array', None, (errors ** 2).reshape(len(errors), 1)), - ('yerror=2xN array', None, numpy.array((errors, errors)) ** 2), - ] - - for name, xError, yError in tests: - with self.subTest(name): - self.plot.setGraphTitle(name) - self.plot.addCurve(self.xData, self.yData, - legend=name, - xerror=xError, yerror=yError, - replace=False, resetzoom=True, - color='green', linestyle="-", symbol='o') - - self.qapp.processEvents() - - self.plot.clear() - self.plot.resetZoom() - self.qapp.processEvents() - - def testPlotCurveToggleLog(self): - """Add a curve with negative data and toggle log axis""" - arange = numpy.arange(1000) + 1 - tests = [ # name, xData, yData - ('x>0, some negative y', arange, arange - 500), - ('x>0, y<0', arange, -arange), - ('some negative x, y>0', arange - 500, arange), - ('x<0, y>0', -arange, arange), - ('some negative x and y', arange - 500, arange - 500), - ('x<0, y<0', -arange, -arange), - ] - - for name, xData, yData in tests: - with self.subTest(name): - self.plot.addCurve(xData, yData, resetzoom=True) - self.qapp.processEvents() - - # no log axis - xLim = self.plot.getXAxis().getLimits() - self.assertEqual(xLim, (min(xData), max(xData))) - yLim = self.plot.getYAxis().getLimits() - self.assertEqual(yLim, (min(yData), max(yData))) - - # x axis log - self.plot.getXAxis()._setLogarithmic(True) - self.qapp.processEvents() - - xLim = self.plot.getXAxis().getLimits() - yLim = self.plot.getYAxis().getLimits() - positives = xData > 0 - if numpy.any(positives): - self.assertTrue(numpy.allclose( - xLim, (min(xData[positives]), max(xData[positives])))) - self.assertEqual( - yLim, (min(yData[positives]), max(yData[positives]))) - else: # No positive x in the curve - self.assertEqual(xLim, (1., 100.)) - self.assertEqual(yLim, (1., 100.)) - - # x axis and y axis log - self.plot.getYAxis()._setLogarithmic(True) - self.qapp.processEvents() - - xLim = self.plot.getXAxis().getLimits() - yLim = self.plot.getYAxis().getLimits() - positives = numpy.logical_and(xData > 0, yData > 0) - if numpy.any(positives): - self.assertTrue(numpy.allclose( - xLim, (min(xData[positives]), max(xData[positives])))) - self.assertTrue(numpy.allclose( - yLim, (min(yData[positives]), max(yData[positives])))) - else: # No positive x and y in the curve - self.assertEqual(xLim, (1., 100.)) - self.assertEqual(yLim, (1., 100.)) - - # y axis log - self.plot.getXAxis()._setLogarithmic(False) - self.qapp.processEvents() - - xLim = self.plot.getXAxis().getLimits() - yLim = self.plot.getYAxis().getLimits() - positives = yData > 0 - if numpy.any(positives): - self.assertEqual( - xLim, (min(xData[positives]), max(xData[positives]))) - self.assertTrue(numpy.allclose( - yLim, (min(yData[positives]), max(yData[positives])))) - else: # No positive y in the curve - self.assertEqual(xLim, (1., 100.)) - self.assertEqual(yLim, (1., 100.)) - - # no log axis - self.plot.getYAxis()._setLogarithmic(False) - self.qapp.processEvents() - - xLim = self.plot.getXAxis().getLimits() - self.assertEqual(xLim, (min(xData), max(xData))) - yLim = self.plot.getYAxis().getLimits() - self.assertEqual(yLim, (min(yData), max(yData))) - - self.plot.clear() - self.plot.resetZoom() - self.qapp.processEvents() - - -class TestPlotImageLog(PlotWidgetTestCase): - """Basic tests for addImage with log scale axes.""" - - def setUp(self): - super(TestPlotImageLog, self).setUp() - - self.plot.getXAxis().setLabel('Columns') - self.plot.getYAxis().setLabel('Rows') - - def testPlotColormapGrayLogX(self): - self.plot.getXAxis()._setLogarithmic(True) - self.plot.setGraphTitle('CMap X: Log Y: Linear') - - colormap = Colormap(name='gray', - normalization='linear', - vmin=None, - vmax=None) - self.plot.addImage(DATA_2D, legend="image 1", - origin=(1., 1.), scale=(1., 1.), - resetzoom=False, colormap=colormap) - self.plot.resetZoom() - - def testPlotColormapGrayLogY(self): - self.plot.getYAxis()._setLogarithmic(True) - self.plot.setGraphTitle('CMap X: Linear Y: Log') - - colormap = Colormap(name='gray', - normalization='linear', - vmin=None, - vmax=None) - self.plot.addImage(DATA_2D, legend="image 1", - origin=(1., 1.), scale=(1., 1.), - resetzoom=False, colormap=colormap) - self.plot.resetZoom() - - def testPlotColormapGrayLogXY(self): - self.plot.getXAxis()._setLogarithmic(True) - self.plot.getYAxis()._setLogarithmic(True) - self.plot.setGraphTitle('CMap X: Log Y: Log') - - colormap = Colormap(name='gray', - normalization='linear', - vmin=None, - vmax=None) - self.plot.addImage(DATA_2D, legend="image 1", - origin=(1., 1.), scale=(1., 1.), - resetzoom=False, colormap=colormap) - self.plot.resetZoom() - - def testPlotRgbRgbaLogXY(self): - self.plot.getXAxis()._setLogarithmic(True) - self.plot.getYAxis()._setLogarithmic(True) - self.plot.setGraphTitle('RGB + RGBA X: Log Y: Log') - - rgb = numpy.array( - (((0, 0, 0), (128, 0, 0), (255, 0, 0)), - ((0, 128, 0), (0, 128, 128), (0, 128, 256))), - dtype=numpy.uint8) - - self.plot.addImage(rgb, legend="rgb", - origin=(1, 1), scale=(10, 10), - resetzoom=False) - - rgba = numpy.array( - (((0, 0, 0, .5), (.5, 0, 0, 1), (1, 0, 0, .5)), - ((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.), - resetzoom=False) - self.plot.resetZoom() - - -class TestPlotMarkerLog(PlotWidgetTestCase): - """Basic tests for markers on log scales""" - - # Test marker parameters - markers = [ # x, y, color, selectable, draggable - (10., 10., 'blue', False, False), - (20., 20., 'red', False, False), - (40., 100., 'green', True, False), - (40., 500., 'gray', True, True), - (60., 800., 'black', False, True), - ] - - def setUp(self): - super(TestPlotMarkerLog, self).setUp() - - self.plot.getYAxis().setLabel('Rows') - self.plot.getXAxis().setLabel('Columns') - self.plot.getXAxis().setAutoScale(False) - self.plot.getYAxis().setAutoScale(False) - self.plot.setKeepDataAspectRatio(False) - self.plot.setLimits(1., 100., 1., 1000.) - self.plot.getXAxis()._setLogarithmic(True) - self.plot.getYAxis()._setLogarithmic(True) - - def testPlotMarkerXLog(self): - self.plot.setGraphTitle('Markers X, Log axes') - - for x, _, color, select, drag in self.markers: - name = str(x) - if select: - name += " sel." - if drag: - name += " drag" - self.plot.addXMarker(x, name, name, color, select, drag) - self.plot.resetZoom() - - def testPlotMarkerYLog(self): - self.plot.setGraphTitle('Markers Y, Log axes') - - for _, y, color, select, drag in self.markers: - name = str(y) - if select: - name += " sel." - if drag: - name += " drag" - self.plot.addYMarker(y, name, name, color, select, drag) - self.plot.resetZoom() - - def testPlotMarkerPtLog(self): - self.plot.setGraphTitle('Markers Pt, Log axes') - - for x, y, color, select, drag in self.markers: - name = "{0},{1}".format(x, y) - if select: - name += " sel." - if drag: - name += " drag" - self.plot.addMarker(x, y, name, name, color, select, drag) - self.plot.resetZoom() - - -class TestPlotWidgetSwitchBackend(PlotWidgetTestCase): - """Test [get|set]Backend to switch backend""" - - def testSwitchBackend(self): - """Test switching a plot with a few items""" - backends = {'none': 'BackendBase', 'mpl': 'BackendMatplotlibQt'} - if test_options.WITH_GL_TEST: - backends['gl'] = 'BackendOpenGL' - - self.plot.addImage(numpy.arange(100).reshape(10, 10)) - self.plot.addCurve((-3, -2, -1), (1, 2, 3)) - self.plot.resetZoom() - xlimits = self.plot.getXAxis().getLimits() - ylimits = self.plot.getYAxis().getLimits() - items = self.plot.getItems() - self.assertEqual(len(items), 2) - - for backend, className in backends.items(): - with self.subTest(backend=backend): - self.plot.setBackend(backend) - self.plot.replot() - - retrievedBackend = self.plot.getBackend() - self.assertEqual(type(retrievedBackend).__name__, className) - self.assertEqual(self.plot.getXAxis().getLimits(), xlimits) - self.assertEqual(self.plot.getYAxis().getLimits(), ylimits) - self.assertEqual(self.plot.getItems(), items) - - -class TestPlotWidgetSelection(PlotWidgetTestCase): - """Test PlotWidget.selection and active items handling""" - - def _checkSelection(self, selection, current=None, selected=()): - """Check current item and selected items.""" - self.assertIs(selection.getCurrentItem(), current) - self.assertEqual(selection.getSelectedItems(), selected) - - def testSyncWithActiveItems(self): - """Test update of PlotWidgetSelection according to active items""" - listener = SignalListener() - - selection = self.plot.selection() - selection.sigCurrentItemChanged.connect(listener) - self._checkSelection(selection) - - # Active item is current - self.plot.addImage(((0, 1), (2, 3)), legend='image') - image = self.plot.getActiveImage() - self.assertEqual(listener.callCount(), 1) - self._checkSelection(selection, image, (image,)) - - # No active = no current - self.plot.setActiveImage(None) - self.assertEqual(listener.callCount(), 2) - self._checkSelection(selection) - - # Active item is current - self.plot.setActiveImage('image') - self.assertEqual(listener.callCount(), 3) - self._checkSelection(selection, image, (image,)) - - # Mosted recently "actived" item is current - self.plot.addScatter((3, 2, 1), (0, 1, 2), (0, 1, 2), legend='scatter') - scatter = self.plot.getActiveScatter() - self.assertEqual(listener.callCount(), 4) - self._checkSelection(selection, scatter, (scatter, image)) - - # Previously mosted recently "actived" item is current - self.plot.setActiveScatter(None) - self.assertEqual(listener.callCount(), 5) - self._checkSelection(selection, image, (image,)) - - # Mosted recently "actived" item is current - self.plot.setActiveScatter('scatter') - self.assertEqual(listener.callCount(), 6) - self._checkSelection(selection, scatter, (scatter, image)) - - # No active = no current - self.plot.setActiveImage(None) - self.plot.setActiveScatter(None) - self.assertEqual(listener.callCount(), 7) - self._checkSelection(selection) - - # Mosted recently "actived" item is current - self.plot.setActiveScatter('scatter') - self.assertEqual(listener.callCount(), 8) - self.plot.setActiveImage('image') - self.assertEqual(listener.callCount(), 9) - self._checkSelection(selection, image, (image, scatter)) - - # Add a curve which is not active by default - self.plot.addCurve((0, 1, 2), (0, 1, 2), legend='curve') - curve = self.plot.getCurve('curve') - self.assertEqual(listener.callCount(), 9) - self._checkSelection(selection, image, (image, scatter)) - - # Mosted recently "actived" item is current - self.plot.setActiveCurve('curve') - self.assertEqual(listener.callCount(), 10) - self._checkSelection(selection, curve, (curve, image, scatter)) - - # Add a curve which is not active by default - self.plot.addCurve((0, 1, 2), (0, 1, 2), legend='curve2') - curve2 = self.plot.getCurve('curve2') - self.assertEqual(listener.callCount(), 10) - self._checkSelection(selection, curve, (curve, image, scatter)) - - # Mosted recently "actived" item is current, previous curve is removed - self.plot.setActiveCurve('curve2') - self.assertEqual(listener.callCount(), 11) - self._checkSelection(selection, curve2, (curve2, image, scatter)) - - # No items = no current - self.plot.clear() - self.assertEqual(listener.callCount(), 12) - self._checkSelection(selection) - - def testPlotWidgetWithItems(self): - """Test init of selection on a plot with items""" - self.plot.addImage(((0, 1), (2, 3)), legend='image') - self.plot.addScatter((3, 2, 1), (0, 1, 2), (0, 1, 2), legend='scatter') - self.plot.addCurve((0, 1, 2), (0, 1, 2), legend='curve') - self.plot.setActiveCurve('curve') - - selection = self.plot.selection() - self.assertIsNotNone(selection.getCurrentItem()) - selected = selection.getSelectedItems() - self.assertEqual(len(selected), 3) - self.assertIn(self.plot.getActiveCurve(), selected) - self.assertIn(self.plot.getActiveImage(), selected) - self.assertIn(self.plot.getActiveScatter(), selected) - - def testSetCurrentItem(self): - """Test setCurrentItem""" - # Add items to the plot - self.plot.addImage(((0, 1), (2, 3)), legend='image') - image = self.plot.getActiveImage() - self.plot.addScatter((3, 2, 1), (0, 1, 2), (0, 1, 2), legend='scatter') - scatter = self.plot.getActiveScatter() - self.plot.addCurve((0, 1, 2), (0, 1, 2), legend='curve') - self.plot.setActiveCurve('curve') - curve = self.plot.getActiveCurve() - - selection = self.plot.selection() - self.assertIsNotNone(selection.getCurrentItem()) - self.assertEqual(len(selection.getSelectedItems()), 3) - - # Set current to None reset all active items - selection.setCurrentItem(None) - self._checkSelection(selection) - self.assertIsNone(self.plot.getActiveCurve()) - self.assertIsNone(self.plot.getActiveImage()) - self.assertIsNone(self.plot.getActiveScatter()) - - # Set current to an item makes it active - selection.setCurrentItem(image) - self._checkSelection(selection, image, (image,)) - self.assertIsNone(self.plot.getActiveCurve()) - self.assertIs(self.plot.getActiveImage(), image) - self.assertIsNone(self.plot.getActiveScatter()) - - # Set current to an item makes it active and keeps other active - selection.setCurrentItem(curve) - self._checkSelection(selection, curve, (curve, image)) - self.assertIs(self.plot.getActiveCurve(), curve) - self.assertIs(self.plot.getActiveImage(), image) - self.assertIsNone(self.plot.getActiveScatter()) - - # Set current to an item makes it active and keeps other active - selection.setCurrentItem(scatter) - self._checkSelection(selection, scatter, (scatter, curve, image)) - self.assertIs(self.plot.getActiveCurve(), curve) - self.assertIs(self.plot.getActiveImage(), image) - self.assertIs(self.plot.getActiveScatter(), scatter) - - -def suite(): - testClasses = (TestPlotWidget, - TestPlotImage, - TestPlotCurve, - TestPlotHistogram, - TestPlotScatter, - TestPlotMarker, - TestPlotItem, - TestPlotAxes, - TestPlotActiveCurveImage, - TestPlotEmptyLog, - TestPlotCurveLog, - TestPlotImageLog, - TestPlotMarkerLog, - TestPlotWidgetSelection) - - test_suite = unittest.TestSuite() - - # Tests with matplotlib - for testClass in testClasses: - test_suite.addTest(parameterize(testClass, backend=None)) - - test_suite.addTest(parameterize(TestSpecialBackend, backend=u"mpl")) - if sys.version_info[0] == 2: - test_suite.addTest(parameterize(TestSpecialBackend, backend=b"mpl")) - - if test_options.WITH_GL_TEST: - # Tests with OpenGL backend - for testClass in testClasses: - test_suite.addTest(parameterize(testClass, backend='gl')) - - test_suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase( - TestPlotWidgetSwitchBackend)) - - return test_suite - - -if __name__ == '__main__': - unittest.main(defaultTest='suite') diff --git a/silx/gui/plot/test/testPlotWidgetNoBackend.py b/silx/gui/plot/test/testPlotWidgetNoBackend.py deleted file mode 100644 index edd3cd7..0000000 --- a/silx/gui/plot/test/testPlotWidgetNoBackend.py +++ /dev/null @@ -1,631 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# -# 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 -# 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 PlotWidget with 'none' backend""" - -__authors__ = ["T. Vincent"] -__license__ = "MIT" -__date__ = "17/01/2018" - - -import unittest -from functools import reduce -from silx.utils.testutils import ParametricTestCase - -import numpy - -from silx.gui.plot.PlotWidget import PlotWidget -from silx.gui.plot.items.histogram import _getHistogramCurve, _computeEdges - - -class TestPlot(unittest.TestCase): - """Basic tests of Plot without backend""" - - def testPlotTitleLabels(self): - """Create a Plot and set the labels""" - - plot = PlotWidget(backend='none') - - title, xlabel, ylabel = 'the title', 'x label', 'y label' - plot.setGraphTitle(title) - plot.getXAxis().setLabel(xlabel) - plot.getYAxis().setLabel(ylabel) - - self.assertEqual(plot.getGraphTitle(), title) - self.assertEqual(plot.getXAxis().getLabel(), xlabel) - self.assertEqual(plot.getYAxis().getLabel(), ylabel) - - def testAddNoRemove(self): - """add objects to the Plot""" - - plot = PlotWidget(backend='none') - plot.addCurve(x=(1, 2, 3), y=(3, 2, 1)) - plot.addImage(numpy.arange(100.).reshape(10, -1)) - plot.addShape(numpy.array((1., 10.)), - numpy.array((10., 10.)), - shape="rectangle") - plot.addXMarker(10.) - - -class TestPlotRanges(ParametricTestCase): - """Basic tests of Plot data ranges without backend""" - - _getValidValues = {True: lambda ar: ar > 0, - False: lambda ar: numpy.ones(shape=ar.shape, - dtype=bool)} - - @staticmethod - def _getRanges(arrays, are_logs): - gen = (TestPlotRanges._getValidValues[is_log](ar) - for (ar, is_log) in zip(arrays, are_logs)) - indices = numpy.where(reduce(numpy.logical_and, gen))[0] - if len(indices) > 0: - ranges = [(ar[indices[0]], ar[indices[-1]]) for ar in arrays] - else: - ranges = [None] * len(arrays) - - return ranges - - @staticmethod - def _getRangesMinmax(ranges): - # TODO : error if None in ranges. - rangeMin = numpy.min([rng[0] for rng in ranges]) - rangeMax = numpy.max([rng[1] for rng in ranges]) - return rangeMin, rangeMax - - def testDataRangeNoPlot(self): - """empty plot data range""" - - plot = PlotWidget(backend='none') - - for logX, logY in ((False, False), - (True, False), - (True, True), - (False, True), - (False, False)): - with self.subTest(logX=logX, logY=logY): - plot.getXAxis()._setLogarithmic(logX) - plot.getYAxis()._setLogarithmic(logY) - dataRange = plot.getDataRange() - self.assertIsNone(dataRange.x) - self.assertIsNone(dataRange.y) - self.assertIsNone(dataRange.yright) - - def testDataRangeLeft(self): - """left axis range""" - - plot = PlotWidget(backend='none') - - xData = numpy.arange(10) - 4.9 # range : -4.9 , 4.1 - yData = numpy.arange(10) - 6.9 # range : -6.9 , 2.1 - - plot.addCurve(x=xData, - y=yData, - legend='plot_0', - yaxis='left') - - for logX, logY in ((False, False), - (True, False), - (True, True), - (False, True), - (False, False)): - with self.subTest(logX=logX, logY=logY): - plot.getXAxis()._setLogarithmic(logX) - plot.getYAxis()._setLogarithmic(logY) - dataRange = plot.getDataRange() - xRange, yRange = self._getRanges([xData, yData], - [logX, logY]) - self.assertSequenceEqual(dataRange.x, xRange) - self.assertSequenceEqual(dataRange.y, yRange) - self.assertIsNone(dataRange.yright) - - def testDataRangeRight(self): - """right axis range""" - - plot = PlotWidget(backend='none') - xData = numpy.arange(10) - 4.9 # range : -4.9 , 4.1 - yData = numpy.arange(10) - 6.9 # range : -6.9 , 2.1 - plot.addCurve(x=xData, - y=yData, - legend='plot_0', - yaxis='right') - - for logX, logY in ((False, False), - (True, False), - (True, True), - (False, True), - (False, False)): - with self.subTest(logX=logX, logY=logY): - plot.getXAxis()._setLogarithmic(logX) - plot.getYAxis()._setLogarithmic(logY) - dataRange = plot.getDataRange() - xRange, yRange = self._getRanges([xData, yData], - [logX, logY]) - self.assertSequenceEqual(dataRange.x, xRange) - self.assertIsNone(dataRange.y) - self.assertSequenceEqual(dataRange.yright, yRange) - - def testDataRangeImage(self): - """image data range""" - - origin = (-10, 25) - scale = (3., 8.) - image = numpy.arange(100.).reshape(20, 5) - - plot = PlotWidget(backend='none') - plot.addImage(image, - origin=origin, scale=scale) - - xRange = numpy.array([0., image.shape[1] * scale[0]]) + origin[0] - yRange = numpy.array([0., image.shape[0] * scale[1]]) + origin[1] - - ranges = {(False, False): (xRange, yRange), - (True, False): (None, None), - (True, True): (None, None), - (False, True): (None, None)} - - for logX, logY in ((False, False), - (True, False), - (True, True), - (False, True), - (False, False)): - with self.subTest(logX=logX, logY=logY): - plot.getXAxis()._setLogarithmic(logX) - plot.getYAxis()._setLogarithmic(logY) - dataRange = plot.getDataRange() - xRange, yRange = ranges[logX, logY] - self.assertTrue(numpy.array_equal(dataRange.x, xRange), - msg='{0} != {1}'.format(dataRange.x, xRange)) - self.assertTrue(numpy.array_equal(dataRange.y, yRange), - msg='{0} != {1}'.format(dataRange.y, yRange)) - self.assertIsNone(dataRange.yright) - - def testDataRangeLeftRight(self): - """right+left axis range""" - - plot = PlotWidget(backend='none') - - xData_l = numpy.arange(10) - 0.9 # range : -0.9 , 8.1 - yData_l = numpy.arange(10) - 1.9 # range : -1.9 , 7.1 - plot.addCurve(x=xData_l, - y=yData_l, - legend='plot_l', - yaxis='left') - - xData_r = numpy.arange(10) - 4.9 # range : -4.9 , 4.1 - yData_r = numpy.arange(10) - 6.9 # range : -6.9 , 2.1 - plot.addCurve(x=xData_r, - y=yData_r, - legend='plot_r', - yaxis='right') - - for logX, logY in ((False, False), - (True, False), - (True, True), - (False, True), - (False, False)): - with self.subTest(logX=logX, logY=logY): - plot.getXAxis()._setLogarithmic(logX) - plot.getYAxis()._setLogarithmic(logY) - dataRange = plot.getDataRange() - xRangeL, yRangeL = self._getRanges([xData_l, yData_l], - [logX, logY]) - xRangeR, yRangeR = self._getRanges([xData_r, yData_r], - [logX, logY]) - xRangeLR = self._getRangesMinmax([xRangeL, xRangeR]) - self.assertSequenceEqual(dataRange.x, xRangeLR) - self.assertSequenceEqual(dataRange.y, yRangeL) - self.assertSequenceEqual(dataRange.yright, yRangeR) - - def testDataRangeCurveImage(self): - """right+left+image axis range""" - - # overlapping ranges : - # image sets x min and y max - # plot_left sets y min - # plot_right sets x max (and yright) - plot = PlotWidget(backend='none') - - origin = (-10, 5) - scale = (3., 8.) - image = numpy.arange(100.).reshape(20, 5) - - plot.addImage(image, - origin=origin, scale=scale, legend='image') - - xData_l = numpy.arange(10) - 0.9 # range : -0.9 , 8.1 - yData_l = numpy.arange(10) - 1.9 # range : -1.9 , 7.1 - plot.addCurve(x=xData_l, - y=yData_l, - legend='plot_l', - yaxis='left') - - xData_r = numpy.arange(10) + 4.1 # range : 4.1 , 13.1 - yData_r = numpy.arange(10) - 0.9 # range : -0.9 , 8.1 - plot.addCurve(x=xData_r, - y=yData_r, - legend='plot_r', - yaxis='right') - - imgXRange = numpy.array([0., image.shape[1] * scale[0]]) + origin[0] - imgYRange = numpy.array([0., image.shape[0] * scale[1]]) + origin[1] - - for logX, logY in ((False, False), - (True, False), - (True, True), - (False, True), - (False, False)): - with self.subTest(logX=logX, logY=logY): - plot.getXAxis()._setLogarithmic(logX) - plot.getYAxis()._setLogarithmic(logY) - dataRange = plot.getDataRange() - xRangeL, yRangeL = self._getRanges([xData_l, yData_l], - [logX, logY]) - xRangeR, yRangeR = self._getRanges([xData_r, yData_r], - [logX, logY]) - if logX or logY: - xRangeLR = self._getRangesMinmax([xRangeL, xRangeR]) - else: - xRangeLR = self._getRangesMinmax([xRangeL, - xRangeR, - imgXRange]) - yRangeL = self._getRangesMinmax([yRangeL, imgYRange]) - self.assertSequenceEqual(dataRange.x, xRangeLR) - self.assertSequenceEqual(dataRange.y, yRangeL) - self.assertSequenceEqual(dataRange.yright, yRangeR) - - def testDataRangeImageNegativeScaleX(self): - """image data range, negative scale""" - - origin = (-10, 25) - scale = (-3., 8.) - image = numpy.arange(100.).reshape(20, 5) - - plot = PlotWidget(backend='none') - plot.addImage(image, - origin=origin, scale=scale) - - xRange = numpy.array([0., image.shape[1] * scale[0]]) + origin[0] - xRange.sort() # negative scale! - yRange = numpy.array([0., image.shape[0] * scale[1]]) + origin[1] - - ranges = {(False, False): (xRange, yRange), - (True, False): (None, None), - (True, True): (None, None), - (False, True): (None, None)} - - for logX, logY in ((False, False), - (True, False), - (True, True), - (False, True), - (False, False)): - with self.subTest(logX=logX, logY=logY): - plot.getXAxis()._setLogarithmic(logX) - plot.getYAxis()._setLogarithmic(logY) - dataRange = plot.getDataRange() - xRange, yRange = ranges[logX, logY] - self.assertTrue(numpy.array_equal(dataRange.x, xRange), - msg='{0} != {1}'.format(dataRange.x, xRange)) - self.assertTrue(numpy.array_equal(dataRange.y, yRange), - msg='{0} != {1}'.format(dataRange.y, yRange)) - self.assertIsNone(dataRange.yright) - - def testDataRangeImageNegativeScaleY(self): - """image data range, negative scale""" - - origin = (-10, 25) - scale = (3., -8.) - image = numpy.arange(100.).reshape(20, 5) - - plot = PlotWidget(backend='none') - plot.addImage(image, - origin=origin, scale=scale) - - xRange = numpy.array([0., image.shape[1] * scale[0]]) + origin[0] - yRange = numpy.array([0., image.shape[0] * scale[1]]) + origin[1] - yRange.sort() # negative scale! - - ranges = {(False, False): (xRange, yRange), - (True, False): (None, None), - (True, True): (None, None), - (False, True): (None, None)} - - for logX, logY in ((False, False), - (True, False), - (True, True), - (False, True), - (False, False)): - with self.subTest(logX=logX, logY=logY): - plot.getXAxis()._setLogarithmic(logX) - plot.getYAxis()._setLogarithmic(logY) - dataRange = plot.getDataRange() - xRange, yRange = ranges[logX, logY] - self.assertTrue(numpy.array_equal(dataRange.x, xRange), - msg='{0} != {1}'.format(dataRange.x, xRange)) - self.assertTrue(numpy.array_equal(dataRange.y, yRange), - msg='{0} != {1}'.format(dataRange.y, yRange)) - self.assertIsNone(dataRange.yright) - - def testDataRangeHiddenCurve(self): - """curves with a hidden curve""" - plot = PlotWidget(backend='none') - plot.addCurve((0, 1), (0, 1), legend='shown') - plot.addCurve((0, 1, 2), (5, 5, 5), legend='hidden') - range1 = plot.getDataRange() - self.assertEqual(range1.x, (0, 2)) - self.assertEqual(range1.y, (0, 5)) - plot.hideCurve('hidden') - range2 = plot.getDataRange() - self.assertEqual(range2.x, (0, 1)) - self.assertEqual(range2.y, (0, 1)) - - -class TestPlotGetCurveImage(unittest.TestCase): - """Test of plot getCurve and getImage methods""" - - def testGetCurve(self): - """PlotWidget.getCurve and Plot.getActiveCurve tests""" - - plot = PlotWidget(backend='none') - - # No curve - curve = plot.getCurve() - self.assertIsNone(curve) # No curve - - plot.setActiveCurveHandling(True) - plot.addCurve(x=(0, 1), y=(0, 1), legend='curve 0') - plot.addCurve(x=(0, 1), y=(0, 1), legend='curve 1') - plot.addCurve(x=(0, 1), y=(0, 1), legend='curve 2') - plot.setActiveCurve('curve 0') - - # Active curve - active = plot.getActiveCurve() - self.assertEqual(active.getName(), 'curve 0') - curve = plot.getCurve() - 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.getName(), 'curve 2') # Last added curve - - # Last curve hidden - plot.hideCurve('curve 2', True) - curve = plot.getCurve() - self.assertEqual(curve.getName(), 'curve 1') # Last added curve - - # All curves hidden - plot.hideCurve('curve 1', True) - plot.hideCurve('curve 0', True) - curve = plot.getCurve() - self.assertIsNone(curve) - - def testGetCurveOldApi(self): - """old API PlotWidget.getCurve and Plot.getActiveCurve tests""" - - plot = PlotWidget(backend='none') - - # No curve - curve = plot.getCurve() - self.assertIsNone(curve) # No curve - - plot.setActiveCurveHandling(True) - x = numpy.arange(10.).astype(numpy.float32) - y = x * x - plot.addCurve(x=x, y=y, legend='curve 0', info=["whatever"]) - plot.addCurve(x=x, y=2*x, legend='curve 1', info="anything") - plot.setActiveCurve('curve 0') - - # Active curve (4 elements) - xOut, yOut, legend, info = plot.getActiveCurve()[:4] - self.assertEqual(legend, 'curve 0') - self.assertTrue(numpy.allclose(xOut, x), 'curve 0 wrong x data') - self.assertTrue(numpy.allclose(yOut, y), 'curve 0 wrong y data') - - # Active curve (5 elements) - xOut, yOut, legend, info, params = plot.getCurve("curve 1") - self.assertEqual(legend, 'curve 1') - self.assertEqual(info, 'anything') - self.assertTrue(numpy.allclose(xOut, x), 'curve 1 wrong x data') - self.assertTrue(numpy.allclose(yOut, 2 * x), 'curve 1 wrong y data') - - def testGetImage(self): - """PlotWidget.getImage and PlotWidget.getActiveImage tests""" - - plot = PlotWidget(backend='none') - - # No image - image = plot.getImage() - self.assertIsNone(image) - - plot.addImage(((0, 1), (2, 3)), legend='image 0') - plot.addImage(((0, 1), (2, 3)), legend='image 1') - - # Active image - active = plot.getActiveImage() - self.assertEqual(active.getName(), 'image 0') - image = plot.getImage() - self.assertEqual(image.getName(), 'image 0') - - # No active image - plot.addImage(((0, 1), (2, 3)), legend='image 2') - plot.setActiveImage(None) - active = plot.getActiveImage() - self.assertIsNone(active) - image = plot.getImage() - self.assertEqual(image.getName(), 'image 2') - - # Active image - plot.setActiveImage('image 1') - active = plot.getActiveImage() - self.assertEqual(active.getName(), 'image 1') - image = plot.getImage() - self.assertEqual(image.getName(), 'image 1') - - def testGetImageOldApi(self): - """PlotWidget.getImage and PlotWidget.getActiveImage old API tests""" - - plot = PlotWidget(backend='none') - - # No image - image = plot.getImage() - self.assertIsNone(image) - - image = numpy.arange(10).astype(numpy.float32) - image.shape = 5, 2 - - plot.addImage(image, legend='image 0', info=["Hi!"]) - - # Active image - data, legend, info, something, params = plot.getActiveImage() - self.assertEqual(legend, 'image 0') - self.assertEqual(info, ["Hi!"]) - self.assertTrue(numpy.allclose(data, image), "image 0 data not correct") - - def testGetAllImages(self): - """PlotWidget.getAllImages test""" - - plot = PlotWidget(backend='none') - - # No image - images = plot.getAllImages() - self.assertEqual(len(images), 0) - - # 2 images - data = numpy.arange(100).reshape(10, 10) - plot.addImage(data, legend='1') - plot.addImage(data, origin=(10, 10), legend='2') - images = plot.getAllImages(just_legend=True) - self.assertEqual(list(images), ['1', '2']) - images = plot.getAllImages(just_legend=False) - self.assertEqual(len(images), 2) - self.assertEqual(images[0].getName(), '1') - self.assertEqual(images[1].getName(), '2') - - -class TestPlotAddScatter(unittest.TestCase): - """Test of plot addScatter""" - - def testAddGetScatter(self): - - plot = PlotWidget(backend='none') - - # No curve - scatter = plot._getItem(kind="scatter") - self.assertIsNone(scatter) # No curve - - 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') - plot._setActiveItem('scatter', 'scatter 0') - - # Active scatter - active = plot._getActiveItem(kind='scatter') - self.assertEqual(active.getName(), 'scatter 0') - - # check default values - self.assertAlmostEqual(active.getSymbolSize(), active._DEFAULT_SYMBOL_SIZE) - self.assertEqual(active.getSymbol(), "o") - self.assertAlmostEqual(active.getAlpha(), 1.0) - - # modify parameters - active.setSymbolSize(20.5) - active.setSymbol("d") - active.setAlpha(0.777) - - s0 = plot.getScatter("scatter 0") - - self.assertAlmostEqual(s0.getSymbolSize(), 20.5) - self.assertEqual(s0.getSymbol(), "d") - self.assertAlmostEqual(s0.getAlpha(), 0.777) - - scatter1 = plot._getItem(kind='scatter', legend='scatter 1') - self.assertEqual(scatter1.getName(), 'scatter 1') - - def testGetAllScatters(self): - """PlotWidget.getAllImages test""" - - plot = PlotWidget(backend='none') - - 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') - - 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): - """Basic tests for histogram.""" - - def testEdges(self): - x = numpy.array([0, 1, 2]) - edgesRight = numpy.array([0, 1, 2, 3]) - edgesLeft = numpy.array([-1, 0, 1, 2]) - edgesCenter = numpy.array([-0.5, 0.5, 1.5, 2.5]) - - # testing x values for right - edges = _computeEdges(x, 'right') - numpy.testing.assert_array_equal(edges, edgesRight) - - edges = _computeEdges(x, 'center') - numpy.testing.assert_array_equal(edges, edgesCenter) - - edges = _computeEdges(x, 'left') - numpy.testing.assert_array_equal(edges, edgesLeft) - - def testHistogramCurve(self): - y = numpy.array([3, 2, 5]) - edges = numpy.array([0, 1, 2, 3]) - - xHisto, yHisto = _getHistogramCurve(y, edges) - numpy.testing.assert_array_equal( - yHisto, numpy.array([3, 3, 2, 2, 5, 5])) - - y = numpy.array([-3, 2, 5, 0]) - edges = numpy.array([-2, -1, 0, 1, 2]) - xHisto, yHisto = _getHistogramCurve(y, edges) - numpy.testing.assert_array_equal( - yHisto, numpy.array([-3, -3, 2, 2, 5, 5, 0, 0])) - - -def suite(): - test_suite = unittest.TestSuite() - for TestClass in (TestPlot, TestPlotRanges, TestPlotGetCurveImage, - TestPlotHistogram, TestPlotAddScatter): - test_suite.addTest( - unittest.defaultTestLoader.loadTestsFromTestCase(TestClass)) - return test_suite - - -if __name__ == '__main__': - unittest.main(defaultTest='suite') diff --git a/silx/gui/plot/test/testPlotWindow.py b/silx/gui/plot/test/testPlotWindow.py deleted file mode 100644 index e12b756..0000000 --- a/silx/gui/plot/test/testPlotWindow.py +++ /dev/null @@ -1,185 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# -# 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 -# 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 PlotWindow""" - -__authors__ = ["T. Vincent"] -__license__ = "MIT" -__date__ = "27/06/2017" - - -import unittest -import numpy - -from silx.gui.utils.testutils import TestCaseQt, getQToolButtonFromAction -from silx.test.utils import test_options - -from silx.gui import qt -from silx.gui.plot import PlotWindow -from silx.gui.colors import Colormap - -class TestPlotWindow(TestCaseQt): - """Base class for tests of PlotWindow.""" - - def setUp(self): - super(TestPlotWindow, self).setUp() - self.plot = PlotWindow() - self.plot.show() - self.qWaitForWindowExposed(self.plot) - - def tearDown(self): - self.plot.setAttribute(qt.Qt.WA_DeleteOnClose) - self.plot.close() - del self.plot - super(TestPlotWindow, self).tearDown() - - def testActions(self): - """Test the actions QToolButtons""" - self.plot.setLimits(1, 100, 1, 100) - - checkList = [ # QAction, Plot state getter - (self.plot.xAxisAutoScaleAction, self.plot.getXAxis().isAutoScale), - (self.plot.yAxisAutoScaleAction, self.plot.getYAxis().isAutoScale), - (self.plot.xAxisLogarithmicAction, self.plot.getXAxis()._isLogarithmic), - (self.plot.yAxisLogarithmicAction, self.plot.getYAxis()._isLogarithmic), - (self.plot.gridAction, self.plot.getGraphGrid), - ] - - for action, getter in checkList: - self.mouseMove(self.plot) - initialState = getter() - toolButton = getQToolButtonFromAction(action) - self.assertIsNot(toolButton, None) - self.mouseClick(toolButton, qt.Qt.LeftButton) - self.assertNotEqual(getter(), initialState, - msg='"%s" state not changed' % action.text()) - - self.mouseClick(toolButton, qt.Qt.LeftButton) - self.assertEqual(getter(), initialState, - msg='"%s" state not changed' % action.text()) - - # Trigger a zoom reset - self.mouseMove(self.plot) - resetZoomAction = self.plot.resetZoomAction - toolButton = getQToolButtonFromAction(resetZoomAction) - 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() - self.assertTrue(self.plot.isKeepDataAspectRatio()) - self.plot.keepDataAspectRatioButton.dontKeepDataAspectRatio() - self.assertFalse(self.plot.isKeepDataAspectRatio()) - - def testToolYAxisOrigin(self): - self.plot.toolBar() - self.plot.yAxisInvertedButton.setYAxisUpward() - self.assertFalse(self.plot.getYAxis().isInverted()) - 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 - - @unittest.skipUnless(test_options.WITH_GL_TEST, - test_options.WITH_QT_TEST_REASON) - def testSwitchBackend(self): - """Test switching an empty plot""" - self.plot.resetZoom() - xlimits = self.plot.getXAxis().getLimits() - ylimits = self.plot.getYAxis().getLimits() - isKeepAspectRatio = self.plot.isKeepDataAspectRatio() - - for backend in ('gl', 'mpl'): - with self.subTest(): - self.plot.setBackend(backend) - self.plot.replot() - self.assertEqual(self.plot.getXAxis().getLimits(), xlimits) - self.assertEqual(self.plot.getYAxis().getLimits(), ylimits) - self.assertEqual( - self.plot.isKeepDataAspectRatio(), isKeepAspectRatio) - - -def suite(): - test_suite = unittest.TestSuite() - test_suite.addTest( - unittest.defaultTestLoader.loadTestsFromTestCase(TestPlotWindow)) - return test_suite - - -if __name__ == '__main__': - unittest.main(defaultTest='suite') diff --git a/silx/gui/plot/test/testRoiStatsWidget.py b/silx/gui/plot/test/testRoiStatsWidget.py deleted file mode 100644 index 378d499..0000000 --- a/silx/gui/plot/test/testRoiStatsWidget.py +++ /dev/null @@ -1,290 +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. -# -# ###########################################################################*/ -"""Tests for ROIStatsWidget""" - - -from silx.gui.utils.testutils import TestCaseQt -from silx.gui import qt -from silx.gui.plot import PlotWindow -from silx.gui.plot.stats.stats import Stats -from silx.gui.plot.ROIStatsWidget import ROIStatsWidget -from silx.gui.plot.CurvesROIWidget import ROI -from silx.gui.plot.items.roi import RectangleROI, PolygonROI -from silx.gui.plot.StatsWidget import UpdateMode -import unittest -import numpy - - - -class _TestRoiStatsBase(TestCaseQt): - """Base class for several unittest relative to ROIStatsWidget""" - def setUp(self): - TestCaseQt.setUp(self) - # define plot - self.plot = PlotWindow() - self.plot.addImage(numpy.arange(10000).reshape(100, 100), - legend='img1') - self.img_item = self.plot.getImage('img1') - self.plot.addCurve(x=numpy.linspace(0, 10, 56), y=numpy.arange(56), - legend='curve1') - self.curve_item = self.plot.getCurve('curve1') - self.plot.addHistogram(edges=numpy.linspace(0, 10, 56), - histogram=numpy.arange(56), legend='histo1') - self.histogram_item = self.plot.getHistogram(legend='histo1') - self.plot.addScatter(x=numpy.linspace(0, 10, 56), - y=numpy.linspace(0, 10, 56), - value=numpy.arange(56), - legend='scatter1') - self.scatter_item = self.plot.getScatter(legend='scatter1') - - # stats widget - self.statsWidget = ROIStatsWidget(plot=self.plot) - - # define stats - stats = [ - ('sum', numpy.sum), - ('mean', numpy.mean), - ] - self.statsWidget.setStats(stats=stats) - - # define rois - self.roi1D = ROI(name='range1', fromdata=0, todata=4, type_='energy') - self.rectangle_roi = RectangleROI() - self.rectangle_roi.setGeometry(origin=(0, 0), size=(20, 20)) - self.rectangle_roi.setName('Initial ROI') - self.polygon_roi = PolygonROI() - points = numpy.array([[0, 5], [5, 0], [10, 5], [5, 10]]) - self.polygon_roi.setPoints(points) - - def statsTable(self): - return self.statsWidget._statsROITable - - def tearDown(self): - Stats._getContext.cache_clear() - self.statsWidget.setAttribute(qt.Qt.WA_DeleteOnClose, True) - self.statsWidget.close() - self.statsWidget = None - self.plot.setAttribute(qt.Qt.WA_DeleteOnClose, True) - self.plot.close() - self.plot = None - TestCaseQt.tearDown(self) - - -class TestRoiStatsCouple(_TestRoiStatsBase): - """ - Test different possible couple (roi, plotItem). - Check that: - - * computation is correct if couple is valid - * raise an error if couple is invalid - """ - def testROICurve(self): - """ - Test that the couple (ROI, curveItem) can be used for stats - """ - item = self.statsWidget.addItem(roi=self.roi1D, - plotItem=self.curve_item) - assert item is not None - tableItems = self.statsTable()._itemToTableItems(item) - self.assertEqual(tableItems['sum'].text(), '253') - self.assertEqual(tableItems['mean'].text(), '11.0') - - def testRectangleImage(self): - """ - Test that the couple (RectangleROI, imageItem) can be used for stats - """ - item = self.statsWidget.addItem(roi=self.rectangle_roi, - plotItem=self.img_item) - assert item is not None - self.plot.addImage(numpy.ones(10000).reshape(100, 100), - legend='img1') - self.qapp.processEvents() - tableItems = self.statsTable()._itemToTableItems(item) - self.assertEqual(tableItems['sum'].text(), str(float(21*21))) - self.assertEqual(tableItems['mean'].text(), '1.0') - - def testPolygonImage(self): - """ - Test that the couple (PolygonROI, imageItem) can be used for stats - """ - item = self.statsWidget.addItem(roi=self.polygon_roi, - plotItem=self.img_item) - assert item is not None - tableItems = self.statsTable()._itemToTableItems(item) - self.assertEqual(tableItems['sum'].text(), '22750') - self.assertEqual(tableItems['mean'].text(), '455.0') - - def testROIImage(self): - """ - Test that the couple (ROI, imageItem) is raising an error - """ - with self.assertRaises(TypeError): - self.statsWidget.addItem(roi=self.roi1D, - plotItem=self.img_item) - - def testRectangleCurve(self): - """ - Test that the couple (rectangleROI, curveItem) is raising an error - """ - with self.assertRaises(TypeError): - self.statsWidget.addItem(roi=self.rectangle_roi, - plotItem=self.curve_item) - - def testROIHistogram(self): - """ - Test that the couple (PolygonROI, imageItem) can be used for stats - """ - item = self.statsWidget.addItem(roi=self.roi1D, - plotItem=self.histogram_item) - assert item is not None - tableItems = self.statsTable()._itemToTableItems(item) - self.assertEqual(tableItems['sum'].text(), '253') - self.assertEqual(tableItems['mean'].text(), '11.0') - - def testROIScatter(self): - """ - Test that the couple (PolygonROI, imageItem) can be used for stats - """ - item = self.statsWidget.addItem(roi=self.roi1D, - plotItem=self.scatter_item) - assert item is not None - tableItems = self.statsTable()._itemToTableItems(item) - self.assertEqual(tableItems['sum'].text(), '253') - self.assertEqual(tableItems['mean'].text(), '11.0') - - -class TestRoiStatsAddRemoveItem(_TestRoiStatsBase): - """Test adding and removing (roi, plotItem) items""" - def testAddRemoveItems(self): - item1 = self.statsWidget.addItem(roi=self.roi1D, - plotItem=self.scatter_item) - self.assertTrue(item1 is not None) - self.assertEqual(self.statsTable().rowCount(), 1) - item2 = self.statsWidget.addItem(roi=self.roi1D, - plotItem=self.histogram_item) - self.assertTrue(item2 is not None) - self.assertEqual(self.statsTable().rowCount(), 2) - # try to add twice the same item - item3 = self.statsWidget.addItem(roi=self.roi1D, - plotItem=self.histogram_item) - self.assertTrue(item3 is None) - self.assertEqual(self.statsTable().rowCount(), 2) - item4 = self.statsWidget.addItem(roi=self.roi1D, - plotItem=self.curve_item) - self.assertTrue(item4 is not None) - self.assertEqual(self.statsTable().rowCount(), 3) - - self.statsWidget.removeItem(plotItem=item4._plot_item, - roi=item4._roi) - self.assertEqual(self.statsTable().rowCount(), 2) - # try to remove twice the same item - self.statsWidget.removeItem(plotItem=item4._plot_item, - roi=item4._roi) - self.assertEqual(self.statsTable().rowCount(), 2) - self.statsWidget.removeItem(plotItem=item2._plot_item, - roi=item2._roi) - self.statsWidget.removeItem(plotItem=item1._plot_item, - roi=item1._roi) - self.assertEqual(self.statsTable().rowCount(), 0) - - -class TestRoiStatsRoiUpdate(_TestRoiStatsBase): - """Test that the stats will be updated if the roi is updated""" - def testChangeRoi(self): - item = self.statsWidget.addItem(roi=self.rectangle_roi, - plotItem=self.img_item) - assert item is not None - tableItems = self.statsTable()._itemToTableItems(item) - self.assertEqual(tableItems['sum'].text(), '445410') - self.assertEqual(tableItems['mean'].text(), '1010.0') - - # update roi - self.rectangle_roi.setOrigin(position=(10, 10)) - self.assertNotEqual(tableItems['sum'].text(), '445410') - self.assertNotEqual(tableItems['mean'].text(), '1010.0') - - def testUpdateModeScenario(self): - """Test update according to a simple scenario""" - self.statsWidget._setUpdateMode(UpdateMode.AUTO) - item = self.statsWidget.addItem(roi=self.rectangle_roi, - plotItem=self.img_item) - - assert item is not None - tableItems = self.statsTable()._itemToTableItems(item) - self.assertEqual(tableItems['sum'].text(), '445410') - self.assertEqual(tableItems['mean'].text(), '1010.0') - self.statsWidget._setUpdateMode(UpdateMode.MANUAL) - self.rectangle_roi.setOrigin(position=(10, 10)) - self.qapp.processEvents() - self.assertNotEqual(tableItems['sum'].text(), '445410') - self.assertNotEqual(tableItems['mean'].text(), '1010.0') - self.statsWidget._updateAllStats(is_request=True) - self.assertNotEqual(tableItems['sum'].text(), '445410') - self.assertNotEqual(tableItems['mean'].text(), '1010.0') - - -class TestRoiStatsPlotItemUpdate(_TestRoiStatsBase): - """Test that the stats will be updated if the plot item is updated""" - def testChangeImage(self): - self.statsWidget._setUpdateMode(UpdateMode.AUTO) - item = self.statsWidget.addItem(roi=self.rectangle_roi, - plotItem=self.img_item) - - assert item is not None - tableItems = self.statsTable()._itemToTableItems(item) - self.assertEqual(tableItems['mean'].text(), '1010.0') - - # update plot - self.plot.addImage(numpy.arange(100, 10100).reshape(100, 100), - legend='img1') - self.assertNotEqual(tableItems['mean'].text(), '1059.5') - - def testUpdateModeScenario(self): - """Test update according to a simple scenario""" - self.statsWidget._setUpdateMode(UpdateMode.MANUAL) - item = self.statsWidget.addItem(roi=self.rectangle_roi, - plotItem=self.img_item) - - assert item is not None - tableItems = self.statsTable()._itemToTableItems(item) - self.assertEqual(tableItems['mean'].text(), '1010.0') - self.plot.addImage(numpy.arange(100, 10100).reshape(100, 100), - legend='img1') - self.assertEqual(tableItems['mean'].text(), '1010.0') - self.statsWidget._updateAllStats(is_request=True) - self.assertEqual(tableItems['mean'].text(), '1110.0') - - -def suite(): - test_suite = unittest.TestSuite() - for TestClass in (TestRoiStatsCouple, TestRoiStatsRoiUpdate, - TestRoiStatsPlotItemUpdate): - test_suite.addTest( - unittest.defaultTestLoader.loadTestsFromTestCase(TestClass)) - return test_suite - - -if __name__ == '__main__': - unittest.main(defaultTest='suite') diff --git a/silx/gui/plot/test/testSaveAction.py b/silx/gui/plot/test/testSaveAction.py deleted file mode 100644 index 0eb129d..0000000 --- a/silx/gui/plot/test/testSaveAction.py +++ /dev/null @@ -1,143 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# -# Copyright (c) 2017-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. -# -# ###########################################################################*/ -"""Test the plot's save action (consistency of output)""" - -__authors__ = ["P. Knobel"] -__license__ = "MIT" -__date__ = "28/11/2017" - - -import unittest -import tempfile -import os - -from silx.gui.plot.test.utils import PlotWidgetTestCase - -from silx.gui.plot import PlotWidget -from silx.gui.plot.actions.io import SaveAction - - -class TestSaveActionSaveCurvesAsSpec(unittest.TestCase): - - def setUp(self): - self.plot = PlotWidget(backend='none') - self.saveAction = SaveAction(plot=self.plot) - - self.tempdir = tempfile.mkdtemp() - self.out_fname = os.path.join(self.tempdir, "out.dat") - - def tearDown(self): - os.unlink(self.out_fname) - os.rmdir(self.tempdir) - - def testSaveMultipleCurvesAsSpec(self): - """Test that labels are properly used.""" - self.plot.setGraphXLabel("graph x label") - self.plot.setGraphYLabel("graph y label") - - self.plot.addCurve([0, 1], [1, 2], "curve with labels", - xlabel="curve0 X", ylabel="curve0 Y") - self.plot.addCurve([-1, 3], [-6, 2], "curve with X label", - xlabel="curve1 X") - self.plot.addCurve([-2, 0], [8, 12], "curve with Y label", - ylabel="curve2 Y") - self.plot.addCurve([3, 1], [7, 6], "curve with no labels") - - self.saveAction._saveCurves(self.plot, - self.out_fname, - SaveAction.DEFAULT_ALL_CURVES_FILTERS[0]) # "All curves as SpecFile (*.dat)" - - with open(self.out_fname, "rb") as f: - file_content = f.read() - if hasattr(file_content, "decode"): - file_content = file_content.decode() - - # case with all curve labels specified - self.assertIn("#S 1 curve0 Y", file_content) - self.assertIn("#L curve0 X curve0 Y", file_content) - - # graph X&Y labels are used when no curve label is specified - self.assertIn("#S 2 graph y label", file_content) - self.assertIn("#L curve1 X graph y label", file_content) - - self.assertIn("#S 3 curve2 Y", file_content) - self.assertIn("#L graph x label curve2 Y", file_content) - - self.assertIn("#S 4 graph y label", file_content) - self.assertIn("#L graph x label graph y label", file_content) - - -class TestSaveActionExtension(PlotWidgetTestCase): - """Test SaveAction file filter API""" - - def _dummySaveFunction(self, plot, filename, nameFilter): - pass - - def testFileFilterAPI(self): - """Test addition/update of a file filter""" - saveAction = SaveAction(plot=self.plot, parent=self.plot) - - # Add a new file filter - nameFilter = 'Dummy file (*.dummy)' - saveAction.setFileFilter('all', nameFilter, self._dummySaveFunction) - self.assertTrue(nameFilter in saveAction.getFileFilters('all')) - self.assertEqual(saveAction.getFileFilters('all')[nameFilter], - self._dummySaveFunction) - - # Add a new file filter at a particular position - nameFilter = 'Dummy file2 (*.dummy)' - saveAction.setFileFilter('all', nameFilter, - self._dummySaveFunction, index=3) - self.assertTrue(nameFilter in saveAction.getFileFilters('all')) - filters = saveAction.getFileFilters('all') - self.assertEqual(filters[nameFilter], self._dummySaveFunction) - self.assertEqual(list(filters.keys()).index(nameFilter),3) - - # Update an existing file filter - nameFilter = SaveAction.IMAGE_FILTER_EDF - saveAction.setFileFilter('image', nameFilter, self._dummySaveFunction) - self.assertEqual(saveAction.getFileFilters('image')[nameFilter], - self._dummySaveFunction) - - # Change the position of an existing file filter - nameFilter = 'Dummy file2 (*.dummy)' - oldIndex = list(saveAction.getFileFilters('all')).index(nameFilter) - newIndex = oldIndex - 1 - saveAction.setFileFilter('all', nameFilter, - self._dummySaveFunction, index=newIndex) - filters = saveAction.getFileFilters('all') - self.assertEqual(filters[nameFilter], self._dummySaveFunction) - self.assertEqual(list(filters.keys()).index(nameFilter), newIndex) - -def suite(): - test_suite = unittest.TestSuite() - for cls in (TestSaveActionSaveCurvesAsSpec, TestSaveActionExtension): - test_suite.addTest( - unittest.defaultTestLoader.loadTestsFromTestCase(cls)) - return test_suite - - -if __name__ == '__main__': - unittest.main(defaultTest='suite') diff --git a/silx/gui/plot/test/testScatterMaskToolsWidget.py b/silx/gui/plot/test/testScatterMaskToolsWidget.py deleted file mode 100644 index 800f30e..0000000 --- a/silx/gui/plot/test/testScatterMaskToolsWidget.py +++ /dev/null @@ -1,318 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# -# Copyright (c) 2016-2017 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 MaskToolsWidget""" - -__authors__ = ["T. Vincent", "P. Knobel"] -__license__ = "MIT" -__date__ = "17/01/2018" - - -import logging -import os.path -import unittest - -import numpy - -from silx.gui import qt -from silx.test.utils import temp_dir -from silx.utils.testutils import ParametricTestCase -from silx.gui.utils.testutils import getQToolButtonFromAction -from silx.gui.plot import PlotWindow, ScatterMaskToolsWidget -from .utils import PlotWidgetTestCase - -import fabio - - -_logger = logging.getLogger(__name__) - - -class TestScatterMaskToolsWidget(PlotWidgetTestCase, ParametricTestCase): - """Basic test for MaskToolsWidget""" - - def _createPlot(self): - return PlotWindow() - - def setUp(self): - super(TestScatterMaskToolsWidget, self).setUp() - self.widget = ScatterMaskToolsWidget.ScatterMaskToolsDockWidget( - plot=self.plot, name='TEST') - self.plot.addDockWidget(qt.Qt.BottomDockWidgetArea, self.widget) - - self.maskWidget = self.widget.widget() - - def tearDown(self): - del self.maskWidget - del self.widget - super(TestScatterMaskToolsWidget, self).tearDown() - - def testEmptyPlot(self): - """Empty plot, display MaskToolsDockWidget, toggle multiple masks""" - self.maskWidget.setMultipleMasks('single') - self.qapp.processEvents() - - self.maskWidget.setMultipleMasks('exclusive') - self.qapp.processEvents() - - def _drag(self): - """Drag from plot center to offset position""" - plot = self.plot.getWidgetHandle() - xCenter, yCenter = plot.width() // 2, plot.height() // 2 - offset = min(plot.width(), plot.height()) // 10 - - pos0 = xCenter, yCenter - pos1 = xCenter + offset, yCenter + offset - - self.mouseMove(plot, pos=(0, 0)) - self.mouseMove(plot, pos=pos0) - self.qapp.processEvents() - self.mousePress(plot, qt.Qt.LeftButton, pos=pos0) - self.qapp.processEvents() - - self.mouseMove(plot, pos=(pos0[0] + offset // 2, pos0[1] + offset // 2)) - self.mouseMove(plot, pos=pos1) - self.qapp.processEvents() - self.mouseRelease(plot, qt.Qt.LeftButton, pos=pos1) - self.qapp.processEvents() - self.mouseMove(plot, pos=(0, 0)) - - def _drawPolygon(self): - """Draw a star polygon in the plot""" - plot = self.plot.getWidgetHandle() - x, y = plot.width() // 2, plot.height() // 2 - offset = min(plot.width(), plot.height()) // 10 - - star = [(x, y + offset), - (x - offset, y - offset), - (x + offset, y), - (x - offset, y), - (x + offset, y - offset), - (x, y + offset)] # Close polygon - - self.mouseMove(plot, pos=[0, 0]) - for pos in star: - self.mouseMove(plot, pos=pos) - self.qapp.processEvents() - self.mousePress(plot, qt.Qt.LeftButton, pos=pos) - self.qapp.processEvents() - self.mouseRelease(plot, qt.Qt.LeftButton, pos=pos) - self.qapp.processEvents() - - def _drawPencil(self): - """Draw a star polygon in the plot""" - plot = self.plot.getWidgetHandle() - x, y = plot.width() // 2, plot.height() // 2 - offset = min(plot.width(), plot.height()) // 10 - - star = [(x, y + offset), - (x - offset, y - offset), - (x + offset, y), - (x - offset, y), - (x + offset, y - offset)] - - self.mouseMove(plot, pos=[0, 0]) - self.mouseMove(plot, pos=star[0]) - self.mousePress(plot, qt.Qt.LeftButton, pos=star[0]) - for pos in star[1:]: - self.mouseMove(plot, pos=pos) - self.mouseRelease( - plot, qt.Qt.LeftButton, pos=star[-1]) - - def testWithAScatter(self): - """Plot with a Scatter: test MaskToolsWidget interactions""" - - # Add and remove a scatter (this should enable/disable GUI + change mask) - self.plot.addScatter( - x=numpy.arange(256), - y=numpy.arange(256), - value=numpy.random.random(256), - legend='test') - self.plot._setActiveItem(kind="scatter", legend="test") - self.qapp.processEvents() - - self.plot.remove('test', kind='scatter') - self.qapp.processEvents() - - self.plot.addScatter( - x=numpy.arange(1000), - y=1000 * (numpy.arange(1000) % 20), - value=numpy.random.random(1000), - legend='test') - self.plot._setActiveItem(kind="scatter", legend="test") - self.plot.resetZoom() - self.qapp.processEvents() - - # Test draw rectangle # - toolButton = getQToolButtonFromAction(self.maskWidget.rectAction) - self.assertIsNot(toolButton, None) - self.mouseClick(toolButton, qt.Qt.LeftButton) - - # mask - self.maskWidget.maskStateGroup.button(1).click() - self.qapp.processEvents() - self._drag() - - self.assertFalse( - numpy.all(numpy.equal(self.maskWidget.getSelectionMask(), 0))) - - # unmask same region - self.maskWidget.maskStateGroup.button(0).click() - self.qapp.processEvents() - self._drag() - self.assertTrue( - numpy.all(numpy.equal(self.maskWidget.getSelectionMask(), 0))) - - # Test draw polygon # - toolButton = getQToolButtonFromAction(self.maskWidget.polygonAction) - self.assertIsNot(toolButton, None) - self.mouseClick(toolButton, qt.Qt.LeftButton) - - # mask - self.maskWidget.maskStateGroup.button(1).click() - self.qapp.processEvents() - self._drawPolygon() - self.assertFalse( - numpy.all(numpy.equal(self.maskWidget.getSelectionMask(), 0))) - - # unmask same region - self.maskWidget.maskStateGroup.button(0).click() - self.qapp.processEvents() - self._drawPolygon() - self.assertTrue( - numpy.all(numpy.equal(self.maskWidget.getSelectionMask(), 0))) - - # Test draw pencil # - toolButton = getQToolButtonFromAction(self.maskWidget.pencilAction) - self.assertIsNot(toolButton, None) - self.mouseClick(toolButton, qt.Qt.LeftButton) - - self.maskWidget.pencilSpinBox.setValue(30) - self.qapp.processEvents() - - # mask - self.maskWidget.maskStateGroup.button(1).click() - self.qapp.processEvents() - self._drawPencil() - self.assertFalse( - numpy.all(numpy.equal(self.maskWidget.getSelectionMask(), 0))) - - # unmask same region - self.maskWidget.maskStateGroup.button(0).click() - self.qapp.processEvents() - self._drawPencil() - self.assertTrue( - numpy.all(numpy.equal(self.maskWidget.getSelectionMask(), 0))) - - # Test no draw tool # - toolButton = getQToolButtonFromAction(self.maskWidget.browseAction) - self.assertIsNot(toolButton, None) - self.mouseClick(toolButton, qt.Qt.LeftButton) - - self.plot.clear() - - def __loadSave(self, file_format): - self.plot.addScatter( - x=numpy.arange(256), - y=25 * (numpy.arange(256) % 10), - value=numpy.random.random(256), - legend='test') - self.plot._setActiveItem(kind="scatter", legend="test") - self.plot.resetZoom() - self.qapp.processEvents() - - # Draw a polygon mask - toolButton = getQToolButtonFromAction(self.maskWidget.polygonAction) - self.assertIsNot(toolButton, None) - self.mouseClick(toolButton, qt.Qt.LeftButton) - self._drawPolygon() - - ref_mask = self.maskWidget.getSelectionMask() - self.assertFalse(numpy.all(numpy.equal(ref_mask, 0))) - - with temp_dir() as tmp: - mask_filename = os.path.join(tmp, 'mask.' + file_format) - self.maskWidget.save(mask_filename, file_format) - - self.maskWidget.resetSelectionMask() - self.assertTrue( - numpy.all(numpy.equal(self.maskWidget.getSelectionMask(), 0))) - - self.maskWidget.load(mask_filename) - self.assertTrue(numpy.all(numpy.equal( - self.maskWidget.getSelectionMask(), ref_mask))) - - def testLoadSaveNpy(self): - self.__loadSave("npy") - - def testLoadSaveCsv(self): - self.__loadSave("csv") - - def testSigMaskChangedEmitted(self): - self.qapp.processEvents() - self.plot.addScatter( - x=numpy.arange(1000), - y=1000 * (numpy.arange(1000) % 20), - value=numpy.ones((1000,)), - legend='test') - self.plot._setActiveItem(kind="scatter", legend="test") - self.plot.resetZoom() - self.qapp.processEvents() - - self.plot.remove('test', kind='scatter') - self.qapp.processEvents() - - self.plot.addScatter( - x=numpy.arange(1000), - y=1000 * (numpy.arange(1000) % 20), - value=numpy.random.random(1000), - legend='test') - - l = [] - - def slot(): - l.append(1) - - self.maskWidget.sigMaskChanged.connect(slot) - - # rectangle mask - toolButton = getQToolButtonFromAction(self.maskWidget.rectAction) - self.assertIsNot(toolButton, None) - self.mouseClick(toolButton, qt.Qt.LeftButton) - self.maskWidget.maskStateGroup.button(1).click() - self.qapp.processEvents() - self._drag() - - self.assertGreater(len(l), 0) - - -def suite(): - test_suite = unittest.TestSuite() - for TestClass in (TestScatterMaskToolsWidget,): - test_suite.addTest( - unittest.defaultTestLoader.loadTestsFromTestCase(TestClass)) - return test_suite - - -if __name__ == '__main__': - unittest.main(defaultTest='suite') diff --git a/silx/gui/plot/test/testScatterView.py b/silx/gui/plot/test/testScatterView.py deleted file mode 100644 index 583e3ed..0000000 --- a/silx/gui/plot/test/testScatterView.py +++ /dev/null @@ -1,134 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# -# Copyright (c) 2018 European Synchrotron Radiation Facility -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# 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 ScatterView""" - -__authors__ = ["T. Vincent"] -__license__ = "MIT" -__date__ = "06/03/2018" - - -import unittest - -import numpy - -from silx.gui.plot.items import Axis, Scatter -from silx.gui.plot import ScatterView -from silx.gui.plot.test.utils import PlotWidgetTestCase - - -class TestScatterView(PlotWidgetTestCase): - """Test of ScatterView widget""" - - def _createPlot(self): - return ScatterView() - - def test(self): - """Simple tests""" - x = numpy.arange(100) - y = numpy.arange(100) - value = numpy.arange(100) - self.plot.setData(x, y, value) - self.qapp.processEvents() - - data = self.plot.getData() - self.assertEqual(len(data), 5) - self.assertTrue(numpy.all(numpy.equal(x, data[0]))) - self.assertTrue(numpy.all(numpy.equal(y, data[1]))) - self.assertTrue(numpy.all(numpy.equal(value, data[2]))) - self.assertIsNone(data[3]) # xerror - self.assertIsNone(data[4]) # yerror - - # Test access to scatter item - self.assertIsInstance(self.plot.getScatterItem(), Scatter) - - # Test toolbar actions - - action = self.plot.getScatterToolBar().getXAxisLogarithmicAction() - action.trigger() - self.qapp.processEvents() - - maskAction = self.plot.getScatterToolBar().actions()[-1] - maskAction.trigger() - self.qapp.processEvents() - - # Test proxy API - - self.plot.resetZoom() - self.qapp.processEvents() - - scale = self.plot.getXAxis().getScale() - self.assertEqual(scale, Axis.LOGARITHMIC) - - scale = self.plot.getYAxis().getScale() - self.assertEqual(scale, Axis.LINEAR) - - title = 'Test ScatterView' - self.plot.setGraphTitle(title) - self.assertEqual(self.plot.getGraphTitle(), title) - - self.qapp.processEvents() - - # Reset scatter data - - self.plot.setData(None, None, None) - self.qapp.processEvents() - - data = self.plot.getData() - self.assertEqual(len(data), 5) - self.assertEqual(len(data[0]), 0) # x - self.assertEqual(len(data[1]), 0) # y - self.assertEqual(len(data[2]), 0) # value - self.assertIsNone(data[3]) # xerror - self.assertIsNone(data[4]) # yerror - - def testAlpha(self): - """Test alpha transparency in setData""" - _pts = 100 - _levels = 100 - _fwhm = 50 - x = numpy.random.rand(_pts)*_levels - y = numpy.random.rand(_pts)*_levels - value = numpy.random.rand(_pts)*_levels - x0 = x[int(_pts/2)] - y0 = x[int(_pts/2)] - #2D Gaussian kernel - alpha = numpy.exp(-4*numpy.log(2) * ((x-x0)**2 + (y-y0)**2) / _fwhm**2) - - self.plot.setData(x, y, value, alpha=alpha) - self.qapp.processEvents() - - alphaData = self.plot.getScatterItem().getAlphaData() - self.assertTrue(numpy.all(numpy.equal(alpha, alphaData))) - - -def suite(): - test_suite = unittest.TestSuite() - loadTests = unittest.defaultTestLoader.loadTestsFromTestCase - test_suite.addTest(loadTests(TestScatterView)) - return test_suite - - -if __name__ == '__main__': - unittest.main(defaultTest='suite') diff --git a/silx/gui/plot/test/testStackView.py b/silx/gui/plot/test/testStackView.py deleted file mode 100644 index 7605bbc..0000000 --- a/silx/gui/plot/test/testStackView.py +++ /dev/null @@ -1,261 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# -# 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 -# 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 StackView""" - -__authors__ = ["P. Knobel"] -__license__ = "MIT" -__date__ = "20/03/2017" - - -import unittest -import numpy - -from silx.gui.utils.testutils import TestCaseQt, SignalListener - -from silx.gui import qt -from silx.gui.plot import StackView -from silx.gui.plot.StackView import StackViewMainWindow - -from silx.utils.array_like import ListOfImages - - -class TestStackView(TestCaseQt): - """Base class for tests of StackView.""" - - def setUp(self): - super(TestStackView, self).setUp() - self.stackview = StackView() - self.stackview.show() - self.qWaitForWindowExposed(self.stackview) - self.mystack = numpy.fromfunction( - lambda i, j, k: numpy.sin(i/15.) + numpy.cos(j/4.) + 2 * numpy.sin(k/6.), - (10, 20, 30) - ) - - def tearDown(self): - self.stackview.setAttribute(qt.Qt.WA_DeleteOnClose) - self.stackview.close() - del self.stackview - super(TestStackView, self).tearDown() - - def testScaleColormapRangeToStack(self): - """Test scaleColormapRangeToStack""" - self.stackview.setStack(self.mystack) - self.stackview.setColormap("viridis") - colormap = self.stackview.getColormap() - - # Colormap autoscale to image - self.assertEqual(colormap.getVRange(), (None, None)) - self.stackview.scaleColormapRangeToStack() - - # Colormap range set according to stack range - self.assertEqual(colormap.getVRange(), (self.mystack.min(), self.mystack.max())) - - def testSetStack(self): - self.stackview.setStack(self.mystack) - self.stackview.setColormap("viridis", autoscale=True) - my_trans_stack, params = self.stackview.getStack() - self.assertEqual(my_trans_stack.shape, self.mystack.shape) - self.assertTrue(numpy.array_equal(self.mystack, - my_trans_stack)) - self.assertEqual(params["colormap"]["name"], - "viridis") - - def testSetStackPerspective(self): - self.stackview.setStack(self.mystack, perspective=1) - # my_orig_stack, params = self.stackview.getStack() - my_trans_stack, params = self.stackview.getCurrentView() - - # get stack returns the transposed data, depending on the perspective - self.assertEqual(my_trans_stack.shape, - (self.mystack.shape[1], self.mystack.shape[0], self.mystack.shape[2])) - self.assertTrue(numpy.array_equal(numpy.transpose(self.mystack, axes=(1, 0, 2)), - my_trans_stack)) - - def testSetStackListOfImages(self): - loi = [self.mystack[i] for i in range(self.mystack.shape[0])] - - self.stackview.setStack(loi) - my_orig_stack, params = self.stackview.getStack(returnNumpyArray=True) - my_trans_stack, params = self.stackview.getStack(returnNumpyArray=True) - self.assertEqual(my_trans_stack.shape, self.mystack.shape) - self.assertTrue(numpy.array_equal(self.mystack, - my_trans_stack)) - self.assertTrue(numpy.array_equal(self.mystack, - my_orig_stack)) - self.assertIsInstance(my_trans_stack, numpy.ndarray) - - self.stackview.setStack(loi, perspective=2) - my_orig_stack, params = self.stackview.getStack(copy=False) - my_trans_stack, params = self.stackview.getCurrentView(copy=False) - # getStack(copy=False) must return the object set in setStack - self.assertIs(my_orig_stack, loi) - # getCurrentView(copy=False) returns a ListOfImages whose .images - # attr is the original data - self.assertEqual(my_trans_stack.shape, - (self.mystack.shape[2], self.mystack.shape[0], self.mystack.shape[1])) - self.assertTrue(numpy.array_equal(numpy.array(my_trans_stack), - numpy.transpose(self.mystack, axes=(2, 0, 1)))) - self.assertIsInstance(my_trans_stack, - ListOfImages) # returnNumpyArray=False by default in getStack - self.assertIs(my_trans_stack.images, loi) - - def testPerspective(self): - self.stackview.setStack(numpy.arange(24).reshape((2, 3, 4))) - self.assertEqual(self.stackview._perspective, 0, - "Default perspective is not 0 (dim1-dim2).") - - self.stackview._StackView__planeSelection.setPerspective(1) - self.assertEqual(self.stackview._perspective, 1, - "Plane selection combobox not updating perspective") - - self.stackview.setStack(numpy.arange(6).reshape((1, 2, 3))) - self.assertEqual(self.stackview._perspective, 1, - "Perspective not preserved when calling setStack " - "without specifying the perspective parameter.") - - self.stackview.setStack(numpy.arange(24).reshape((2, 3, 4)), perspective=2) - self.assertEqual(self.stackview._perspective, 2, - "Perspective not set in setStack(..., perspective=2).") - - def testDefaultTitle(self): - """Test that the plot title contains the proper Z information""" - self.stackview.setStack(numpy.arange(24).reshape((4, 3, 2)), - calibrations=[(0, 1), (-10, 10), (3.14, 3.14)]) - self.assertEqual(self.stackview._plot.getGraphTitle(), - "Image z=0") - self.stackview.setFrameNumber(2) - self.assertEqual(self.stackview._plot.getGraphTitle(), - "Image z=2") - - self.stackview._StackView__planeSelection.setPerspective(1) - self.stackview.setFrameNumber(0) - self.assertEqual(self.stackview._plot.getGraphTitle(), - "Image z=-10") - self.stackview.setFrameNumber(2) - self.assertEqual(self.stackview._plot.getGraphTitle(), - "Image z=10") - - self.stackview._StackView__planeSelection.setPerspective(2) - self.stackview.setFrameNumber(0) - self.assertEqual(self.stackview._plot.getGraphTitle(), - "Image z=3.14") - self.stackview.setFrameNumber(1) - self.assertEqual(self.stackview._plot.getGraphTitle(), - "Image z=6.28") - - def testCustomTitle(self): - """Test setting the plot title with a user defined callback""" - self.stackview.setStack(numpy.arange(24).reshape((4, 3, 2)), - calibrations=[(0, 1), (-10, 10), (3.14, 3.14)]) - - def title_callback(frame_idx): - return "Cubed index title %d" % (frame_idx**3) - - self.stackview.setTitleCallback(title_callback) - self.assertEqual(self.stackview._plot.getGraphTitle(), - "Cubed index title 0") - self.stackview.setFrameNumber(2) - self.assertEqual(self.stackview._plot.getGraphTitle(), - "Cubed index title 8") - - # perspective should not matter, only frame index - self.stackview._StackView__planeSelection.setPerspective(1) - self.stackview.setFrameNumber(0) - self.assertEqual(self.stackview._plot.getGraphTitle(), - "Cubed index title 0") - self.stackview.setFrameNumber(2) - self.assertEqual(self.stackview._plot.getGraphTitle(), - "Cubed index title 8") - - with self.assertRaises(TypeError): - # setTitleCallback should not accept non-callable objects like strings - self.stackview.setTitleCallback( - "Là , vous faites sirop de vingt-et-un et vous dites : " - "beau sirop, mi-sirop, siroté, gagne-sirop, sirop-grelot," - " passe-montagne, sirop au bon goût.") - - def testStackFrameNumber(self): - self.stackview.setStack(self.mystack) - self.assertEqual(self.stackview.getFrameNumber(), 0) - - listener = SignalListener() - self.stackview.sigFrameChanged.connect(listener) - - self.stackview.setFrameNumber(1) - self.assertEqual(self.stackview.getFrameNumber(), 1) - self.assertEqual(listener.arguments(), [(1,)]) - - -class TestStackViewMainWindow(TestCaseQt): - """Base class for tests of StackView.""" - - def setUp(self): - super(TestStackViewMainWindow, self).setUp() - self.stackview = StackViewMainWindow() - self.stackview.show() - self.qWaitForWindowExposed(self.stackview) - self.mystack = numpy.fromfunction( - lambda i, j, k: numpy.sin(i/15.) + numpy.cos(j/4.) + 2 * numpy.sin(k/6.), - (10, 20, 30) - ) - - def tearDown(self): - self.stackview.setAttribute(qt.Qt.WA_DeleteOnClose) - self.stackview.close() - del self.stackview - super(TestStackViewMainWindow, self).tearDown() - - def testSetStack(self): - self.stackview.setStack(self.mystack) - self.stackview.setColormap("viridis", autoscale=True) - my_trans_stack, params = self.stackview.getStack() - self.assertEqual(my_trans_stack.shape, self.mystack.shape) - self.assertTrue(numpy.array_equal(self.mystack, - my_trans_stack)) - self.assertEqual(params["colormap"]["name"], - "viridis") - - def testSetStackPerspective(self): - self.stackview.setStack(self.mystack, perspective=1) - my_trans_stack, params = self.stackview.getCurrentView() - # get stack returns the transposed data, depending on the perspective - self.assertEqual(my_trans_stack.shape, - (self.mystack.shape[1], self.mystack.shape[0], self.mystack.shape[2])) - self.assertTrue(numpy.array_equal(numpy.transpose(self.mystack, axes=(1, 0, 2)), - my_trans_stack)) - - -def suite(): - test_suite = unittest.TestSuite() - test_suite.addTest( - unittest.defaultTestLoader.loadTestsFromTestCase(TestStackView)) - test_suite.addTest( - unittest.defaultTestLoader.loadTestsFromTestCase(TestStackViewMainWindow)) - 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 deleted file mode 100644 index d5046ba..0000000 --- a/silx/gui/plot/test/testStats.py +++ /dev/null @@ -1,1058 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# -# 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 -# 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 CurvesROIWidget""" - -__authors__ = ["H. Payno"] -__license__ = "MIT" -__date__ = "07/03/2018" - - -from silx.gui import qt -from silx.gui.plot.stats import stats -from silx.gui.plot import StatsWidget -from silx.gui.plot.stats import statshandler -from silx.gui.utils.testutils import TestCaseQt, SignalListener -from silx.gui.plot import Plot1D, Plot2D -from silx.gui.plot3d.SceneWidget import SceneWidget -from silx.gui.plot.items.roi import RectangleROI, PolygonROI -from silx.gui.plot.tools.roi import RegionOfInterestManager -from silx.gui.plot.stats.stats import Stats -from silx.gui.plot.CurvesROIWidget import ROI -from silx.utils.testutils import ParametricTestCase -import unittest -import logging -import numpy - -_logger = logging.getLogger(__name__) - - -class TestStatsBase(object): - """Base class for stats TestCase""" - def setUp(self): - self.createCurveContext() - self.createImageContext() - self.createScatterContext() - - 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 - - def createCurveContext(self): - self.plot1d = Plot1D() - x = range(20) - y = range(20) - self.plot1d.addCurve(x, y, legend='curve0') - - self.curveContext = stats._CurveContext( - item=self.plot1d.getCurve('curve0'), - plot=self.plot1d, - onlimits=False, - roi=None) - - def createScatterContext(self): - self.scatterPlot = Plot2D() - lgd = 'scatter plot' - self.xScatterData = numpy.array([0, 2, 3, 20, 50, 60, 36]) - self.yScatterData = numpy.array([2, 3, 4, 26, 69, 6, 18]) - self.valuesScatterData = numpy.array([5, 6, 7, 10, 90, 20, 5]) - self.scatterPlot.addScatter(self.xScatterData, self.yScatterData, - self.valuesScatterData, legend=lgd) - self.scatterContext = stats._ScatterContext( - item=self.scatterPlot.getScatter(lgd), - plot=self.scatterPlot, - onlimits=False, - roi=None - ) - - def createImageContext(self): - self.plot2d = Plot2D() - self._imgLgd = 'test image' - self.imageData = numpy.arange(32*128).reshape(32, 128) - self.plot2d.addImage(data=self.imageData, - legend=self._imgLgd, replace=False) - self.imageContext = stats._ImageContext( - item=self.plot2d.getImage(self._imgLgd), - plot=self.plot2d, - onlimits=False, - roi=None - ) - - def getBasicStats(self): - return { - 'min': stats.StatMin(), - 'minCoords': stats.StatCoordMin(), - 'max': stats.StatMax(), - 'maxCoords': stats.StatCoordMax(), - 'std': stats.Stat(name='std', fct=numpy.std), - 'mean': stats.Stat(name='mean', fct=numpy.mean), - 'com': stats.StatCOM() - } - - -class TestStats(TestStatsBase, TestCaseQt): - """ - Test :class:`BaseClass` class and inheriting classes - """ - def setUp(self): - TestCaseQt.setUp(self) - TestStatsBase.setUp(self) - - def tearDown(self): - TestStatsBase.tearDown(self) - TestCaseQt.tearDown(self) - - def testBasicStatsCurve(self): - """Test result for simple stats on a curve""" - _stats = self.getBasicStats() - xData = yData = numpy.array(range(20)) - self.assertEqual(_stats['min'].calculate(self.curveContext), 0) - self.assertEqual(_stats['max'].calculate(self.curveContext), 19) - self.assertEqual(_stats['minCoords'].calculate(self.curveContext), (0,)) - self.assertEqual(_stats['maxCoords'].calculate(self.curveContext), (19,)) - self.assertEqual(_stats['std'].calculate(self.curveContext), numpy.std(yData)) - self.assertEqual(_stats['mean'].calculate(self.curveContext), numpy.mean(yData)) - com = numpy.sum(xData * yData) / numpy.sum(yData) - self.assertEqual(_stats['com'].calculate(self.curveContext), com) - - def testBasicStatsImage(self): - """Test result for simple stats on an image""" - _stats = self.getBasicStats() - self.assertEqual(_stats['min'].calculate(self.imageContext), 0) - self.assertEqual(_stats['max'].calculate(self.imageContext), 128 * 32 - 1) - self.assertEqual(_stats['minCoords'].calculate(self.imageContext), (0, 0)) - self.assertEqual(_stats['maxCoords'].calculate(self.imageContext), (127, 31)) - self.assertEqual(_stats['std'].calculate(self.imageContext), numpy.std(self.imageData)) - self.assertEqual(_stats['mean'].calculate(self.imageContext), numpy.mean(self.imageData)) - - yData = numpy.sum(self.imageData.astype(numpy.float64), axis=1) - xData = numpy.sum(self.imageData.astype(numpy.float64), axis=0) - dataXRange = range(self.imageData.shape[1]) - dataYRange = range(self.imageData.shape[0]) - - ycom = numpy.sum(yData*dataYRange) / numpy.sum(yData) - xcom = numpy.sum(xData*dataXRange) / numpy.sum(xData) - - self.assertEqual(_stats['com'].calculate(self.imageContext), (xcom, ycom)) - - def testStatsImageAdv(self): - """Test that scale and origin are taking into account for images""" - - image2Data = numpy.arange(32 * 128).reshape(32, 128) - self.plot2d.addImage(data=image2Data, legend=self._imgLgd, - replace=True, origin=(100, 10), scale=(2, 0.5)) - image2Context = stats._ImageContext( - item=self.plot2d.getImage(self._imgLgd), - plot=self.plot2d, - onlimits=False, - roi=None, - ) - _stats = self.getBasicStats() - self.assertEqual(_stats['min'].calculate(image2Context), 0) - self.assertEqual( - _stats['max'].calculate(image2Context), 128 * 32 - 1) - self.assertEqual( - _stats['minCoords'].calculate(image2Context), (100, 10)) - self.assertEqual( - _stats['maxCoords'].calculate(image2Context), (127*2. + 100, - 31 * 0.5 + 10)) - self.assertEqual(_stats['std'].calculate(image2Context), - numpy.std(self.imageData)) - self.assertEqual(_stats['mean'].calculate(image2Context), - numpy.mean(self.imageData)) - - yData = numpy.sum(self.imageData, axis=1) - xData = numpy.sum(self.imageData, axis=0) - dataXRange = numpy.arange(self.imageData.shape[1], dtype=numpy.float64) - dataYRange = numpy.arange(self.imageData.shape[0], dtype=numpy.float64) - - ycom = numpy.sum(yData * dataYRange) / numpy.sum(yData) - ycom = (ycom * 0.5) + 10 - xcom = numpy.sum(xData * dataXRange) / numpy.sum(xData) - xcom = (xcom * 2.) + 100 - self.assertTrue(numpy.allclose( - _stats['com'].calculate(image2Context), (xcom, ycom))) - - def testBasicStatsScatter(self): - """Test result for simple stats on a scatter""" - _stats = self.getBasicStats() - self.assertEqual(_stats['min'].calculate(self.scatterContext), 5) - self.assertEqual(_stats['max'].calculate(self.scatterContext), 90) - self.assertEqual(_stats['minCoords'].calculate(self.scatterContext), (0, 2)) - self.assertEqual(_stats['maxCoords'].calculate(self.scatterContext), (50, 69)) - self.assertEqual(_stats['std'].calculate(self.scatterContext), numpy.std(self.valuesScatterData)) - self.assertEqual(_stats['mean'].calculate(self.scatterContext), numpy.mean(self.valuesScatterData)) - - data = self.valuesScatterData.astype(numpy.float64) - comx = numpy.sum(self.xScatterData * data) / numpy.sum(data) - comy = numpy.sum(self.yScatterData * data) / numpy.sum(data) - self.assertEqual(_stats['com'].calculate(self.scatterContext), - (comx, comy)) - - def testKindNotManagedByStat(self): - """Make sure an exception is raised if we try to execute calculate - of the base class""" - b = stats.StatBase(name='toto', compatibleKinds='curve') - with self.assertRaises(NotImplementedError): - b.calculate(self.imageContext) - - def testKindNotManagedByContext(self): - """ - Make sure an error is raised if we try to calculate a statistic with - a context not managed - """ - myStat = stats.Stat(name='toto', fct=numpy.std, kinds=('curve')) - myStat.calculate(self.curveContext) - with self.assertRaises(ValueError): - myStat.calculate(self.scatterContext) - with self.assertRaises(ValueError): - myStat.calculate(self.imageContext) - - def testOnLimits(self): - stat = stats.StatMin() - - self.plot1d.getXAxis().setLimitsConstraints(minPos=2, maxPos=5) - curveContextOnLimits = stats._CurveContext( - item=self.plot1d.getCurve('curve0'), - plot=self.plot1d, - onlimits=True, - roi=None) - self.assertEqual(stat.calculate(curveContextOnLimits), 2) - - self.plot2d.getXAxis().setLimitsConstraints(minPos=32) - imageContextOnLimits = stats._ImageContext( - item=self.plot2d.getImage('test image'), - plot=self.plot2d, - onlimits=True, - roi=None) - self.assertEqual(stat.calculate(imageContextOnLimits), 32) - - self.scatterPlot.getXAxis().setLimitsConstraints(minPos=40) - scatterContextOnLimits = stats._ScatterContext( - item=self.scatterPlot.getScatter('scatter plot'), - plot=self.scatterPlot, - onlimits=True, - roi=None) - self.assertEqual(stat.calculate(scatterContextOnLimits), 20) - - -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) - self.plot1d.addCurve(x, y, legend='curve0') - - self.curveContext = stats._CurveContext( - item=self.plot1d.getCurve('curve0'), - plot=self.plot1d, - onlimits=False, - roi=None) - - self.stat = stats.StatMin() - - 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 - simple cast to str""" - emptyFormatter = statshandler.StatFormatter() - self.assertEqual( - emptyFormatter.format(self.stat.calculate(self.curveContext)), '0.000') - - def testSettedFormatter(self): - """Make sure a formatter with no formatter definition will return a - simple cast to str""" - formatter= statshandler.StatFormatter(formatter='{0:.3f}') - self.assertEqual( - formatter.format(self.stat.calculate(self.curveContext)), '0.000') - - -class TestStatsHandler(TestCaseQt): - """Make sure the StatHandler is correctly making the link between - :class:`StatBase` and :class:`StatFormatter` and checking the API is valid - """ - def setUp(self): - TestCaseQt.setUp(self) - self.plot1d = Plot1D() - x = range(20) - y = range(20) - self.plot1d.addCurve(x, y, legend='curve0') - self.curveItem = self.plot1d.getCurve('curve0') - - self.stat = stats.StatMin() - - def tearDown(self): - Stats._getContext.cache_clear() - self.plot1d.setAttribute(qt.Qt.WA_DeleteOnClose) - self.plot1d.close() - self.plot1d = None - TestCaseQt.tearDown(self) - - def testConstructor(self): - """Make sure the constructor can deal will all possible arguments: - - * tuple of :class:`StatBase` derivated classes - * tuple of tuples (:class:`StatBase`, :class:`StatFormatter`) - * tuple of tuples (str, pointer to function, kind) - """ - handler0 = statshandler.StatsHandler( - (stats.StatMin(), stats.StatMax()) - ) - - res = handler0.calculate(item=self.curveItem, plot=self.plot1d, - onlimits=False) - self.assertTrue('min' in res) - self.assertEqual(res['min'], '0') - self.assertTrue('max' in res) - self.assertEqual(res['max'], '19') - - handler1 = statshandler.StatsHandler( - ( - (stats.StatMin(), statshandler.StatFormatter(formatter=None)), - (stats.StatMax(), statshandler.StatFormatter()) - ) - ) - - res = handler1.calculate(item=self.curveItem, plot=self.plot1d, - onlimits=False) - self.assertTrue('min' in res) - self.assertEqual(res['min'], '0') - self.assertTrue('max' in res) - self.assertEqual(res['max'], '19.000') - - handler2 = statshandler.StatsHandler( - ( - (stats.StatMin(), None), - (stats.StatMax(), statshandler.StatFormatter()) - )) - - res = handler2.calculate(item=self.curveItem, plot=self.plot1d, - onlimits=False) - self.assertTrue('min' in res) - self.assertEqual(res['min'], '0') - self.assertTrue('max' in res) - self.assertEqual(res['max'], '19.000') - - handler3 = statshandler.StatsHandler(( - (('amin', numpy.argmin), statshandler.StatFormatter()), - ('amax', numpy.argmax) - )) - - res = handler3.calculate(item=self.curveItem, plot=self.plot1d, - onlimits=False) - self.assertTrue('amin' in res) - self.assertEqual(res['amin'], '0.000') - self.assertTrue('amax' in res) - self.assertEqual(res['amax'], '19') - - with self.assertRaises(ValueError): - statshandler.StatsHandler(('name')) - - -class TestStatsWidgetWithCurves(TestCaseQt, ParametricTestCase): - """Basic test for StatsWidget with curves""" - def setUp(self): - TestCaseQt.setUp(self) - self.plot = Plot1D() - self.plot.show() - x = range(20) - y = range(20) - self.plot.addCurve(x, y, legend='curve0') - y = range(12, 32) - self.plot.addCurve(x, y, legend='curve1') - y = range(-2, 18) - self.plot.addCurve(x, y, legend='curve2') - self.widget = StatsWidget.StatsWidget(plot=self.plot) - self.statsTable = self.widget._statsTable - - mystats = statshandler.StatsHandler(( - stats.StatMin(), - (stats.StatCoordMin(), statshandler.StatFormatter(None, qt.QTableWidgetItem)), - stats.StatMax(), - (stats.StatCoordMax(), statshandler.StatFormatter(None, qt.QTableWidgetItem)), - stats.StatDelta(), - ('std', numpy.std), - ('mean', numpy.mean), - stats.StatCOM() - )) - - self.statsTable.setStats(mystats) - - def tearDown(self): - Stats._getContext.cache_clear() - self.plot.setAttribute(qt.Qt.WA_DeleteOnClose) - self.plot.close() - self.statsTable = None - self.widget.setAttribute(qt.Qt.WA_DeleteOnClose) - self.widget.close() - self.widget = None - self.plot = None - TestCaseQt.tearDown(self) - - def testDisplayActiveItemsSyncOptions(self): - """ - Test that the several option of the sync options are well - synchronized between the different object""" - widget = StatsWidget.StatsWidget(plot=self.plot) - table = StatsWidget.StatsTable(plot=self.plot) - - def check_display_only_active_item(only_active): - # check internal value - self.assertIs(widget._statsTable._displayOnlyActItem, only_active) - # self.assertTrue(table._displayOnlyActItem is only_active) - # check gui display - self.assertEqual(widget._options.isActiveItemMode(), only_active) - - for displayOnlyActiveItems in (True, False): - with self.subTest(displayOnlyActiveItems=displayOnlyActiveItems): - widget.setDisplayOnlyActiveItem(displayOnlyActiveItems) - # table.setDisplayOnlyActiveItem(displayOnlyActiveItems) - check_display_only_active_item(displayOnlyActiveItems) - - check_display_only_active_item(only_active=False) - widget.setAttribute(qt.Qt.WA_DeleteOnClose) - table.setAttribute(qt.Qt.WA_DeleteOnClose) - widget.close() - table.close() - - def testInit(self): - """Make sure all the curves are registred on initialization""" - self.assertEqual(self.statsTable.rowCount(), 3) - - def testRemoveCurve(self): - """Make sure the Curves stats take into account the curve removal from - plot""" - self.plot.removeCurve('curve2') - self.assertEqual(self.statsTable.rowCount(), 2) - for iRow in range(2): - self.assertTrue(self.statsTable.item(iRow, 0).text() in ('curve0', 'curve1')) - - self.plot.removeCurve('curve0') - self.assertEqual(self.statsTable.rowCount(), 1) - self.plot.removeCurve('curve1') - self.assertEqual(self.statsTable.rowCount(), 0) - - def testAddCurve(self): - """Make sure the Curves stats take into account the add curve action""" - self.plot.addCurve(legend='curve3', x=range(10), y=range(10)) - self.assertEqual(self.statsTable.rowCount(), 4) - - def testUpdateCurveFromAddCurve(self): - """Make sure the stats of the cuve will be removed after updating a - curve""" - self.plot.addCurve(legend='curve0', x=range(10), y=range(10)) - self.qapp.processEvents() - self.assertEqual(self.statsTable.rowCount(), 3) - curve = self.plot._getItem(kind='curve', legend='curve0') - tableItems = self.statsTable._itemToTableItems(curve) - self.assertEqual(tableItems['max'].text(), '9') - - def testUpdateCurveFromCurveObj(self): - self.plot.getCurve('curve0').setData(x=range(4), y=range(4)) - self.qapp.processEvents() - self.assertEqual(self.statsTable.rowCount(), 3) - curve = self.plot._getItem(kind='curve', legend='curve0') - tableItems = self.statsTable._itemToTableItems(curve) - self.assertEqual(tableItems['max'].text(), '3') - - def testSetAnotherPlot(self): - plot2 = Plot1D() - plot2.addCurve(x=range(26), y=range(26), legend='new curve') - self.statsTable.setPlot(plot2) - self.assertEqual(self.statsTable.rowCount(), 1) - self.qapp.processEvents() - plot2.setAttribute(qt.Qt.WA_DeleteOnClose) - plot2.close() - plot2 = None - - def testUpdateMode(self): - """Make sure the update modes are well take into account""" - self.plot.setActiveCurve('curve0') - for display_only_active in (True, False): - with self.subTest(display_only_active=display_only_active): - self.widget.setDisplayOnlyActiveItem(display_only_active) - self.plot.getCurve('curve0').setData(x=range(4), y=range(4)) - self.widget.setUpdateMode(StatsWidget.UpdateMode.AUTO) - update_stats_action = self.widget._options.getUpdateStatsAction() - # test from api - 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)) - self.qapp.processEvents() - tableItems = self.statsTable._itemToTableItems(self.plot.getCurve('curve0')) - curve0_min = tableItems['min'].text() - self.assertTrue(float(curve0_min) == -1.) - - self.plot.getCurve('curve0').setData(x=range(4), y=range(1, 5)) - self.qapp.processEvents() - tableItems = self.statsTable._itemToTableItems(self.plot.getCurve('curve0')) - curve0_min = tableItems['min'].text() - self.assertTrue(float(curve0_min) == 1.) - - # check stats change in manual mode only if requested - self.widget.setUpdateMode(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() - tableItems = self.statsTable._itemToTableItems(self.plot.getCurve('curve0')) - curve0_min = tableItems['min'].text() - self.assertTrue(float(curve0_min) == 1.) - - update_stats_action.trigger() - tableItems = self.statsTable._itemToTableItems(self.plot.getCurve('curve0')) - curve0_min = tableItems['min'].text() - self.assertTrue(float(curve0_min) == 2.) - - def testItemHidden(self): - """Test if an item is hide, then the associated stats item is also - hide""" - curve0 = self.plot.getCurve('curve0') - curve1 = self.plot.getCurve('curve1') - curve2 = self.plot.getCurve('curve2') - - self.plot.show() - self.widget.show() - self.qWaitForWindowExposed(self.widget) - self.assertFalse(self.statsTable.isRowHidden(0)) - self.assertFalse(self.statsTable.isRowHidden(1)) - self.assertFalse(self.statsTable.isRowHidden(2)) - - curve0.setVisible(False) - self.qapp.processEvents() - self.assertTrue(self.statsTable.isRowHidden(0)) - curve0.setVisible(True) - self.qapp.processEvents() - self.assertFalse(self.statsTable.isRowHidden(0)) - curve1.setVisible(False) - self.qapp.processEvents() - self.assertTrue(self.statsTable.isRowHidden(1)) - tableItems = self.statsTable._itemToTableItems(curve2) - curve2_min = tableItems['min'].text() - self.assertTrue(float(curve2_min) == -2.) - - curve0.setVisible(False) - curve1.setVisible(False) - curve2.setVisible(False) - self.qapp.processEvents() - self.assertTrue(self.statsTable.isRowHidden(0)) - self.assertTrue(self.statsTable.isRowHidden(1)) - self.assertTrue(self.statsTable.isRowHidden(2)) - - -class TestStatsWidgetWithImages(TestCaseQt): - """Basic test for StatsWidget with images""" - - IMAGE_LEGEND = 'test image' - - def setUp(self): - TestCaseQt.setUp(self) - self.plot = Plot2D() - - self.plot.addImage(data=numpy.arange(128*128).reshape(128, 128), - legend=self.IMAGE_LEGEND, replace=False) - - self.widget = StatsWidget.StatsTable(plot=self.plot) - - mystats = statshandler.StatsHandler(( - (stats.StatMin(), statshandler.StatFormatter()), - (stats.StatCoordMin(), statshandler.StatFormatter(None, qt.QTableWidgetItem)), - (stats.StatMax(), statshandler.StatFormatter()), - (stats.StatCoordMax(), statshandler.StatFormatter(None, qt.QTableWidgetItem)), - (stats.StatDelta(), statshandler.StatFormatter()), - ('std', numpy.std), - ('mean', numpy.mean), - (stats.StatCOM(), statshandler.StatFormatter(None)) - )) - - self.widget.setStats(mystats) - - def tearDown(self): - Stats._getContext.cache_clear() - self.plot.setAttribute(qt.Qt.WA_DeleteOnClose) - self.plot.close() - self.widget.setAttribute(qt.Qt.WA_DeleteOnClose) - self.widget.close() - self.widget = None - self.plot = None - TestCaseQt.tearDown(self) - - def test(self): - image = self.plot._getItem( - kind='image', legend=self.IMAGE_LEGEND) - tableItems = self.widget._itemToTableItems(image) - - maxText = '{0:.3f}'.format((128 * 128) - 1) - self.assertEqual(tableItems['legend'].text(), self.IMAGE_LEGEND) - self.assertEqual(tableItems['min'].text(), '0.000') - self.assertEqual(tableItems['max'].text(), maxText) - self.assertEqual(tableItems['delta'].text(), maxText) - self.assertEqual(tableItems['coords min'].text(), '0.0, 0.0') - self.assertEqual(tableItems['coords max'].text(), '127.0, 127.0') - - def testItemHidden(self): - """Test if an item is hide, then the associated stats item is also - hide""" - self.widget.show() - self.plot.show() - self.qWaitForWindowExposed(self.widget) - self.assertFalse(self.widget.isRowHidden(0)) - self.plot.getImage(self.IMAGE_LEGEND).setVisible(False) - self.qapp.processEvents() - self.assertTrue(self.widget.isRowHidden(0)) - - -class TestStatsWidgetWithScatters(TestCaseQt): - - SCATTER_LEGEND = 'scatter plot' - - def setUp(self): - TestCaseQt.setUp(self) - self.scatterPlot = Plot2D() - self.scatterPlot.addScatter([0, 1, 2, 20, 50, 60], - [2, 3, 4, 26, 69, 6], - [5, 6, 7, 10, 90, 20], - legend=self.SCATTER_LEGEND) - self.widget = StatsWidget.StatsTable(plot=self.scatterPlot) - - mystats = statshandler.StatsHandler(( - stats.StatMin(), - (stats.StatCoordMin(), statshandler.StatFormatter(None, qt.QTableWidgetItem)), - stats.StatMax(), - (stats.StatCoordMax(), statshandler.StatFormatter(None, qt.QTableWidgetItem)), - stats.StatDelta(), - ('std', numpy.std), - ('mean', numpy.mean), - stats.StatCOM() - )) - - self.widget.setStats(mystats) - - def tearDown(self): - Stats._getContext.cache_clear() - self.scatterPlot.setAttribute(qt.Qt.WA_DeleteOnClose) - self.scatterPlot.close() - self.widget.setAttribute(qt.Qt.WA_DeleteOnClose) - self.widget.close() - self.widget = None - self.scatterPlot = None - TestCaseQt.tearDown(self) - - def testStats(self): - scatter = self.scatterPlot._getItem( - kind='scatter', legend=self.SCATTER_LEGEND) - tableItems = self.widget._itemToTableItems(scatter) - self.assertEqual(tableItems['legend'].text(), self.SCATTER_LEGEND) - self.assertEqual(tableItems['min'].text(), '5') - self.assertEqual(tableItems['coords min'].text(), '0, 2') - self.assertEqual(tableItems['max'].text(), '90') - self.assertEqual(tableItems['coords max'].text(), '50, 69') - self.assertEqual(tableItems['delta'].text(), '85') - - -class TestEmptyStatsWidget(TestCaseQt): - def test(self): - widget = StatsWidget.StatsWidget() - widget.show() - self.qWaitForWindowExposed(widget) - - -# skip unit test for pyqt4 because there is some unrealised widget without -# apparent reason -@unittest.skipIf(qt.qVersion().split('.')[0] == '4', reason='PyQt4 not tested') -class TestLineWidget(TestCaseQt): - """Some test for the StatsLineWidget.""" - def setUp(self): - TestCaseQt.setUp(self) - - mystats = statshandler.StatsHandler(( - (stats.StatMin(), statshandler.StatFormatter()), - )) - - self.plot = Plot1D() - self.plot.show() - self.x = range(20) - self.y0 = range(20) - self.curve0 = self.plot.addCurve(self.x, self.y0, legend='curve0') - self.y1 = range(12, 32) - self.plot.addCurve(self.x, self.y1, legend='curve1') - self.y2 = range(-2, 18) - self.plot.addCurve(self.x, self.y2, legend='curve2') - self.widget = StatsWidget.BasicGridStatsWidget(plot=self.plot, - kind='curve', - stats=mystats) - - def tearDown(self): - Stats._getContext.cache_clear() - self.qapp.processEvents() - self.plot.setAttribute(qt.Qt.WA_DeleteOnClose) - self.plot.close() - self.widget.setPlot(None) - self.widget._lineStatsWidget._statQlineEdit.clear() - self.widget.setAttribute(qt.Qt.WA_DeleteOnClose) - self.widget.close() - self.widget = None - self.plot = None - TestCaseQt.tearDown(self) - - def testProcessing(self): - self.widget._lineStatsWidget.setStatsOnVisibleData(False) - self.qapp.processEvents() - self.plot.setActiveCurve(legend='curve0') - self.assertTrue(self.widget._lineStatsWidget._statQlineEdit['min'].text() == '0.000') - self.plot.setActiveCurve(legend='curve1') - self.assertTrue(self.widget._lineStatsWidget._statQlineEdit['min'].text() == '12.000') - self.plot.getXAxis().setLimitsConstraints(minPos=2, maxPos=5) - self.widget.setStatsOnVisibleData(True) - self.qapp.processEvents() - self.assertTrue(self.widget._lineStatsWidget._statQlineEdit['min'].text() == '14.000') - self.plot.setActiveCurve(None) - self.assertIsNone(self.plot.getActiveCurve()) - self.widget.setStatsOnVisibleData(False) - self.qapp.processEvents() - self.assertFalse(self.widget._lineStatsWidget._statQlineEdit['min'].text() == '14.000') - self.widget.setKind('image') - self.plot.addImage(numpy.arange(100*100).reshape(100, 100) + 0.312) - self.qapp.processEvents() - self.assertTrue(self.widget._lineStatsWidget._statQlineEdit['min'].text() == '0.312') - - def testUpdateMode(self): - """Make sure the update modes are well take into account""" - self.plot.setActiveCurve(self.curve0) - _autoRB = self.widget._options._autoRB - _manualRB = self.widget._options._manualRB - # test from api - self.widget.setUpdateMode(StatsWidget.UpdateMode.AUTO) - self.assertTrue(_autoRB.isChecked()) - self.assertFalse(_manualRB.isChecked()) - - # check stats change in auto mode - curve0_min = self.widget._lineStatsWidget._statQlineEdit['min'].text() - new_y = numpy.array(self.y0) - 2.56 - self.plot.addCurve(x=self.x, y=new_y, legend=self.curve0) - curve0_min2 = self.widget._lineStatsWidget._statQlineEdit['min'].text() - self.assertTrue(curve0_min != curve0_min2) - - # check stats change in manual mode only if requested - self.widget.setUpdateMode(StatsWidget.UpdateMode.MANUAL) - self.assertFalse(_autoRB.isChecked()) - self.assertTrue(_manualRB.isChecked()) - - new_y = numpy.array(self.y0) - 1.2 - self.plot.addCurve(x=self.x, y=new_y, legend=self.curve0) - curve0_min3 = self.widget._lineStatsWidget._statQlineEdit['min'].text() - self.assertTrue(curve0_min3 == curve0_min2) - self.widget._options._updateRequested() - curve0_min3 = self.widget._lineStatsWidget._statQlineEdit['min'].text() - self.assertTrue(curve0_min3 != curve0_min2) - - # test from gui - self.widget.showRadioButtons(True) - self.widget._options._autoRB.toggle() - self.assertTrue(_autoRB.isChecked()) - self.assertFalse(_manualRB.isChecked()) - - self.widget._options._manualRB.toggle() - self.assertFalse(_autoRB.isChecked()) - self.assertTrue(_manualRB.isChecked()) - - -class TestUpdateModeWidget(TestCaseQt): - """Test UpdateModeWidget""" - def setUp(self): - TestCaseQt.setUp(self) - self.widget = StatsWidget.UpdateModeWidget(parent=None) - - def tearDown(self): - self.widget.setAttribute(qt.Qt.WA_DeleteOnClose) - self.widget.close() - self.widget = None - TestCaseQt.tearDown(self) - - def testSignals(self): - """Test the signal emission of the widget""" - self.widget.setUpdateMode(StatsWidget.UpdateMode.AUTO) - modeChangedListener = SignalListener() - manualUpdateListener = SignalListener() - self.widget.sigUpdateModeChanged.connect(modeChangedListener) - self.widget.sigUpdateRequested.connect(manualUpdateListener) - self.widget.setUpdateMode(StatsWidget.UpdateMode.AUTO) - self.assertEqual(self.widget.getUpdateMode(), StatsWidget.UpdateMode.AUTO) - self.assertEqual(modeChangedListener.callCount(), 0) - self.qapp.processEvents() - - self.widget.setUpdateMode(StatsWidget.UpdateMode.MANUAL) - self.assertEqual(self.widget.getUpdateMode(), StatsWidget.UpdateMode.MANUAL) - self.qapp.processEvents() - self.assertEqual(modeChangedListener.callCount(), 1) - self.assertEqual(manualUpdateListener.callCount(), 0) - self.widget._updatePB.click() - self.widget._updatePB.click() - self.assertEqual(manualUpdateListener.callCount(), 2) - - self.widget._autoRB.setChecked(True) - self.assertEqual(modeChangedListener.callCount(), 2) - self.widget._updatePB.click() - self.assertEqual(manualUpdateListener.callCount(), 2) - - -class TestStatsROI(TestStatsBase, TestCaseQt): - """ - Test stats based on ROI - """ - def setUp(self): - TestCaseQt.setUp(self) - self.createRois() - TestStatsBase.setUp(self) - self.createHistogramContext() - - self.roiManager = RegionOfInterestManager(self.plot2d) - self.roiManager.addRoi(self._2Droi_rect) - self.roiManager.addRoi(self._2Droi_poly) - - def tearDown(self): - self.roiManager.clear() - self.roiManager = None - self._1Droi = None - self._2Droi_rect = None - self._2Droi_poly = None - self.plotHisto.setAttribute(qt.Qt.WA_DeleteOnClose) - self.plotHisto.close() - self.plotHisto = None - TestStatsBase.tearDown(self) - TestCaseQt.tearDown(self) - - def createRois(self): - self._1Droi = ROI(name='my1DRoi', fromdata=2.0, todata=5.0) - self._2Droi_rect = RectangleROI() - self._2Droi_rect.setGeometry(size=(10, 10), origin=(10, 0)) - self._2Droi_poly = PolygonROI() - points = numpy.array(((0, 20), (0, 0), (10, 0))) - self._2Droi_poly.setPoints(points=points) - - def createCurveContext(self): - TestStatsBase.createCurveContext(self) - self.curveContext = stats._CurveContext( - item=self.plot1d.getCurve('curve0'), - plot=self.plot1d, - onlimits=False, - roi=self._1Droi) - - def createHistogramContext(self): - self.plotHisto = Plot1D() - x = range(20) - y = range(20) - self.plotHisto.addHistogram(x, y, legend='histo0') - - self.histoContext = stats._HistogramContext( - item=self.plotHisto.getHistogram('histo0'), - plot=self.plotHisto, - onlimits=False, - roi=self._1Droi) - - def createScatterContext(self): - TestStatsBase.createScatterContext(self) - self.scatterContext = stats._ScatterContext( - item=self.scatterPlot.getScatter('scatter plot'), - plot=self.scatterPlot, - onlimits=False, - roi=self._1Droi - ) - - def createImageContext(self): - TestStatsBase.createImageContext(self) - - self.imageContext = stats._ImageContext( - item=self.plot2d.getImage(self._imgLgd), - plot=self.plot2d, - onlimits=False, - roi=self._2Droi_rect - ) - - self.imageContext_2 = stats._ImageContext( - item=self.plot2d.getImage(self._imgLgd), - plot=self.plot2d, - onlimits=False, - roi=self._2Droi_poly - ) - - def testErrors(self): - # test if onlimits is True and give also a roi - with self.assertRaises(ValueError): - stats._CurveContext(item=self.plot1d.getCurve('curve0'), - plot=self.plot1d, - onlimits=True, - roi=self._1Droi) - - # test if is a curve context and give an invalid 2D roi - with self.assertRaises(TypeError): - stats._CurveContext(item=self.plot1d.getCurve('curve0'), - plot=self.plot1d, - onlimits=False, - roi=self._2Droi_rect) - - def testBasicStatsCurve(self): - """Test result for simple stats on a curve""" - _stats = self.getBasicStats() - xData = yData = numpy.array(range(0, 10)) - self.assertEqual(_stats['min'].calculate(self.curveContext), 2) - self.assertEqual(_stats['max'].calculate(self.curveContext), 5) - self.assertEqual(_stats['minCoords'].calculate(self.curveContext), (2,)) - self.assertEqual(_stats['maxCoords'].calculate(self.curveContext), (5,)) - self.assertEqual(_stats['std'].calculate(self.curveContext), numpy.std(yData[2:6])) - self.assertEqual(_stats['mean'].calculate(self.curveContext), numpy.mean(yData[2:6])) - com = numpy.sum(xData[2:6] * yData[2:6]) / numpy.sum(yData[2:6]) - self.assertEqual(_stats['com'].calculate(self.curveContext), com) - - def testBasicStatsImageRectRoi(self): - """Test result for simple stats on an image""" - self.assertEqual(self.imageContext.values.compressed().size, 121) - _stats = self.getBasicStats() - self.assertEqual(_stats['min'].calculate(self.imageContext), 10) - self.assertEqual(_stats['max'].calculate(self.imageContext), 1300) - self.assertEqual(_stats['minCoords'].calculate(self.imageContext), (10, 0)) - self.assertEqual(_stats['maxCoords'].calculate(self.imageContext), (20.0, 10.0)) - self.assertAlmostEqual(_stats['std'].calculate(self.imageContext), - numpy.std(self.imageData[0:11, 10:21])) - self.assertAlmostEqual(_stats['mean'].calculate(self.imageContext), - numpy.mean(self.imageData[0:11, 10:21])) - - compressed_values = self.imageContext.values.compressed() - compressed_values = compressed_values.reshape(11, 11) - yData = numpy.sum(compressed_values.astype(numpy.float64), axis=1) - xData = numpy.sum(compressed_values.astype(numpy.float64), axis=0) - - dataYRange = range(11) - dataXRange = range(10, 21) - - ycom = numpy.sum(yData*dataYRange) / numpy.sum(yData) - xcom = numpy.sum(xData*dataXRange) / numpy.sum(xData) - self.assertEqual(_stats['com'].calculate(self.imageContext), (xcom, ycom)) - - def testBasicStatsImagePolyRoi(self): - """Test a simple rectangle ROI""" - _stats = self.getBasicStats() - self.assertEqual(_stats['min'].calculate(self.imageContext_2), 0) - self.assertEqual(_stats['max'].calculate(self.imageContext_2), 2432) - self.assertEqual(_stats['minCoords'].calculate(self.imageContext_2), (0.0, 0.0)) - # not 0.0, 19.0 because not fully in. Should all pixel have a weight, - # on to manage them in stats. For now 0 if the center is not in, else 1 - self.assertEqual(_stats['maxCoords'].calculate(self.imageContext_2), (0.0, 19.0)) - - def testBasicStatsScatter(self): - self.assertEqual(self.scatterContext.values.compressed().size, 2) - _stats = self.getBasicStats() - self.assertEqual(_stats['min'].calculate(self.scatterContext), 6) - self.assertEqual(_stats['max'].calculate(self.scatterContext), 7) - self.assertEqual(_stats['minCoords'].calculate(self.scatterContext), (2, 3)) - self.assertEqual(_stats['maxCoords'].calculate(self.scatterContext), (3, 4)) - self.assertEqual(_stats['std'].calculate(self.scatterContext), numpy.std([6, 7])) - self.assertEqual(_stats['mean'].calculate(self.scatterContext), numpy.mean([6, 7])) - - def testBasicHistogram(self): - _stats = self.getBasicStats() - xData = yData = numpy.array(range(2, 6)) - self.assertEqual(_stats['min'].calculate(self.histoContext), 2) - self.assertEqual(_stats['max'].calculate(self.histoContext), 5) - self.assertEqual(_stats['minCoords'].calculate(self.histoContext), (2,)) - self.assertEqual(_stats['maxCoords'].calculate(self.histoContext), (5,)) - self.assertEqual(_stats['std'].calculate(self.histoContext), numpy.std(yData)) - self.assertEqual(_stats['mean'].calculate(self.histoContext), numpy.mean(yData)) - com = numpy.sum(xData * yData) / numpy.sum(yData) - self.assertEqual(_stats['com'].calculate(self.histoContext), com) - - -class TestAdvancedROIImageContext(TestCaseQt): - """Test stats result on an image context with different scale and - origins""" - - def setUp(self): - TestCaseQt.setUp(self) - self.data_dims = (100, 100) - self.data = numpy.random.rand(*self.data_dims) - self.plot = Plot2D() - - def test(self): - """Test stats result on an image context with different scale and - origins""" - roi_origins = [(0, 0), (2, 10), (14, 20)] - img_origins = [(0, 0), (14, 20), (2, 10)] - img_scales = [1.0, 0.5, 2.0] - _stats = {'sum': stats.Stat(name='sum', fct=numpy.sum), } - for roi_origin in roi_origins: - for img_origin in img_origins: - for img_scale in img_scales: - with self.subTest(roi_origin=roi_origin, - img_origin=img_origin, - img_scale=img_scale): - self.plot.addImage(self.data, legend='img', - origin=img_origin, - scale=img_scale) - roi = RectangleROI() - roi.setGeometry(origin=roi_origin, size=(20, 20)) - context = stats._ImageContext( - item=self.plot.getImage('img'), - plot=self.plot, - onlimits=False, - roi=roi) - x_start = int((roi_origin[0] - img_origin[0]) / img_scale) - x_end = int(x_start + (20 / img_scale)) + 1 - y_start = int((roi_origin[1] - img_origin[1])/ img_scale) - y_end = int(y_start + (20 / img_scale)) + 1 - x_start = max(x_start, 0) - x_end = min(max(x_end, 0), self.data_dims[1]) - y_start = max(y_start, 0) - y_end = min(max(y_end, 0), self.data_dims[0]) - th_sum = numpy.sum(self.data[y_start:y_end, x_start:x_end]) - self.assertAlmostEqual(_stats['sum'].calculate(context), - th_sum) - -def suite(): - test_suite = unittest.TestSuite() - for TestClass in (TestStats, TestStatsHandler, TestStatsWidgetWithScatters, - TestStatsWidgetWithImages, TestStatsWidgetWithCurves, - TestStatsFormatter, TestEmptyStatsWidget, TestStatsROI, - TestLineWidget, TestUpdateModeWidget, ): - test_suite.addTest( - unittest.defaultTestLoader.loadTestsFromTestCase(TestClass)) - return test_suite - - -if __name__ == '__main__': - unittest.main(defaultTest='suite') diff --git a/silx/gui/plot/test/testUtilsAxis.py b/silx/gui/plot/test/testUtilsAxis.py deleted file mode 100644 index 64373b8..0000000 --- a/silx/gui/plot/test/testUtilsAxis.py +++ /dev/null @@ -1,214 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# -# Copyright (c) 2016 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 PlotWidget""" - -__authors__ = ["V. Valls"] -__license__ = "MIT" -__date__ = "20/11/2018" - - -import unittest -from silx.gui.plot import PlotWidget -from silx.gui.utils.testutils import TestCaseQt -from silx.gui.plot.utils.axis import SyncAxes - - -class TestAxisSync(TestCaseQt): - """Tests AxisSync class""" - - def setUp(self): - TestCaseQt.setUp(self) - self.plot1 = PlotWidget() - self.plot2 = PlotWidget() - self.plot3 = PlotWidget() - - def tearDown(self): - self.plot1 = None - self.plot2 = None - self.plot3 = None - TestCaseQt.tearDown(self) - - def testMoveFirstAxis(self): - """Test synchronization after construction""" - _sync = SyncAxes([self.plot1.getXAxis(), self.plot2.getXAxis(), self.plot3.getXAxis()]) - - self.plot1.getXAxis().setLimits(10, 500) - self.assertEqual(self.plot1.getXAxis().getLimits(), (10, 500)) - self.assertEqual(self.plot2.getXAxis().getLimits(), (10, 500)) - self.assertEqual(self.plot3.getXAxis().getLimits(), (10, 500)) - - def testMoveSecondAxis(self): - """Test synchronization after construction""" - _sync = SyncAxes([self.plot1.getXAxis(), self.plot2.getXAxis(), self.plot3.getXAxis()]) - - self.plot2.getXAxis().setLimits(10, 500) - self.assertEqual(self.plot1.getXAxis().getLimits(), (10, 500)) - self.assertEqual(self.plot2.getXAxis().getLimits(), (10, 500)) - self.assertEqual(self.plot3.getXAxis().getLimits(), (10, 500)) - - def testMoveTwoAxes(self): - """Test synchronization after construction""" - _sync = SyncAxes([self.plot1.getXAxis(), self.plot2.getXAxis(), self.plot3.getXAxis()]) - - self.plot1.getXAxis().setLimits(1, 50) - self.plot2.getXAxis().setLimits(10, 500) - self.assertEqual(self.plot1.getXAxis().getLimits(), (10, 500)) - self.assertEqual(self.plot2.getXAxis().getLimits(), (10, 500)) - self.assertEqual(self.plot3.getXAxis().getLimits(), (10, 500)) - - def testDestruction(self): - """Test synchronization when sync object is destroyed""" - sync = SyncAxes([self.plot1.getXAxis(), self.plot2.getXAxis(), self.plot3.getXAxis()]) - del sync - - self.plot1.getXAxis().setLimits(10, 500) - self.assertEqual(self.plot1.getXAxis().getLimits(), (10, 500)) - self.assertNotEqual(self.plot2.getXAxis().getLimits(), (10, 500)) - self.assertNotEqual(self.plot3.getXAxis().getLimits(), (10, 500)) - - def testAxisDestruction(self): - """Test synchronization when an axis disappear""" - _sync = SyncAxes([self.plot1.getXAxis(), self.plot2.getXAxis(), self.plot3.getXAxis()]) - - # Destroy the plot is possible - import weakref - plot = weakref.ref(self.plot2) - self.plot2 = None - result = self.qWaitForDestroy(plot) - if not result: - # We can't test - self.skipTest("Object not destroyed") - - self.plot1.getXAxis().setLimits(10, 500) - self.assertEqual(self.plot3.getXAxis().getLimits(), (10, 500)) - - def testStop(self): - """Test synchronization after calling stop""" - sync = SyncAxes([self.plot1.getXAxis(), self.plot2.getXAxis(), self.plot3.getXAxis()]) - sync.stop() - - self.plot1.getXAxis().setLimits(10, 500) - self.assertEqual(self.plot1.getXAxis().getLimits(), (10, 500)) - self.assertNotEqual(self.plot2.getXAxis().getLimits(), (10, 500)) - self.assertNotEqual(self.plot3.getXAxis().getLimits(), (10, 500)) - - def testStopMovingStart(self): - """Test synchronization after calling stop, moving an axis, then start again""" - sync = SyncAxes([self.plot1.getXAxis(), self.plot2.getXAxis(), self.plot3.getXAxis()]) - sync.stop() - self.plot1.getXAxis().setLimits(10, 500) - self.plot2.getXAxis().setLimits(1, 50) - self.assertEqual(self.plot1.getXAxis().getLimits(), (10, 500)) - sync.start() - - # The first axis is the reference - self.assertEqual(self.plot1.getXAxis().getLimits(), (10, 500)) - self.assertEqual(self.plot2.getXAxis().getLimits(), (10, 500)) - self.assertEqual(self.plot3.getXAxis().getLimits(), (10, 500)) - - def testDoubleStop(self): - """Test double stop""" - sync = SyncAxes([self.plot1.getXAxis(), self.plot2.getXAxis(), self.plot3.getXAxis()]) - sync.stop() - self.assertRaises(RuntimeError, sync.stop) - - def testDoubleStart(self): - """Test double stop""" - sync = SyncAxes([self.plot1.getXAxis(), self.plot2.getXAxis(), self.plot3.getXAxis()]) - self.assertRaises(RuntimeError, sync.start) - - def testScale(self): - """Test scale change""" - _sync = SyncAxes([self.plot1.getXAxis(), self.plot2.getXAxis(), self.plot3.getXAxis()]) - self.plot1.getXAxis().setScale(self.plot1.getXAxis().LOGARITHMIC) - self.assertEqual(self.plot1.getXAxis().getScale(), self.plot1.getXAxis().LOGARITHMIC) - self.assertEqual(self.plot2.getXAxis().getScale(), self.plot1.getXAxis().LOGARITHMIC) - self.assertEqual(self.plot3.getXAxis().getScale(), self.plot1.getXAxis().LOGARITHMIC) - - def testDirection(self): - """Test direction change""" - _sync = SyncAxes([self.plot1.getYAxis(), self.plot2.getYAxis(), self.plot3.getYAxis()]) - self.plot1.getYAxis().setInverted(True) - self.assertEqual(self.plot1.getYAxis().isInverted(), True) - self.assertEqual(self.plot2.getYAxis().isInverted(), True) - self.assertEqual(self.plot3.getYAxis().isInverted(), True) - - def testSyncCenter(self): - """Test direction change""" - # Not the same scale - self.plot1.getXAxis().setLimits(0, 200) - self.plot2.getXAxis().setLimits(0, 20) - self.plot3.getXAxis().setLimits(0, 2) - _sync = SyncAxes([self.plot1.getXAxis(), self.plot2.getXAxis(), self.plot3.getXAxis()], - syncLimits=False, syncCenter=True) - - self.assertEqual(self.plot1.getXAxis().getLimits(), (0, 200)) - self.assertEqual(self.plot2.getXAxis().getLimits(), (100 - 10, 100 + 10)) - self.assertEqual(self.plot3.getXAxis().getLimits(), (100 - 1, 100 + 1)) - - def testSyncCenterAndZoom(self): - """Test direction change""" - # Not the same scale - self.plot1.getXAxis().setLimits(0, 200) - self.plot2.getXAxis().setLimits(0, 20) - self.plot3.getXAxis().setLimits(0, 2) - _sync = SyncAxes([self.plot1.getXAxis(), self.plot2.getXAxis(), self.plot3.getXAxis()], - syncLimits=False, syncCenter=True, syncZoom=True) - - # Supposing all the plots use the same size - self.assertEqual(self.plot1.getXAxis().getLimits(), (0, 200)) - self.assertEqual(self.plot2.getXAxis().getLimits(), (0, 200)) - self.assertEqual(self.plot3.getXAxis().getLimits(), (0, 200)) - - def testAddAxis(self): - """Test synchronization after construction""" - sync = SyncAxes([self.plot1.getXAxis(), self.plot2.getXAxis()]) - sync.addAxis(self.plot3.getXAxis()) - - self.plot1.getXAxis().setLimits(10, 500) - self.assertEqual(self.plot1.getXAxis().getLimits(), (10, 500)) - self.assertEqual(self.plot2.getXAxis().getLimits(), (10, 500)) - self.assertEqual(self.plot3.getXAxis().getLimits(), (10, 500)) - - def testRemoveAxis(self): - """Test synchronization after construction""" - sync = SyncAxes([self.plot1.getXAxis(), self.plot2.getXAxis(), self.plot3.getXAxis()]) - sync.removeAxis(self.plot3.getXAxis()) - - self.plot1.getXAxis().setLimits(10, 500) - self.assertEqual(self.plot1.getXAxis().getLimits(), (10, 500)) - self.assertEqual(self.plot2.getXAxis().getLimits(), (10, 500)) - self.assertNotEqual(self.plot3.getXAxis().getLimits(), (10, 500)) - - -def suite(): - test_suite = unittest.TestSuite() - loadTests = unittest.defaultTestLoader.loadTestsFromTestCase - test_suite.addTest(loadTests(TestAxisSync)) - return test_suite - - -if __name__ == '__main__': - unittest.main(defaultTest='suite') diff --git a/silx/gui/plot/test/utils.py b/silx/gui/plot/test/utils.py deleted file mode 100644 index ed1917a..0000000 --- a/silx/gui/plot/test/utils.py +++ /dev/null @@ -1,94 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# -# Copyright (c) 2016-2018 European Synchrotron Radiation Facility -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# 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 PlotWidget""" - -__authors__ = ["T. Vincent"] -__license__ = "MIT" -__date__ = "26/01/2018" - - -import logging - -from silx.gui.utils.testutils import TestCaseQt - -from silx.gui import qt -from silx.gui.plot import PlotWidget - - -logger = logging.getLogger(__name__) - - -class PlotWidgetTestCase(TestCaseQt): - """Base class for tests of PlotWidget, not a TestCase in itself. - - plot attribute is the PlotWidget created for the test. - """ - - __screenshot_already_taken = False - - def __init__(self, methodName='runTest', backend=None): - TestCaseQt.__init__(self, methodName=methodName) - self.__backend = backend - - def _createPlot(self): - return PlotWidget(backend=self.__backend) - - def setUp(self): - super(PlotWidgetTestCase, self).setUp() - self.plot = self._createPlot() - self.plot.show() - self.plotAlive = True - self.qWaitForWindowExposed(self.plot) - TestCaseQt.mouseClick(self, self.plot, button=qt.Qt.LeftButton, pos=(0, 0)) - - def __onPlotDestroyed(self): - self.plotAlive = False - - def _waitForPlotClosed(self): - self.plot.setAttribute(qt.Qt.WA_DeleteOnClose) - self.plot.destroyed.connect(self.__onPlotDestroyed) - self.plot.close() - del self.plot - for _ in range(100): - if not self.plotAlive: - break - self.qWait(10) - else: - logger.error("Plot is still alive") - - def tearDown(self): - if not self._currentTestSucceeded(): - # MPL is the only widget which uses the real system mouse. - # In case of a the windows is outside of the screen, minimzed, - # overlapped by a system popup, the MPL widget will not receive the - # mouse event. - # Taking a screenshot help debuging this cases in the continuous - # integration environement. - if not PlotWidgetTestCase.__screenshot_already_taken: - PlotWidgetTestCase.__screenshot_already_taken = True - self.logScreenShot() - self.qapp.processEvents() - self._waitForPlotClosed() - super(PlotWidgetTestCase, self).tearDown() |