diff options
author | Picca Frédéric-Emmanuel <picca@debian.org> | 2022-02-02 14:20:08 +0100 |
---|---|---|
committer | Picca Frédéric-Emmanuel <picca@debian.org> | 2022-02-02 14:20:08 +0100 |
commit | 57f0326e359e3cde2e07798962bb3338a4992f69 (patch) | |
tree | 391091598e3f0483063ba67ebd1477336a7b2d04 /silx/gui/plot/tools/test | |
parent | 7e9ae6407baa168a6ac892d4da70488f85f203c7 (diff) | |
parent | 4e774db12d5ebe7a20eded6dd434a289e27999e5 (diff) |
Update upstream source from tag 'upstream/1.0.0+dfsg'
Update to upstream version '1.0.0+dfsg'
with Debian dir 4f303792de4ba2e28ebf523038bc9f0057d7f3a7
Diffstat (limited to 'silx/gui/plot/tools/test')
-rw-r--r-- | silx/gui/plot/tools/test/__init__.py | 52 | ||||
-rw-r--r-- | silx/gui/plot/tools/test/testCurveLegendsWidget.py | 125 | ||||
-rw-r--r-- | silx/gui/plot/tools/test/testProfile.py | 673 | ||||
-rw-r--r-- | silx/gui/plot/tools/test/testROI.py | 694 | ||||
-rw-r--r-- | silx/gui/plot/tools/test/testScatterProfileToolBar.py | 196 | ||||
-rw-r--r-- | silx/gui/plot/tools/test/testTools.py | 147 |
6 files changed, 0 insertions, 1887 deletions
diff --git a/silx/gui/plot/tools/test/__init__.py b/silx/gui/plot/tools/test/__init__.py deleted file mode 100644 index 1429545..0000000 --- a/silx/gui/plot/tools/test/__init__.py +++ /dev/null @@ -1,52 +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. -# -# ###########################################################################*/ -__authors__ = ["T. Vincent"] -__license__ = "MIT" -__date__ = "26/03/2018" - - -import unittest - -from . import testROI -from . import testTools -from . import testScatterProfileToolBar -from . import testCurveLegendsWidget -from . import testProfile - - -def suite(): - test_suite = unittest.TestSuite() - test_suite.addTests( - [testROI.suite(), - testTools.suite(), - testScatterProfileToolBar.suite(), - testCurveLegendsWidget.suite(), - testProfile.suite(), - ]) - return test_suite - - -if __name__ == '__main__': - unittest.main(defaultTest='suite') diff --git a/silx/gui/plot/tools/test/testCurveLegendsWidget.py b/silx/gui/plot/tools/test/testCurveLegendsWidget.py deleted file mode 100644 index 4824dd7..0000000 --- a/silx/gui/plot/tools/test/testCurveLegendsWidget.py +++ /dev/null @@ -1,125 +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. -# -# ###########################################################################*/ -__authors__ = ["T. Vincent"] -__license__ = "MIT" -__date__ = "02/08/2018" - - -import unittest - -from silx.gui import qt -from silx.utils.testutils import ParametricTestCase -from silx.gui.utils.testutils import TestCaseQt -from silx.gui.plot import PlotWindow -from silx.gui.plot.tools import CurveLegendsWidget - - -class TestCurveLegendsWidget(TestCaseQt, ParametricTestCase): - """Tests for CurveLegendsWidget class""" - - def setUp(self): - super(TestCurveLegendsWidget, self).setUp() - self.plot = PlotWindow() - - self.legends = CurveLegendsWidget.CurveLegendsWidget() - self.legends.setPlotWidget(self.plot) - - dock = qt.QDockWidget() - dock.setWindowTitle('Curve Legends') - dock.setWidget(self.legends) - self.plot.addTabbedDockWidget(dock) - - self.plot.show() - self.qWaitForWindowExposed(self.plot) - - def tearDown(self): - del self.legends - self.qapp.processEvents() - self.plot.setAttribute(qt.Qt.WA_DeleteOnClose) - self.plot.close() - del self.plot - super(TestCurveLegendsWidget, self).tearDown() - - def _assertNbLegends(self, count): - """Check the number of legends in the CurveLegendsWidget""" - children = self.legends.findChildren(CurveLegendsWidget._LegendWidget) - self.assertEqual(len(children), count) - - def testAddRemoveCurves(self): - """Test CurveLegendsWidget while adding/removing curves""" - self.plot.addCurve((0, 1), (1, 2), legend='a') - self._assertNbLegends(1) - self.plot.addCurve((0, 1), (2, 3), legend='b') - self._assertNbLegends(2) - - # Detached/attach - self.legends.setPlotWidget(None) - self._assertNbLegends(0) - - self.legends.setPlotWidget(self.plot) - self._assertNbLegends(2) - - self.plot.clear() - self._assertNbLegends(0) - - def testUpdateCurves(self): - """Test CurveLegendsWidget while updating curves """ - self.plot.addCurve((0, 1), (1, 2), legend='a') - self._assertNbLegends(1) - self.plot.addCurve((0, 1), (2, 3), legend='b') - self._assertNbLegends(2) - - # Activate curve - self.plot.setActiveCurve('a') - self.qapp.processEvents() - self.plot.setActiveCurve('b') - self.qapp.processEvents() - - # Change curve style - curve = self.plot.getCurve('a') - curve.setLineWidth(2) - for linestyle in (':', '', '--', '-'): - with self.subTest(linestyle=linestyle): - curve.setLineStyle(linestyle) - self.qapp.processEvents() - self.qWait(1000) - - for symbol in ('o', 'd', '', 's'): - with self.subTest(symbol=symbol): - curve.setSymbol(symbol) - self.qapp.processEvents() - self.qWait(1000) - - -def suite(): - test_suite = unittest.TestSuite() - test_suite.addTest( - unittest.defaultTestLoader.loadTestsFromTestCase( - TestCurveLegendsWidget)) - return test_suite - - -if __name__ == '__main__': - unittest.main(defaultTest='suite') diff --git a/silx/gui/plot/tools/test/testProfile.py b/silx/gui/plot/tools/test/testProfile.py deleted file mode 100644 index 444cfe0..0000000 --- a/silx/gui/plot/tools/test/testProfile.py +++ /dev/null @@ -1,673 +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. -# -# ###########################################################################*/ -__authors__ = ["T. Vincent"] -__license__ = "MIT" -__date__ = "28/06/2018" - - -import unittest -import contextlib -import numpy -import logging - -from silx.gui import qt -from silx.utils import deprecation -from silx.utils import testutils - -from silx.gui.utils.testutils import TestCaseQt -from silx.utils.testutils import ParametricTestCase -from silx.gui.plot import PlotWindow, Plot1D, Plot2D, Profile -from silx.gui.plot.StackView import StackView -from silx.gui.plot.tools.profile import rois -from silx.gui.plot.tools.profile import editors -from silx.gui.plot.items import roi as roi_items -from silx.gui.plot.tools.profile import manager -from silx.gui import plot as silx_plot - -_logger = logging.getLogger(__name__) - - -class TestRois(TestCaseQt): - - def test_init(self): - """Check that the constructor is not called twice""" - roi = rois.ProfileImageVerticalLineROI() - if qt.BINDING not in ["PySide", "PySide2"]: - # the profile ROI + the shape - self.assertEqual(roi.receivers(roi.sigRegionChanged), 2) - - -class TestInteractions(TestCaseQt): - - @contextlib.contextmanager - def defaultPlot(self): - try: - widget = silx_plot.PlotWidget() - widget.show() - self.qWaitForWindowExposed(widget) - yield widget - finally: - widget.close() - widget = None - self.qWait() - - @contextlib.contextmanager - def imagePlot(self): - try: - widget = silx_plot.Plot2D() - image = numpy.arange(10 * 10).reshape(10, -1) - widget.addImage(image) - widget.show() - self.qWaitForWindowExposed(widget) - yield widget - finally: - widget.close() - widget = None - self.qWait() - - @contextlib.contextmanager - def scatterPlot(self): - try: - widget = silx_plot.ScatterView() - - nbX, nbY = 7, 5 - yy = numpy.atleast_2d(numpy.ones(nbY)).T - xx = numpy.atleast_2d(numpy.ones(nbX)) - positionX = numpy.linspace(10, 50, nbX) * yy - positionX = positionX.reshape(nbX * nbY) - positionY = numpy.atleast_2d(numpy.linspace(20, 60, nbY)).T * xx - positionY = positionY.reshape(nbX * nbY) - values = numpy.arange(nbX * nbY) - - widget.setData(positionX, positionY, values) - widget.resetZoom() - widget.show() - self.qWaitForWindowExposed(widget) - yield widget.getPlotWidget() - finally: - widget.close() - widget = None - self.qWait() - - @contextlib.contextmanager - def stackPlot(self): - try: - widget = silx_plot.StackView() - image = numpy.arange(10 * 10).reshape(10, -1) - cube = numpy.array([image, image, image]) - widget.setStack(cube) - widget.resetZoom() - widget.show() - self.qWaitForWindowExposed(widget) - yield widget.getPlotWidget() - finally: - widget.close() - widget = None - self.qWait() - - def waitPendingOperations(self, proflie): - for _ in range(10): - if not proflie.hasPendingOperations(): - return - self.qWait(100) - _logger.error("The profile manager still have pending operations") - - def genericRoiTest(self, plot, roiClass): - profileManager = manager.ProfileManager(plot, plot) - profileManager.setItemType(image=True, scatter=True) - - try: - action = profileManager.createProfileAction(roiClass, plot) - action.triggered[bool].emit(True) - widget = plot.getWidgetHandle() - - # Do the mouse interaction - pos1 = widget.width() * 0.4, widget.height() * 0.4 - self.mouseMove(widget, pos=pos1) - self.mouseClick(widget, qt.Qt.LeftButton, pos=pos1) - - if issubclass(roiClass, roi_items.LineROI): - pos2 = widget.width() * 0.6, widget.height() * 0.6 - self.mouseMove(widget, pos=pos2) - self.mouseClick(widget, qt.Qt.LeftButton, pos=pos2) - - self.waitPendingOperations(profileManager) - - # Test that something was computed - if issubclass(roiClass, rois._ProfileCrossROI): - self.assertEqual(profileManager._computedProfiles, 2) - elif issubclass(roiClass, roi_items.LineROI): - self.assertGreaterEqual(profileManager._computedProfiles, 1) - else: - self.assertEqual(profileManager._computedProfiles, 1) - - # Test the created ROIs - profileRois = profileManager.getRoiManager().getRois() - if issubclass(roiClass, rois._ProfileCrossROI): - self.assertEqual(len(profileRois), 3) - else: - self.assertEqual(len(profileRois), 1) - # The first one should be the expected one - roi = profileRois[0] - - # Test that something was displayed - if issubclass(roiClass, rois._ProfileCrossROI): - profiles = roi._getLines() - window = profiles[0].getProfileWindow() - self.assertIsNotNone(window) - window = profiles[1].getProfileWindow() - self.assertIsNotNone(window) - else: - window = roi.getProfileWindow() - self.assertIsNotNone(window) - finally: - profileManager.clearProfile() - - def testImageActions(self): - roiClasses = [ - rois.ProfileImageHorizontalLineROI, - rois.ProfileImageVerticalLineROI, - rois.ProfileImageLineROI, - rois.ProfileImageCrossROI, - ] - with self.imagePlot() as plot: - for roiClass in roiClasses: - with self.subTest(roiClass=roiClass): - self.genericRoiTest(plot, roiClass) - - def testScatterActions(self): - roiClasses = [ - rois.ProfileScatterHorizontalLineROI, - rois.ProfileScatterVerticalLineROI, - rois.ProfileScatterLineROI, - rois.ProfileScatterCrossROI, - rois.ProfileScatterHorizontalSliceROI, - rois.ProfileScatterVerticalSliceROI, - rois.ProfileScatterCrossSliceROI, - ] - with self.scatterPlot() as plot: - for roiClass in roiClasses: - with self.subTest(roiClass=roiClass): - self.genericRoiTest(plot, roiClass) - - def testStackActions(self): - roiClasses = [ - rois.ProfileImageStackHorizontalLineROI, - rois.ProfileImageStackVerticalLineROI, - rois.ProfileImageStackLineROI, - rois.ProfileImageStackCrossROI, - ] - with self.stackPlot() as plot: - for roiClass in roiClasses: - with self.subTest(roiClass=roiClass): - self.genericRoiTest(plot, roiClass) - - def genericEditorTest(self, plot, roi, editor): - if isinstance(editor, editors._NoProfileRoiEditor): - pass - elif isinstance(editor, editors._DefaultImageStackProfileRoiEditor): - # GUI to ROI - editor._lineWidth.setValue(2) - self.assertEqual(roi.getProfileLineWidth(), 2) - editor._methodsButton.setMethod("sum") - self.assertEqual(roi.getProfileMethod(), "sum") - editor._profileDim.setDimension(1) - self.assertEqual(roi.getProfileType(), "1D") - # ROI to GUI - roi.setProfileLineWidth(3) - self.assertEqual(editor._lineWidth.value(), 3) - roi.setProfileMethod("mean") - self.assertEqual(editor._methodsButton.getMethod(), "mean") - roi.setProfileType("2D") - self.assertEqual(editor._profileDim.getDimension(), 2) - elif isinstance(editor, editors._DefaultImageProfileRoiEditor): - # GUI to ROI - editor._lineWidth.setValue(2) - self.assertEqual(roi.getProfileLineWidth(), 2) - editor._methodsButton.setMethod("sum") - self.assertEqual(roi.getProfileMethod(), "sum") - # ROI to GUI - roi.setProfileLineWidth(3) - self.assertEqual(editor._lineWidth.value(), 3) - roi.setProfileMethod("mean") - self.assertEqual(editor._methodsButton.getMethod(), "mean") - elif isinstance(editor, editors._DefaultScatterProfileRoiEditor): - # GUI to ROI - editor._nPoints.setValue(100) - self.assertEqual(roi.getNPoints(), 100) - # ROI to GUI - roi.setNPoints(200) - self.assertEqual(editor._nPoints.value(), 200) - else: - assert False - - def testEditors(self): - roiClasses = [ - (rois.ProfileImageHorizontalLineROI, editors._DefaultImageProfileRoiEditor), - (rois.ProfileImageVerticalLineROI, editors._DefaultImageProfileRoiEditor), - (rois.ProfileImageLineROI, editors._DefaultImageProfileRoiEditor), - (rois.ProfileImageCrossROI, editors._DefaultImageProfileRoiEditor), - (rois.ProfileScatterHorizontalLineROI, editors._DefaultScatterProfileRoiEditor), - (rois.ProfileScatterVerticalLineROI, editors._DefaultScatterProfileRoiEditor), - (rois.ProfileScatterLineROI, editors._DefaultScatterProfileRoiEditor), - (rois.ProfileScatterCrossROI, editors._DefaultScatterProfileRoiEditor), - (rois.ProfileScatterHorizontalSliceROI, editors._NoProfileRoiEditor), - (rois.ProfileScatterVerticalSliceROI, editors._NoProfileRoiEditor), - (rois.ProfileScatterCrossSliceROI, editors._NoProfileRoiEditor), - (rois.ProfileImageStackHorizontalLineROI, editors._DefaultImageStackProfileRoiEditor), - (rois.ProfileImageStackVerticalLineROI, editors._DefaultImageStackProfileRoiEditor), - (rois.ProfileImageStackLineROI, editors._DefaultImageStackProfileRoiEditor), - (rois.ProfileImageStackCrossROI, editors._DefaultImageStackProfileRoiEditor), - ] - with self.defaultPlot() as plot: - profileManager = manager.ProfileManager(plot, plot) - editorAction = profileManager.createEditorAction(parent=plot) - for roiClass, editorClass in roiClasses: - with self.subTest(roiClass=roiClass): - roi = roiClass() - roi._setProfileManager(profileManager) - try: - # Force widget creation - menu = qt.QMenu(plot) - menu.addAction(editorAction) - widgets = editorAction.createdWidgets() - self.assertGreater(len(widgets), 0) - - editorAction.setProfileRoi(roi) - editorWidget = editorAction._getEditor(widgets[0]) - self.assertIsInstance(editorWidget, editorClass) - self.genericEditorTest(plot, roi, editorWidget) - finally: - editorAction.setProfileRoi(None) - menu.deleteLater() - menu = None - self.qapp.processEvents() - - -class TestProfileToolBar(TestCaseQt, ParametricTestCase): - """Tests for ProfileToolBar widget.""" - - def setUp(self): - super(TestProfileToolBar, self).setUp() - self.plot = PlotWindow() - self.toolBar = Profile.ProfileToolBar(plot=self.plot) - self.plot.addToolBar(self.toolBar) - - self.plot.show() - self.qWaitForWindowExposed(self.plot) - - self.mouseMove(self.plot) # Move to center - self.qapp.processEvents() - deprecation.FORCE = True - - def tearDown(self): - deprecation.FORCE = False - self.qapp.processEvents() - profileManager = self.toolBar.getProfileManager() - profileManager.clearProfile() - profileManager = None - self.plot.setAttribute(qt.Qt.WA_DeleteOnClose) - self.plot.close() - del self.plot - del self.toolBar - - super(TestProfileToolBar, self).tearDown() - - def testAlignedProfile(self): - """Test horizontal and vertical profile, without and with image""" - # Use Plot backend widget to submit mouse events - widget = self.plot.getWidgetHandle() - for method in ('sum', 'mean'): - with self.subTest(method=method): - # 2 positions to use for mouse events - pos1 = widget.width() * 0.4, widget.height() * 0.4 - pos2 = widget.width() * 0.6, widget.height() * 0.6 - - for action in (self.toolBar.hLineAction, self.toolBar.vLineAction): - with self.subTest(mode=action.text()): - # Trigger tool button for mode - action.trigger() - # Without image - self.mouseMove(widget, pos=pos1) - self.mouseClick(widget, qt.Qt.LeftButton, pos=pos1) - - # with image - self.plot.addImage( - numpy.arange(100 * 100).reshape(100, -1)) - self.mousePress(widget, qt.Qt.LeftButton, pos=pos1) - self.mouseMove(widget, pos=pos2) - self.mouseRelease(widget, qt.Qt.LeftButton, pos=pos2) - - self.mouseMove(widget) - self.mouseClick(widget, qt.Qt.LeftButton) - - manager = self.toolBar.getProfileManager() - for _ in range(20): - self.qWait(200) - if not manager.hasPendingOperations(): - break - - @testutils.test_logging(deprecation.depreclog.name, warning=4) - def testDiagonalProfile(self): - """Test diagonal profile, without and with image""" - # Use Plot backend widget to submit mouse events - widget = self.plot.getWidgetHandle() - - for method in ('sum', 'mean'): - for image in (False, True): - with self.subTest(method=method, image=image): - # 2 positions to use for mouse events - pos1 = widget.width() * 0.4, widget.height() * 0.4 - pos2 = widget.width() * 0.6, widget.height() * 0.6 - - if image: - self.plot.addImage( - numpy.arange(100 * 100).reshape(100, -1)) - - # Trigger tool button for diagonal profile mode - self.toolBar.lineAction.trigger() - - # draw profile line - widget.setFocus(qt.Qt.OtherFocusReason) - self.mouseMove(widget, pos=pos1) - self.qWait(100) - self.mousePress(widget, qt.Qt.LeftButton, pos=pos1) - self.qWait(100) - self.mouseMove(widget, pos=pos2) - self.qWait(100) - self.mouseRelease(widget, qt.Qt.LeftButton, pos=pos2) - self.qWait(100) - - manager = self.toolBar.getProfileManager() - - for _ in range(20): - self.qWait(200) - if not manager.hasPendingOperations(): - break - - roi = manager.getCurrentRoi() - self.assertIsNotNone(roi) - roi.setProfileLineWidth(3) - roi.setProfileMethod(method) - - for _ in range(20): - self.qWait(200) - if not manager.hasPendingOperations(): - break - - if image is True: - curveItem = self.toolBar.getProfilePlot().getAllCurves()[0] - if method == 'sum': - self.assertTrue(curveItem.getData()[1].max() > 10000) - elif method == 'mean': - self.assertTrue(curveItem.getData()[1].max() < 10000) - - # Remove the ROI so the profile window is also removed - roiManager = manager.getRoiManager() - roiManager.removeRoi(roi) - self.qWait(100) - - -class TestDeprecatedProfileToolBar(TestCaseQt): - """Tests old features of the ProfileToolBar widget.""" - - def setUp(self): - self.plot = None - super(TestDeprecatedProfileToolBar, self).setUp() - - def tearDown(self): - if self.plot is not None: - self.plot.setAttribute(qt.Qt.WA_DeleteOnClose) - self.plot.close() - self.plot = None - self.qWait() - - super(TestDeprecatedProfileToolBar, self).tearDown() - - @testutils.test_logging(deprecation.depreclog.name, warning=2) - def testCustomProfileWindow(self): - from silx.gui.plot import ProfileMainWindow - - self.plot = PlotWindow() - profileWindow = ProfileMainWindow.ProfileMainWindow(self.plot) - toolBar = Profile.ProfileToolBar(parent=self.plot, - plot=self.plot, - profileWindow=profileWindow) - - self.plot.show() - self.qWaitForWindowExposed(self.plot) - profileWindow.show() - self.qWaitForWindowExposed(profileWindow) - self.qapp.processEvents() - - self.plot.addImage(numpy.arange(10 * 10).reshape(10, -1)) - profile = rois.ProfileImageHorizontalLineROI() - profile.setPosition(5) - toolBar.getProfileManager().getRoiManager().addRoi(profile) - toolBar.getProfileManager().getRoiManager().setCurrentRoi(profile) - - for _ in range(20): - self.qWait(200) - if not toolBar.getProfileManager().hasPendingOperations(): - break - - # There is a displayed profile - self.assertIsNotNone(profileWindow.getProfile()) - self.assertIs(toolBar.getProfileMainWindow(), profileWindow) - - # There is nothing anymore but the window is still there - toolBar.getProfileManager().clearProfile() - self.qapp.processEvents() - self.assertIsNone(profileWindow.getProfile()) - - -class TestProfile3DToolBar(TestCaseQt): - """Tests for Profile3DToolBar widget. - """ - def setUp(self): - super(TestProfile3DToolBar, self).setUp() - self.plot = StackView() - self.plot.show() - self.qWaitForWindowExposed(self.plot) - - self.plot.setStack(numpy.array([ - [[0, 1, 2], [3, 4, 5]], - [[6, 7, 8], [9, 10, 11]], - [[12, 13, 14], [15, 16, 17]] - ])) - deprecation.FORCE = True - - def tearDown(self): - deprecation.FORCE = False - profileManager = self.plot.getProfileToolbar().getProfileManager() - profileManager.clearProfile() - profileManager = None - self.plot.setAttribute(qt.Qt.WA_DeleteOnClose) - self.plot.close() - self.plot = None - - super(TestProfile3DToolBar, self).tearDown() - - @testutils.test_logging(deprecation.depreclog.name, warning=2) - def testMethodProfile2D(self): - """Test that the profile can have a different method if we want to - compute then in 1D or in 2D""" - - toolBar = self.plot.getProfileToolbar() - - toolBar.vLineAction.trigger() - plot2D = self.plot.getPlotWidget().getWidgetHandle() - pos1 = plot2D.width() * 0.5, plot2D.height() * 0.5 - self.mouseClick(plot2D, qt.Qt.LeftButton, pos=pos1) - - manager = toolBar.getProfileManager() - roi = manager.getCurrentRoi() - roi.setProfileMethod("mean") - roi.setProfileType("2D") - roi.setProfileLineWidth(3) - - for _ in range(20): - self.qWait(200) - if not manager.hasPendingOperations(): - break - - # check 2D 'mean' profile - profilePlot = toolBar.getProfilePlot() - data = profilePlot.getAllImages()[0].getData() - expected = numpy.array([[1, 4], [7, 10], [13, 16]]) - numpy.testing.assert_almost_equal(data, expected) - - @testutils.test_logging(deprecation.depreclog.name, warning=2) - def testMethodSumLine(self): - """Simple interaction test to make sure the sum is correctly computed - """ - toolBar = self.plot.getProfileToolbar() - - toolBar.lineAction.trigger() - plot2D = self.plot.getPlotWidget().getWidgetHandle() - pos1 = plot2D.width() * 0.5, plot2D.height() * 0.2 - pos2 = plot2D.width() * 0.5, plot2D.height() * 0.8 - - self.mouseMove(plot2D, pos=pos1) - self.mousePress(plot2D, qt.Qt.LeftButton, pos=pos1) - self.mouseMove(plot2D, pos=pos2) - self.mouseRelease(plot2D, qt.Qt.LeftButton, pos=pos2) - - manager = toolBar.getProfileManager() - roi = manager.getCurrentRoi() - roi.setProfileMethod("sum") - roi.setProfileType("2D") - roi.setProfileLineWidth(3) - - for _ in range(20): - self.qWait(200) - if not manager.hasPendingOperations(): - break - - # check 2D 'sum' profile - profilePlot = toolBar.getProfilePlot() - data = profilePlot.getAllImages()[0].getData() - expected = numpy.array([[3, 12], [21, 30], [39, 48]]) - numpy.testing.assert_almost_equal(data, expected) - - -class TestGetProfilePlot(TestCaseQt): - - def setUp(self): - self.plot = None - super(TestGetProfilePlot, self).setUp() - - def tearDown(self): - if self.plot is not None: - manager = self.plot.getProfileToolbar().getProfileManager() - manager.clearProfile() - manager = None - self.plot.setAttribute(qt.Qt.WA_DeleteOnClose) - self.plot.close() - self.plot = None - - super(TestGetProfilePlot, self).tearDown() - - def testProfile1D(self): - self.plot = Plot2D() - self.plot.show() - self.qWaitForWindowExposed(self.plot) - self.plot.addImage([[0, 1], [2, 3]]) - - toolBar = self.plot.getProfileToolbar() - - manager = toolBar.getProfileManager() - roiManager = manager.getRoiManager() - - roi = rois.ProfileImageHorizontalLineROI() - roi.setPosition(0.5) - roiManager.addRoi(roi) - roiManager.setCurrentRoi(roi) - - for _ in range(20): - self.qWait(200) - if not manager.hasPendingOperations(): - break - - profileWindow = roi.getProfileWindow() - self.assertIsInstance(roi.getProfileWindow(), qt.QMainWindow) - self.assertIsInstance(profileWindow.getCurrentPlotWidget(), Plot1D) - - def testProfile2D(self): - """Test that the profile plot associated to a stack view is either a - Plot1D or a plot 2D instance.""" - self.plot = StackView() - self.plot.show() - self.qWaitForWindowExposed(self.plot) - - self.plot.setStack(numpy.array([[[0, 1], [2, 3]], - [[4, 5], [6, 7]]])) - - toolBar = self.plot.getProfileToolbar() - - manager = toolBar.getProfileManager() - roiManager = manager.getRoiManager() - - roi = rois.ProfileImageStackHorizontalLineROI() - roi.setPosition(0.5) - roi.setProfileType("2D") - roiManager.addRoi(roi) - roiManager.setCurrentRoi(roi) - - for _ in range(20): - self.qWait(200) - if not manager.hasPendingOperations(): - break - - profileWindow = roi.getProfileWindow() - self.assertIsInstance(roi.getProfileWindow(), qt.QMainWindow) - self.assertIsInstance(profileWindow.getCurrentPlotWidget(), Plot2D) - - roi.setProfileType("1D") - - for _ in range(20): - self.qWait(200) - if not manager.hasPendingOperations(): - break - - profileWindow = roi.getProfileWindow() - self.assertIsInstance(roi.getProfileWindow(), qt.QMainWindow) - self.assertIsInstance(profileWindow.getCurrentPlotWidget(), Plot1D) - - -def suite(): - test_suite = unittest.TestSuite() - loadTests = unittest.defaultTestLoader.loadTestsFromTestCase - test_suite.addTest(loadTests(TestRois)) - test_suite.addTest(loadTests(TestInteractions)) - test_suite.addTest(loadTests(TestProfileToolBar)) - test_suite.addTest(loadTests(TestGetProfilePlot)) - test_suite.addTest(loadTests(TestProfile3DToolBar)) - test_suite.addTest(loadTests(TestDeprecatedProfileToolBar)) - return test_suite - - -if __name__ == '__main__': - unittest.main(defaultTest='suite') diff --git a/silx/gui/plot/tools/test/testROI.py b/silx/gui/plot/tools/test/testROI.py deleted file mode 100644 index 8a00073..0000000 --- a/silx/gui/plot/tools/test/testROI.py +++ /dev/null @@ -1,694 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# -# Copyright (c) 2018-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. -# -# ###########################################################################*/ -__authors__ = ["T. Vincent"] -__license__ = "MIT" -__date__ = "28/06/2018" - - -import unittest -import numpy.testing - -from silx.gui import qt -from silx.utils.testutils import ParametricTestCase -from silx.gui.utils.testutils import TestCaseQt, SignalListener -from silx.gui.plot import PlotWindow -import silx.gui.plot.items.roi as roi_items -from silx.gui.plot.tools import roi - - -class TestRoiItems(TestCaseQt): - - def testLine_geometry(self): - item = roi_items.LineROI() - startPoint = numpy.array([1, 2]) - endPoint = numpy.array([3, 4]) - item.setEndPoints(startPoint, endPoint) - numpy.testing.assert_allclose(item.getEndPoints()[0], startPoint) - numpy.testing.assert_allclose(item.getEndPoints()[1], endPoint) - - def testHLine_geometry(self): - item = roi_items.HorizontalLineROI() - item.setPosition(15) - self.assertEqual(item.getPosition(), 15) - - def testVLine_geometry(self): - item = roi_items.VerticalLineROI() - item.setPosition(15) - self.assertEqual(item.getPosition(), 15) - - def testPoint_geometry(self): - point = numpy.array([1, 2]) - item = roi_items.PointROI() - item.setPosition(point) - numpy.testing.assert_allclose(item.getPosition(), point) - - def testRectangle_originGeometry(self): - origin = numpy.array([0, 0]) - size = numpy.array([10, 20]) - center = numpy.array([5, 10]) - item = roi_items.RectangleROI() - item.setGeometry(origin=origin, size=size) - numpy.testing.assert_allclose(item.getOrigin(), origin) - numpy.testing.assert_allclose(item.getSize(), size) - numpy.testing.assert_allclose(item.getCenter(), center) - - def testRectangle_centerGeometry(self): - origin = numpy.array([0, 0]) - size = numpy.array([10, 20]) - center = numpy.array([5, 10]) - item = roi_items.RectangleROI() - item.setGeometry(center=center, size=size) - numpy.testing.assert_allclose(item.getOrigin(), origin) - numpy.testing.assert_allclose(item.getSize(), size) - numpy.testing.assert_allclose(item.getCenter(), center) - - def testRectangle_setCenterGeometry(self): - origin = numpy.array([0, 0]) - size = numpy.array([10, 20]) - item = roi_items.RectangleROI() - item.setGeometry(origin=origin, size=size) - newCenter = numpy.array([0, 0]) - item.setCenter(newCenter) - expectedOrigin = numpy.array([-5, -10]) - numpy.testing.assert_allclose(item.getOrigin(), expectedOrigin) - numpy.testing.assert_allclose(item.getCenter(), newCenter) - numpy.testing.assert_allclose(item.getSize(), size) - - def testRectangle_setOriginGeometry(self): - origin = numpy.array([0, 0]) - size = numpy.array([10, 20]) - item = roi_items.RectangleROI() - item.setGeometry(origin=origin, size=size) - newOrigin = numpy.array([10, 10]) - item.setOrigin(newOrigin) - expectedCenter = numpy.array([15, 20]) - numpy.testing.assert_allclose(item.getOrigin(), newOrigin) - numpy.testing.assert_allclose(item.getCenter(), expectedCenter) - numpy.testing.assert_allclose(item.getSize(), size) - - def testCircle_geometry(self): - center = numpy.array([0, 0]) - radius = 10. - item = roi_items.CircleROI() - item.setGeometry(center=center, radius=radius) - numpy.testing.assert_allclose(item.getCenter(), center) - numpy.testing.assert_allclose(item.getRadius(), radius) - - def testCircle_setCenter(self): - center = numpy.array([0, 0]) - radius = 10. - item = roi_items.CircleROI() - item.setGeometry(center=center, radius=radius) - newCenter = numpy.array([-10, 0]) - item.setCenter(newCenter) - numpy.testing.assert_allclose(item.getCenter(), newCenter) - numpy.testing.assert_allclose(item.getRadius(), radius) - - def testCircle_setRadius(self): - center = numpy.array([0, 0]) - radius = 10. - item = roi_items.CircleROI() - item.setGeometry(center=center, radius=radius) - newRadius = 5.1 - item.setRadius(newRadius) - numpy.testing.assert_allclose(item.getCenter(), center) - numpy.testing.assert_allclose(item.getRadius(), newRadius) - - def testCircle_contains(self): - center = numpy.array([2, -1]) - radius = 1. - item = roi_items.CircleROI() - item.setGeometry(center=center, radius=radius) - self.assertTrue(item.contains([1, -1])) - self.assertFalse(item.contains([0, 0])) - self.assertTrue(item.contains([2, 0])) - self.assertFalse(item.contains([3.01, -1])) - - def testEllipse_contains(self): - center = numpy.array([-2, 0]) - item = roi_items.EllipseROI() - item.setCenter(center) - item.setOrientation(numpy.pi / 4.0) - item.setMajorRadius(2) - item.setMinorRadius(1) - print(item.getMinorRadius(), item.getMajorRadius()) - self.assertFalse(item.contains([0, 0])) - self.assertTrue(item.contains([-1, 1])) - self.assertTrue(item.contains([-3, 0])) - self.assertTrue(item.contains([-2, 0])) - self.assertTrue(item.contains([-2, 1])) - self.assertFalse(item.contains([-4, 1])) - - def testRectangle_isIn(self): - origin = numpy.array([0, 0]) - size = numpy.array([10, 20]) - item = roi_items.RectangleROI() - item.setGeometry(origin=origin, size=size) - self.assertTrue(item.contains(position=(0, 0))) - self.assertTrue(item.contains(position=(2, 14))) - self.assertFalse(item.contains(position=(14, 12))) - - def testPolygon_emptyGeometry(self): - points = numpy.empty((0, 2)) - item = roi_items.PolygonROI() - item.setPoints(points) - numpy.testing.assert_allclose(item.getPoints(), points) - - def testPolygon_geometry(self): - points = numpy.array([[10, 10], [12, 10], [50, 1]]) - item = roi_items.PolygonROI() - item.setPoints(points) - numpy.testing.assert_allclose(item.getPoints(), points) - - def testPolygon_isIn(self): - points = numpy.array([[0, 0], [0, 10], [5, 10]]) - item = roi_items.PolygonROI() - item.setPoints(points) - self.assertTrue(item.contains((0, 0))) - self.assertFalse(item.contains((6, 2))) - self.assertFalse(item.contains((-2, 5))) - self.assertFalse(item.contains((2, -1))) - self.assertFalse(item.contains((8, 1))) - self.assertTrue(item.contains((1, 8))) - - def testArc_getToSetGeometry(self): - """Test that we can use getGeometry as input to setGeometry""" - item = roi_items.ArcROI() - item.setFirstShapePoints(numpy.array([[5, 10], [50, 100]])) - item.setGeometry(*item.getGeometry()) - - def testArc_degenerated_point(self): - item = roi_items.ArcROI() - center = numpy.array([10, 20]) - innerRadius, outerRadius, startAngle, endAngle = 0, 0, 0, 0 - item.setGeometry(center, innerRadius, outerRadius, startAngle, endAngle) - - def testArc_degenerated_line(self): - item = roi_items.ArcROI() - center = numpy.array([10, 20]) - innerRadius, outerRadius, startAngle, endAngle = 0, 100, numpy.pi, numpy.pi - item.setGeometry(center, innerRadius, outerRadius, startAngle, endAngle) - - def testArc_special_circle(self): - item = roi_items.ArcROI() - center = numpy.array([10, 20]) - innerRadius, outerRadius, startAngle, endAngle = 0, 100, numpy.pi, 3 * numpy.pi - item.setGeometry(center, innerRadius, outerRadius, startAngle, endAngle) - numpy.testing.assert_allclose(item.getCenter(), center) - self.assertAlmostEqual(item.getInnerRadius(), innerRadius) - self.assertAlmostEqual(item.getOuterRadius(), outerRadius) - self.assertAlmostEqual(item.getStartAngle(), item.getEndAngle() - numpy.pi * 2.0) - self.assertTrue(item.isClosed()) - - def testArc_special_donut(self): - item = roi_items.ArcROI() - center = numpy.array([10, 20]) - innerRadius, outerRadius, startAngle, endAngle = 1, 100, numpy.pi, 3 * numpy.pi - item.setGeometry(center, innerRadius, outerRadius, startAngle, endAngle) - numpy.testing.assert_allclose(item.getCenter(), center) - self.assertAlmostEqual(item.getInnerRadius(), innerRadius) - self.assertAlmostEqual(item.getOuterRadius(), outerRadius) - self.assertAlmostEqual(item.getStartAngle(), item.getEndAngle() - numpy.pi * 2.0) - self.assertTrue(item.isClosed()) - - def testArc_clockwiseGeometry(self): - """Test that we can use getGeometry as input to setGeometry""" - item = roi_items.ArcROI() - center = numpy.array([10, 20]) - innerRadius, outerRadius, startAngle, endAngle = 1, 100, numpy.pi * 0.5, numpy.pi - item.setGeometry(center, innerRadius, outerRadius, startAngle, endAngle) - numpy.testing.assert_allclose(item.getCenter(), center) - self.assertAlmostEqual(item.getInnerRadius(), innerRadius) - self.assertAlmostEqual(item.getOuterRadius(), outerRadius) - self.assertAlmostEqual(item.getStartAngle(), startAngle) - self.assertAlmostEqual(item.getEndAngle(), endAngle) - self.assertAlmostEqual(item.isClosed(), False) - - def testArc_anticlockwiseGeometry(self): - """Test that we can use getGeometry as input to setGeometry""" - item = roi_items.ArcROI() - center = numpy.array([10, 20]) - innerRadius, outerRadius, startAngle, endAngle = 1, 100, numpy.pi * 0.5, -numpy.pi * 0.5 - item.setGeometry(center, innerRadius, outerRadius, startAngle, endAngle) - numpy.testing.assert_allclose(item.getCenter(), center) - self.assertAlmostEqual(item.getInnerRadius(), innerRadius) - self.assertAlmostEqual(item.getOuterRadius(), outerRadius) - self.assertAlmostEqual(item.getStartAngle(), startAngle) - self.assertAlmostEqual(item.getEndAngle(), endAngle) - self.assertAlmostEqual(item.isClosed(), False) - - def testHRange_geometry(self): - item = roi_items.HorizontalRangeROI() - vmin = 1 - vmax = 3 - item.setRange(vmin, vmax) - self.assertAlmostEqual(item.getMin(), vmin) - self.assertAlmostEqual(item.getMax(), vmax) - self.assertAlmostEqual(item.getCenter(), 2) - - -class TestRegionOfInterestManager(TestCaseQt, ParametricTestCase): - """Tests for RegionOfInterestManager class""" - - def setUp(self): - super(TestRegionOfInterestManager, self).setUp() - self.plot = PlotWindow() - - self.roiTableWidget = roi.RegionOfInterestTableWidget() - dock = qt.QDockWidget() - dock.setWidget(self.roiTableWidget) - self.plot.addDockWidget(qt.Qt.BottomDockWidgetArea, dock) - - self.plot.show() - self.qWaitForWindowExposed(self.plot) - - def tearDown(self): - del self.roiTableWidget - self.qapp.processEvents() - self.plot.setAttribute(qt.Qt.WA_DeleteOnClose) - self.plot.close() - del self.plot - super(TestRegionOfInterestManager, self).tearDown() - - def test(self): - """Test ROI of different shapes""" - tests = ( # shape, points=[list of (x, y), list of (x, y)] - (roi_items.PointROI, numpy.array(([(10., 15.)], [(20., 25.)]))), - (roi_items.RectangleROI, - numpy.array((((1., 10.), (11., 20.)), - ((2., 3.), (12., 13.))))), - (roi_items.PolygonROI, - numpy.array((((0., 1.), (0., 10.), (10., 0.)), - ((5., 6.), (5., 16.), (15., 6.))))), - (roi_items.LineROI, - numpy.array((((10., 20.), (10., 30.)), - ((30., 40.), (30., 50.))))), - (roi_items.HorizontalLineROI, - numpy.array((((10., 20.), (10., 30.)), - ((30., 40.), (30., 50.))))), - (roi_items.VerticalLineROI, - numpy.array((((10., 20.), (10., 30.)), - ((30., 40.), (30., 50.))))), - (roi_items.HorizontalLineROI, - numpy.array((((10., 20.), (10., 30.)), - ((30., 40.), (30., 50.))))), - ) - - for roiClass, points in tests: - with self.subTest(roiClass=roiClass): - manager = roi.RegionOfInterestManager(self.plot) - self.roiTableWidget.setRegionOfInterestManager(manager) - manager.start(roiClass) - - self.assertEqual(manager.getRois(), ()) - - finishListener = SignalListener() - manager.sigInteractiveModeFinished.connect(finishListener) - - changedListener = SignalListener() - manager.sigRoiChanged.connect(changedListener) - - # Add a point - r = roiClass() - r.setFirstShapePoints(points[0]) - manager.addRoi(r) - self.qapp.processEvents() - self.assertTrue(len(manager.getRois()), 1) - self.assertEqual(changedListener.callCount(), 1) - - # Remove it - manager.removeRoi(manager.getRois()[0]) - self.assertEqual(manager.getRois(), ()) - self.assertEqual(changedListener.callCount(), 2) - - # Add two point - r = roiClass() - r.setFirstShapePoints(points[0]) - manager.addRoi(r) - self.qapp.processEvents() - r = roiClass() - r.setFirstShapePoints(points[1]) - manager.addRoi(r) - self.qapp.processEvents() - self.assertTrue(len(manager.getRois()), 2) - self.assertEqual(changedListener.callCount(), 4) - - # Reset it - result = manager.clear() - self.assertTrue(result) - self.assertEqual(manager.getRois(), ()) - self.assertEqual(changedListener.callCount(), 5) - - changedListener.clear() - - # Add two point - r = roiClass() - r.setFirstShapePoints(points[0]) - manager.addRoi(r) - self.qapp.processEvents() - r = roiClass() - r.setFirstShapePoints(points[1]) - manager.addRoi(r) - self.qapp.processEvents() - self.assertTrue(len(manager.getRois()), 2) - self.assertEqual(changedListener.callCount(), 2) - - # stop - result = manager.stop() - self.assertTrue(result) - self.assertTrue(len(manager.getRois()), 1) - self.qapp.processEvents() - self.assertEqual(finishListener.callCount(), 1) - - manager.clear() - - def testRoiDisplay(self): - rois = [] - - # Line - item = roi_items.LineROI() - startPoint = numpy.array([1, 2]) - endPoint = numpy.array([3, 4]) - item.setEndPoints(startPoint, endPoint) - rois.append(item) - # Horizontal line - item = roi_items.HorizontalLineROI() - item.setPosition(15) - rois.append(item) - # Vertical line - item = roi_items.VerticalLineROI() - item.setPosition(15) - rois.append(item) - # Point - item = roi_items.PointROI() - point = numpy.array([1, 2]) - item.setPosition(point) - rois.append(item) - # Rectangle - item = roi_items.RectangleROI() - origin = numpy.array([0, 0]) - size = numpy.array([10, 20]) - item.setGeometry(origin=origin, size=size) - rois.append(item) - # Polygon - item = roi_items.PolygonROI() - points = numpy.array([[10, 10], [12, 10], [50, 1]]) - item.setPoints(points) - rois.append(item) - # Degenerated polygon: No points - item = roi_items.PolygonROI() - points = numpy.empty((0, 2)) - item.setPoints(points) - rois.append(item) - # Degenerated polygon: A single point - item = roi_items.PolygonROI() - points = numpy.array([[5, 10]]) - item.setPoints(points) - rois.append(item) - # Degenerated arc: it's a point - item = roi_items.ArcROI() - center = numpy.array([10, 20]) - innerRadius, outerRadius, startAngle, endAngle = 0, 0, 0, 0 - item.setGeometry(center, innerRadius, outerRadius, startAngle, endAngle) - rois.append(item) - # Degenerated arc: it's a line - item = roi_items.ArcROI() - center = numpy.array([10, 20]) - innerRadius, outerRadius, startAngle, endAngle = 0, 100, numpy.pi, numpy.pi - item.setGeometry(center, innerRadius, outerRadius, startAngle, endAngle) - rois.append(item) - # Special arc: it's a donut - item = roi_items.ArcROI() - center = numpy.array([10, 20]) - innerRadius, outerRadius, startAngle, endAngle = 1, 100, numpy.pi, 3 * numpy.pi - item.setGeometry(center, innerRadius, outerRadius, startAngle, endAngle) - rois.append(item) - # Arc - item = roi_items.ArcROI() - center = numpy.array([10, 20]) - innerRadius, outerRadius, startAngle, endAngle = 1, 100, numpy.pi * 0.5, numpy.pi - item.setGeometry(center, innerRadius, outerRadius, startAngle, endAngle) - rois.append(item) - # Horizontal Range - item = roi_items.HorizontalRangeROI() - item.setRange(-1, 3) - rois.append(item) - - manager = roi.RegionOfInterestManager(self.plot) - self.roiTableWidget.setRegionOfInterestManager(manager) - for item in rois: - with self.subTest(roi=str(item)): - manager.addRoi(item) - self.qapp.processEvents() - item.setEditable(True) - self.qapp.processEvents() - item.setEditable(False) - self.qapp.processEvents() - manager.removeRoi(item) - self.qapp.processEvents() - - def testSelectionProxy(self): - item1 = roi_items.PointROI() - item1.setSelectable(True) - item2 = roi_items.PointROI() - item2.setSelectable(True) - item1.setFocusProxy(item2) - manager = roi.RegionOfInterestManager(self.plot) - manager.setCurrentRoi(item1) - self.assertIs(manager.getCurrentRoi(), item2) - - def testRemovedSelection(self): - item1 = roi_items.PointROI() - item1.setSelectable(True) - manager = roi.RegionOfInterestManager(self.plot) - manager.addRoi(item1) - manager.setCurrentRoi(item1) - manager.removeRoi(item1) - self.assertIs(manager.getCurrentRoi(), None) - - def testMaxROI(self): - """Test Max ROI""" - origin1 = numpy.array([1., 10.]) - size1 = numpy.array([10., 10.]) - origin2 = numpy.array([2., 3.]) - size2 = numpy.array([10., 10.]) - - manager = roi.InteractiveRegionOfInterestManager(self.plot) - self.roiTableWidget.setRegionOfInterestManager(manager) - self.assertEqual(manager.getRois(), ()) - - changedListener = SignalListener() - manager.sigRoiChanged.connect(changedListener) - - # Add two point - item = roi_items.RectangleROI() - item.setGeometry(origin=origin1, size=size1) - manager.addRoi(item) - item = roi_items.RectangleROI() - item.setGeometry(origin=origin2, size=size2) - manager.addRoi(item) - self.qapp.processEvents() - self.assertEqual(changedListener.callCount(), 2) - self.assertEqual(len(manager.getRois()), 2) - - # Try to set max ROI to 1 while there is 2 ROIs - with self.assertRaises(ValueError): - manager.setMaxRois(1) - - manager.clear() - self.assertEqual(len(manager.getRois()), 0) - self.assertEqual(changedListener.callCount(), 3) - - # Set max limit to 1 - manager.setMaxRois(1) - - # Add a point - item = roi_items.RectangleROI() - item.setGeometry(origin=origin1, size=size1) - manager.addRoi(item) - self.qapp.processEvents() - self.assertEqual(changedListener.callCount(), 4) - - # Add a 2nd point while max ROI is 1 - item = roi_items.RectangleROI() - item.setGeometry(origin=origin1, size=size1) - manager.addRoi(item) - self.qapp.processEvents() - self.assertEqual(changedListener.callCount(), 6) - self.assertEqual(len(manager.getRois()), 1) - - def testChangeInteractionMode(self): - """Test change of interaction mode""" - manager = roi.RegionOfInterestManager(self.plot) - self.roiTableWidget.setRegionOfInterestManager(manager) - manager.start(roi_items.PointROI) - - interactiveModeToolBar = self.plot.getInteractiveModeToolBar() - panAction = interactiveModeToolBar.getPanModeAction() - - for roiClass in manager.getSupportedRoiClasses(): - with self.subTest(roiClass=roiClass): - # Change to pan mode - panAction.trigger() - - # Change to interactive ROI mode - action = manager.getInteractionModeAction(roiClass) - action.trigger() - - self.assertEqual(roiClass, manager.getCurrentInteractionModeRoiClass()) - - manager.clear() - - def testLineInteraction(self): - """This test make sure that a ROI based on handles can be edited with - the mouse.""" - xlimit = self.plot.getXAxis().getLimits() - ylimit = self.plot.getYAxis().getLimits() - points = numpy.array([xlimit, ylimit]).T - center = numpy.mean(points, axis=0) - - # Create the line - manager = roi.RegionOfInterestManager(self.plot) - item = roi_items.LineROI() - item.setEndPoints(points[0], points[1]) - item.setEditable(True) - manager.addRoi(item) - self.qapp.processEvents() - - # Drag the center - widget = self.plot.getWidgetHandle() - mx, my = self.plot.dataToPixel(*center) - self.mouseMove(widget, pos=(mx, my)) - self.mousePress(widget, qt.Qt.LeftButton, pos=(mx, my)) - self.mouseMove(widget, pos=(mx, my+25)) - self.mouseMove(widget, pos=(mx, my+50)) - self.mouseRelease(widget, qt.Qt.LeftButton, pos=(mx, my+50)) - - result = numpy.array(item.getEndPoints()) - # x location is still the same - numpy.testing.assert_allclose(points[:, 0], result[:, 0], atol=0.5) - # size is still the same - numpy.testing.assert_allclose(points[1] - points[0], - result[1] - result[0], atol=0.5) - # But Y is not the same - self.assertNotEqual(points[0, 1], result[0, 1]) - self.assertNotEqual(points[1, 1], result[1, 1]) - item = None - manager.clear() - self.qapp.processEvents() - - def testPlotWhenCleared(self): - """PlotWidget.clear should clean up the available ROIs""" - manager = roi.RegionOfInterestManager(self.plot) - item = roi_items.LineROI() - item.setEndPoints((0, 0), (1, 1)) - item.setEditable(True) - manager.addRoi(item) - self.qWait() - try: - # Make sure the test setup is fine - self.assertNotEqual(len(manager.getRois()), 0) - self.assertNotEqual(len(self.plot.getItems()), 0) - - # Call clear and test the expected state - self.plot.clear() - self.assertEqual(len(manager.getRois()), 0) - self.assertEqual(len(self.plot.getItems()), 0) - finally: - # Clean up - manager.clear() - - def testPlotWhenRoiRemoved(self): - """Make sure there is no remaining items in the plot when a ROI is removed""" - manager = roi.RegionOfInterestManager(self.plot) - item = roi_items.LineROI() - item.setEndPoints((0, 0), (1, 1)) - item.setEditable(True) - manager.addRoi(item) - self.qWait() - try: - # Make sure the test setup is fine - self.assertNotEqual(len(manager.getRois()), 0) - self.assertNotEqual(len(self.plot.getItems()), 0) - - # Call clear and test the expected state - manager.removeRoi(item) - self.assertEqual(len(manager.getRois()), 0) - self.assertEqual(len(self.plot.getItems()), 0) - finally: - # Clean up - manager.clear() - - def testArcRoiSwitchMode(self): - """Make sure we can switch mode by clicking on the ROI""" - xlimit = self.plot.getXAxis().getLimits() - ylimit = self.plot.getYAxis().getLimits() - points = numpy.array([xlimit, ylimit]).T - center = numpy.mean(points, axis=0) - size = numpy.abs(points[1] - points[0]) - - # Create the line - manager = roi.RegionOfInterestManager(self.plot) - item = roi_items.ArcROI() - item.setGeometry(center, size[1] / 10, size[1] / 2, 0, 3) - item.setEditable(True) - item.setSelectable(True) - manager.addRoi(item) - self.qapp.processEvents() - - # Initial state - self.assertIs(item.getInteractionMode(), roi_items.ArcROI.ThreePointMode) - self.qWait(500) - - # Click on the center - widget = self.plot.getWidgetHandle() - mx, my = self.plot.dataToPixel(*center) - - # Select the ROI - self.mouseMove(widget, pos=(mx, my)) - self.mouseClick(widget, qt.Qt.LeftButton, pos=(mx, my)) - self.qWait(500) - self.assertIs(item.getInteractionMode(), roi_items.ArcROI.ThreePointMode) - - # Change the mode - self.mouseMove(widget, pos=(mx, my)) - self.mouseClick(widget, qt.Qt.LeftButton, pos=(mx, my)) - self.qWait(500) - self.assertIs(item.getInteractionMode(), roi_items.ArcROI.PolarMode) - - manager.clear() - self.qapp.processEvents() - - -def suite(): - test_suite = unittest.TestSuite() - loadTests = unittest.defaultTestLoader.loadTestsFromTestCase - test_suite.addTest(loadTests(TestRoiItems)) - test_suite.addTest(loadTests(TestRegionOfInterestManager)) - return test_suite - - -if __name__ == '__main__': - unittest.main(defaultTest='suite') diff --git a/silx/gui/plot/tools/test/testScatterProfileToolBar.py b/silx/gui/plot/tools/test/testScatterProfileToolBar.py deleted file mode 100644 index b9f4885..0000000 --- a/silx/gui/plot/tools/test/testScatterProfileToolBar.py +++ /dev/null @@ -1,196 +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. -# -# ###########################################################################*/ -__authors__ = ["T. Vincent"] -__license__ = "MIT" -__date__ = "28/06/2018" - - -import unittest -import numpy - -from silx.gui import qt -from silx.utils.testutils import ParametricTestCase -from silx.gui.utils.testutils import TestCaseQt -from silx.gui.plot import PlotWindow -from silx.gui.plot.tools.profile import manager -from silx.gui.plot.tools.profile import core -from silx.gui.plot.tools.profile import rois - - -class TestScatterProfileToolBar(TestCaseQt, ParametricTestCase): - """Tests for ScatterProfileToolBar class""" - - def setUp(self): - super(TestScatterProfileToolBar, self).setUp() - self.plot = PlotWindow() - - self.manager = manager.ProfileManager(plot=self.plot) - self.manager.setItemType(scatter=True) - self.manager.setActiveItemTracking(True) - - self.plot.show() - self.qWaitForWindowExposed(self.plot) - - def tearDown(self): - del self.manager - self.qapp.processEvents() - self.plot.setAttribute(qt.Qt.WA_DeleteOnClose) - self.plot.close() - del self.plot - super(TestScatterProfileToolBar, self).tearDown() - - def testHorizontalProfile(self): - """Test ScatterProfileToolBar horizontal profile""" - - roiManager = self.manager.getRoiManager() - - # Add a scatter plot - self.plot.addScatter( - x=(0., 1., 1., 0.), y=(0., 0., 1., 1.), value=(0., 1., 2., 3.)) - self.plot.resetZoom(dataMargins=(.1, .1, .1, .1)) - self.qapp.processEvents() - - # Set a ROI profile - roi = rois.ProfileScatterHorizontalLineROI() - roi.setPosition(0.5) - roi.setNPoints(8) - roiManager.addRoi(roi) - - # Wait for async interpolator init - for _ in range(20): - self.qWait(200) - if not self.manager.hasPendingOperations(): - break - self.qapp.processEvents() - - window = roi.getProfileWindow() - self.assertIsNotNone(window) - data = window.getProfile() - self.assertIsInstance(data, core.CurveProfileData) - self.assertEqual(len(data.coords), 8) - - # Check that profile has same limits than Plot - xLimits = self.plot.getXAxis().getLimits() - self.assertEqual(data.coords[0], xLimits[0]) - self.assertEqual(data.coords[-1], xLimits[1]) - - # Clear the profile - self.manager.clearProfile() - self.qapp.processEvents() - self.assertIsNone(roi.getProfileWindow()) - - def testVerticalProfile(self): - """Test ScatterProfileToolBar vertical profile""" - - roiManager = self.manager.getRoiManager() - - # Add a scatter plot - self.plot.addScatter( - x=(0., 1., 1., 0.), y=(0., 0., 1., 1.), value=(0., 1., 2., 3.)) - self.plot.resetZoom(dataMargins=(.1, .1, .1, .1)) - self.qapp.processEvents() - - # Set a ROI profile - roi = rois.ProfileScatterVerticalLineROI() - roi.setPosition(0.5) - roi.setNPoints(8) - roiManager.addRoi(roi) - - # Wait for async interpolator init - for _ in range(10): - self.qWait(200) - if not self.manager.hasPendingOperations(): - break - - window = roi.getProfileWindow() - self.assertIsNotNone(window) - data = window.getProfile() - self.assertIsInstance(data, core.CurveProfileData) - self.assertEqual(len(data.coords), 8) - - # Check that profile has same limits than Plot - yLimits = self.plot.getYAxis().getLimits() - self.assertEqual(data.coords[0], yLimits[0]) - self.assertEqual(data.coords[-1], yLimits[1]) - - # Check that profile limits are updated when changing limits - self.plot.getYAxis().setLimits(yLimits[0] + 1, yLimits[1] + 10) - - # Wait for async interpolator init - for _ in range(10): - self.qWait(200) - if not self.manager.hasPendingOperations(): - break - - yLimits = self.plot.getYAxis().getLimits() - data = window.getProfile() - self.assertEqual(data.coords[0], yLimits[0]) - self.assertEqual(data.coords[-1], yLimits[1]) - - # Clear the profile - self.manager.clearProfile() - self.qapp.processEvents() - self.assertIsNone(roi.getProfileWindow()) - - def testLineProfile(self): - """Test ScatterProfileToolBar line profile""" - - roiManager = self.manager.getRoiManager() - - # Add a scatter plot - self.plot.addScatter( - x=(0., 1., 1., 0.), y=(0., 0., 1., 1.), value=(0., 1., 2., 3.)) - self.plot.resetZoom(dataMargins=(.1, .1, .1, .1)) - self.qapp.processEvents() - - # Set a ROI profile - roi = rois.ProfileScatterLineROI() - roi.setEndPoints(numpy.array([0., 0.]), numpy.array([1., 1.])) - roi.setNPoints(8) - roiManager.addRoi(roi) - - # Wait for async interpolator init - for _ in range(10): - self.qWait(200) - if not self.manager.hasPendingOperations(): - break - - window = roi.getProfileWindow() - self.assertIsNotNone(window) - data = window.getProfile() - self.assertIsInstance(data, core.CurveProfileData) - self.assertEqual(len(data.coords), 8) - - -def suite(): - test_suite = unittest.TestSuite() - test_suite.addTest( - unittest.defaultTestLoader.loadTestsFromTestCase( - TestScatterProfileToolBar)) - return test_suite - - -if __name__ == '__main__': - unittest.main(defaultTest='suite') diff --git a/silx/gui/plot/tools/test/testTools.py b/silx/gui/plot/tools/test/testTools.py deleted file mode 100644 index 70c8105..0000000 --- a/silx/gui/plot/tools/test/testTools.py +++ /dev/null @@ -1,147 +0,0 @@ -# coding: utf-8 -# /*########################################################################## -# -# Copyright (c) 2016-2019 European Synchrotron Radiation Facility -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# -# ###########################################################################*/ -"""Basic tests for silx.gui.plot.tools package""" - -__authors__ = ["T. Vincent"] -__license__ = "MIT" -__date__ = "02/03/2018" - - -import functools -import unittest -import numpy - -from silx.utils.testutils import TestLogging -from silx.gui.utils.testutils import qWaitForWindowExposedAndActivate -from silx.gui import qt -from silx.gui.plot import PlotWindow -from silx.gui.plot import tools -from silx.gui.plot.test.utils import PlotWidgetTestCase - - -class TestPositionInfo(PlotWidgetTestCase): - """Tests for PositionInfo widget.""" - - def _createPlot(self): - return PlotWindow() - - def setUp(self): - super(TestPositionInfo, self).setUp() - self.mouseMove(self.plot, pos=(0, 0)) - self.qapp.processEvents() - self.qWait(100) - - def tearDown(self): - super(TestPositionInfo, self).tearDown() - - def _test(self, positionWidget, converterNames, **kwargs): - """General test of PositionInfo. - - - Add it to a toolbar and - - Move mouse around the center of the PlotWindow. - """ - toolBar = qt.QToolBar() - self.plot.addToolBar(qt.Qt.BottomToolBarArea, toolBar) - - toolBar.addWidget(positionWidget) - - converters = positionWidget.getConverters() - self.assertEqual(len(converters), len(converterNames)) - for index, name in enumerate(converterNames): - self.assertEqual(converters[index][0], name) - - with TestLogging(tools.__name__, **kwargs): - # Move mouse to center - center = self.plot.size() / 2 - self.mouseMove(self.plot, pos=(center.width(), center.height())) - # Move out - self.mouseMove(self.plot, pos=(1, 1)) - - def testDefaultConverters(self): - """Test PositionInfo with default converters""" - positionWidget = tools.PositionInfo(plot=self.plot) - self._test(positionWidget, ('X', 'Y')) - - def testCustomConverters(self): - """Test PositionInfo with custom converters""" - converters = [ - ('Coords', lambda x, y: (int(x), int(y))), - ('Radius', lambda x, y: numpy.sqrt(x * x + y * y)), - ('Angle', lambda x, y: numpy.degrees(numpy.arctan2(y, x))) - ] - positionWidget = tools.PositionInfo(plot=self.plot, - converters=converters) - self._test(positionWidget, ('Coords', 'Radius', 'Angle')) - - def testFailingConverters(self): - """Test PositionInfo with failing custom converters""" - def raiseException(x, y): - raise RuntimeError() - - positionWidget = tools.PositionInfo( - plot=self.plot, - converters=[('Exception', raiseException)]) - self._test(positionWidget, ['Exception'], error=2) - - def testUpdate(self): - """Test :meth:`PositionInfo.updateInfo`""" - calls = [] - - def update(calls, x, y): # Get number of calls - calls.append((x, y)) - return len(calls) - - positionWidget = tools.PositionInfo( - plot=self.plot, - converters=[('Call count', functools.partial(update, calls))]) - - positionWidget.updateInfo() - self.assertEqual(len(calls), 1) - - -class TestPlotToolsToolbars(PlotWidgetTestCase): - """Tests toolbars from silx.gui.plot.tools""" - - def test(self): - """"Add all toolbars""" - for tbClass in (tools.InteractiveModeToolBar, - tools.ImageToolBar, - tools.CurveToolBar, - tools.OutputToolBar): - tb = tbClass(parent=self.plot, plot=self.plot) - self.plot.addToolBar(tb) - - -def suite(): - test_suite = unittest.TestSuite() - # test_suite.addTest(positionInfoTestSuite) - for testClass in (TestPositionInfo, TestPlotToolsToolbars): - test_suite.addTest(unittest.defaultTestLoader.loadTestsFromTestCase( - testClass)) - return test_suite - - -if __name__ == '__main__': - unittest.main(defaultTest='suite') |