source: sasview/src/sas/qtgui/Plotting/UnitTesting/PlotterTest.py @ 863ebca

ESS_GUIESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalc
Last change on this file since 863ebca was 863ebca, checked in by Piotr Rozyczko <piotrrozyczko@…>, 6 years ago

Introduced navigation bar toggle in context menu for all types of
charts. SASVIEW-890

  • Property mode set to 100644
File size: 16.1 KB
RevLine 
[6d05e1d]1import sys
2import unittest
[b2a5042]3import platform
[6d05e1d]4
[53c771e]5from PyQt5 import QtGui, QtWidgets, QtPrintSupport
6from PyQt5 import QtCore
7from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
[7fb471d]8from unittest.mock import MagicMock
9from unittest.mock import patch
[6d05e1d]10
11####### TEMP
[416fa8f]12import path_prepare
[6d05e1d]13#######
[dc5ef15]14from sas.qtgui.Plotting.PlotterData import Data1D
15from sas.qtgui.Plotting.PlotterData import Data2D
16from sas.qtgui.UnitTesting.TestUtils import WarningTestNotImplemented
[83eb5208]17from sas.qtgui.Plotting.LinearFit import LinearFit
18from sas.qtgui.Plotting.PlotProperties import PlotProperties
[6d05e1d]19
20# Tested module
[83eb5208]21import sas.qtgui.Plotting.Plotter as Plotter
[6d05e1d]22
[53c771e]23if not QtWidgets.QApplication.instance():
24    app = QtWidgets.QApplication(sys.argv)
[6d05e1d]25
[87cc73a]26
[6d05e1d]27class PlotterTest(unittest.TestCase):
28    '''Test the Plotter 1D class'''
29    def setUp(self):
30        '''create'''
[257bd57]31
[6d05e1d]32        self.plotter = Plotter.Plotter(None, quickplot=True)
33        self.data = Data1D(x=[1.0, 2.0, 3.0],
34                           y=[10.0, 11.0, 12.0],
35                           dx=[0.1, 0.2, 0.3],
36                           dy=[0.1, 0.2, 0.3])
37        self.data.title="Test data"
[aadf0af1]38        self.data.name="Test name"
[6d05e1d]39        self.data.id = 1
[b2a5042]40        self.isWindows = platform.system=="Windows"
[6d05e1d]41
42    def tearDown(self):
43        '''destroy'''
44        self.plotter = None
45
46    def testDataProperty(self):
47        """ Adding data """
48        self.plotter.data = self.data
49
50        self.assertEqual(self.plotter.data, self.data)
[aadf0af1]51        self.assertEqual(self.plotter._title, self.data.name)
[63319b0]52        self.assertEqual(self.plotter.xLabel, "")
53        self.assertEqual(self.plotter.yLabel, "")
[6d05e1d]54
[fecfe28]55    def testPlotWithErrors(self):
56        """ Look at the plotting with error bars"""
[6d05e1d]57        self.plotter.data = self.data
58        self.plotter.show()
[5b144c6]59        FigureCanvas.draw = MagicMock()
[6d05e1d]60
[fecfe28]61        self.plotter.plot(hide_error=False)
[6d05e1d]62
[fecfe28]63        self.assertEqual(self.plotter.ax.get_xscale(), 'log')
[5b144c6]64        self.assertTrue(FigureCanvas.draw.called)
[53c771e]65
66        self.plotter.figure.clf()
[fecfe28]67
68    def testPlotWithoutErrors(self):
69        """ Look at the plotting without error bars"""
70        self.plotter.data = self.data
71        self.plotter.show()
[5b144c6]72        FigureCanvas.draw = MagicMock()
[fecfe28]73
74        self.plotter.plot(hide_error=True)
75
76        self.assertEqual(self.plotter.ax.get_yscale(), 'log')
[5b144c6]77        self.assertTrue(FigureCanvas.draw.called)
[53c771e]78        self.plotter.figure.clf()
[6d05e1d]79
[749b715]80    def testPlotWithSesans(self):
81        """ Ensure that Sesans data is plotted in linear cooredinates"""
82        data = Data1D(x=[1.0, 2.0, 3.0],
83                      y=[10.0, 11.0, 12.0],
84                      dx=[0.1, 0.2, 0.3],
85                      dy=[0.1, 0.2, 0.3])
86        data.title = "Sesans data"
87        data.name = "Test Sesans"
88        data.isSesans = True
89        data.id = 2
90
91        self.plotter.data = data
92        self.plotter.show()
[5b144c6]93        FigureCanvas.draw = MagicMock()
[749b715]94
95        self.plotter.plot(hide_error=True)
96
97        self.assertEqual(self.plotter.ax.get_xscale(), 'linear')
98        self.assertEqual(self.plotter.ax.get_yscale(), 'linear')
[5b144c6]99        self.assertTrue(FigureCanvas.draw.called)
[749b715]100
[b46f285]101    def testCreateContextMenuQuick(self):
[6d05e1d]102        """ Test the right click menu """
[aadf0af1]103        self.plotter.createContextMenuQuick()
[6d05e1d]104        actions = self.plotter.contextMenu.actions()
[863ebca]105        self.assertEqual(len(actions), 9)
[6d05e1d]106
107        # Trigger Print Image and make sure the method is called
108        self.assertEqual(actions[1].text(), "Print Image")
[53c771e]109        QtPrintSupport.QPrintDialog.exec_ = MagicMock(return_value=QtWidgets.QDialog.Rejected)
[6d05e1d]110        actions[1].trigger()
[53c771e]111        self.assertTrue(QtPrintSupport.QPrintDialog.exec_.called)
[6d05e1d]112
113        # Trigger Copy to Clipboard and make sure the method is called
114        self.assertEqual(actions[2].text(), "Copy to Clipboard")
115
116        # Trigger Toggle Grid and make sure the method is called
[863ebca]117        self.assertEqual(actions[6].text(), "Toggle Grid On/Off")
[6d05e1d]118        self.plotter.ax.grid = MagicMock()
[863ebca]119        actions[6].trigger()
[6d05e1d]120        self.assertTrue(self.plotter.ax.grid.called)
121
122        # Trigger Change Scale and make sure the method is called
[863ebca]123        self.assertEqual(actions[8].text(), "Change Scale")
[53c771e]124        self.plotter.properties.exec_ = MagicMock(return_value=QtWidgets.QDialog.Rejected)
[863ebca]125        actions[8].trigger()
[6d05e1d]126        self.assertTrue(self.plotter.properties.exec_.called)
127
[b2a5042]128        # Spy on cliboard's dataChanged() signal
129        if not self.isWindows:
130            return
131        self.clipboard_called = False
132        def done():
133            self.clipboard_called = True
[53c771e]134        QtCore.QObject.connect(QtWidgets.qApp.clipboard(), QtCore.SIGNAL("dataChanged()"), done)
[b2a5042]135        actions[2].trigger()
[53c771e]136        QtWidgets.qApp.processEvents()
[b2a5042]137        # Make sure clipboard got updated.
138        self.assertTrue(self.clipboard_called)
139
[b46f285]140    def testXyTransform(self):
141        """ Tests the XY transformation and new chart update """
[257bd57]142        self.plotter.plot(self.data)
[6d05e1d]143
[b46f285]144        # Transform the points
145        self.plotter.xyTransform(xLabel="x", yLabel="log10(y)")
[6d05e1d]146
[b46f285]147        # Assure new plot has correct labels
[b8080e1]148        #self.assertEqual(self.plotter.ax.get_xlabel(), "$()$")
149        #self.assertEqual(self.plotter.ax.get_ylabel(), "$()$")
[b46f285]150        # ... and scale
151        self.assertEqual(self.plotter.xscale, "linear")
152        self.assertEqual(self.plotter.yscale, "log")
153        # See that just one plot is present
154        self.assertEqual(len(self.plotter.plot_dict), 1)
155        self.assertEqual(len(self.plotter.ax.collections), 1)
[53c771e]156        self.plotter.figure.clf()
[64f1e93]157
[9290b1a]158    def testAddText(self):
159        """ Checks the functionality of adding text to graph """
[257bd57]160
161        self.plotter.plot(self.data)
162        self.plotter.x_click = 100.0
163        self.plotter.y_click = 100.0
164        # modify the text edit control
165        test_text = "Smoke in cabin"
166        test_font = QtGui.QFont("Arial", 16, QtGui.QFont.Bold)
167        test_color = "#00FF00"
168        self.plotter.addText.textEdit.setText(test_text)
169
170        # Return the requested font parameters
171        self.plotter.addText.font = MagicMock(return_value = test_font)
172        self.plotter.addText.color = MagicMock(return_value = test_color)
173        # Return OK from the dialog
[53c771e]174        self.plotter.addText.exec_ = MagicMock(return_value = QtWidgets.QDialog.Accepted)
[257bd57]175        # Add text to graph
176        self.plotter.onAddText()
177        self.plotter.show()
178        # Check if the text was added properly
179        self.assertEqual(len(self.plotter.textList), 1)
180        self.assertEqual(self.plotter.textList[0].get_text(), test_text)
181        self.assertEqual(self.plotter.textList[0].get_color(), test_color)
182        self.assertEqual(self.plotter.textList[0].get_fontproperties().get_family()[0], 'Arial')
183        self.assertEqual(self.plotter.textList[0].get_fontproperties().get_size(), 16)
[53c771e]184        self.plotter.figure.clf()
[9290b1a]185
186    def testOnRemoveText(self):
187        """ Cheks if annotations can be removed from the graph """
[257bd57]188
189        # Add some text
190        self.plotter.plot(self.data)
191        test_text = "Safety instructions"
192        self.plotter.addText.textEdit.setText(test_text)
193        # Return OK from the dialog
[53c771e]194        self.plotter.addText.exec_ = MagicMock(return_value = QtWidgets.QDialog.Accepted)
[257bd57]195        # Add text to graph
[63319b0]196        self.plotter.x_click = 1.0
197        self.plotter.y_click = 5.0
[257bd57]198        self.plotter.onAddText()
199        self.plotter.show()
200        # Check if the text was added properly
201        self.assertEqual(len(self.plotter.textList), 1)
202
203        # Now, remove the text
204        self.plotter.onRemoveText()
205
206        # And assure no text is displayed
207        self.assertEqual(self.plotter.textList, [])
208
209        # Attempt removal on empty and check
210        self.plotter.onRemoveText()
211        self.assertEqual(self.plotter.textList, [])
[53c771e]212        self.plotter.figure.clf()
[9290b1a]213
[d3ca363]214    def testOnSetGraphRange(self):
215        """ Cheks if the graph can be resized for range """
[257bd57]216        new_x = (1,2)
217        new_y = (10,11)
218        self.plotter.plot(self.data)
219        self.plotter.show()
[53c771e]220        self.plotter.setRange.exec_ = MagicMock(return_value = QtWidgets.QDialog.Accepted)
[257bd57]221        self.plotter.setRange.xrange = MagicMock(return_value = new_x)
222        self.plotter.setRange.yrange = MagicMock(return_value = new_y)
223
224        # Call the tested method
225        self.plotter.onSetGraphRange()
226        # See that ranges changed accordingly
227        self.assertEqual(self.plotter.ax.get_xlim(), new_x)
228        self.assertEqual(self.plotter.ax.get_ylim(), new_y)
[53c771e]229        self.plotter.figure.clf()
[d3ca363]230
231    def testOnResetGraphRange(self):
232        """ Cheks if the graph can be reset after resizing for range """
[257bd57]233        # New values
234        new_x = (1,2)
235        new_y = (10,11)
236        # define the plot
237        self.plotter.plot(self.data)
238        self.plotter.show()
239
240        # mock setRange methods
[53c771e]241        self.plotter.setRange.exec_ = MagicMock(return_value = QtWidgets.QDialog.Accepted)
[257bd57]242        self.plotter.setRange.xrange = MagicMock(return_value = new_x)
243        self.plotter.setRange.yrange = MagicMock(return_value = new_y)
244
245        # Change the axes range
246        self.plotter.onSetGraphRange()
247
248        # Now, reset the range back
249        self.plotter.onResetGraphRange()
250
251        # See that ranges are changed
252        self.assertNotEqual(self.plotter.ax.get_xlim(), new_x)
253        self.assertNotEqual(self.plotter.ax.get_ylim(), new_y)
[53c771e]254        self.plotter.figure.clf()
[9290b1a]255
[b46f285]256    def testOnLinearFit(self):
257        """ Checks the response to LinearFit call """
[2e3e959]258        self.plotter.plot(self.data)
259        self.plotter.show()
[53c771e]260        QtWidgets.QDialog.exec_ = MagicMock(return_value=QtWidgets.QDialog.Accepted)
[2e3e959]261
262        # Just this one plot
[7fb471d]263        self.assertEqual(len(list(self.plotter.plot_dict.keys())), 1)
[5b144c6]264        self.plotter.onLinearFit('Test name')
[2e3e959]265
266        # Check that exec_ got called
[53c771e]267        self.assertTrue(QtWidgets.QDialog.exec_.called)
268        self.plotter.figure.clf()
[b46f285]269
270    def testOnRemovePlot(self):
271        """ Assure plots get removed when requested """
[2e3e959]272        # Add two plots
273        self.plotter.show()
274        self.plotter.plot(self.data)
275        data2 = Data1D(x=[1.0, 2.0, 3.0],
276                       y=[11.0, 12.0, 13.0],
277                       dx=[0.1, 0.2, 0.3],
278                       dy=[0.1, 0.2, 0.3])
279        data2.title="Test data 2"
280        data2.name="Test name 2"
281        data2.id = 2
282        self.plotter.plot(data2)
283
284        # Assure the plotter window is visible
[0268aed]285        #self.assertTrue(self.plotter.isVisible())
[2e3e959]286
287        # Assure we have two sets
[7fb471d]288        self.assertEqual(len(list(self.plotter.plot_dict.keys())), 2)
[2e3e959]289
290        # Delete one set
[5b144c6]291        self.plotter.onRemovePlot('Test name 2')
[2e3e959]292        # Assure we have two sets
[7fb471d]293        self.assertEqual(len(list(self.plotter.plot_dict.keys())), 1)
[2e3e959]294
295        self.plotter.manager = MagicMock()
296
297        # Delete the remaining set
[5b144c6]298        self.plotter.onRemovePlot('Test name')
[2e3e959]299        # Assure we have no plots
[7fb471d]300        self.assertEqual(len(list(self.plotter.plot_dict.keys())), 0)
[2e3e959]301        # Assure the plotter window is closed
302        self.assertFalse(self.plotter.isVisible())
[53c771e]303        self.plotter.figure.clf()
[b46f285]304
305    def testRemovePlot(self):
306        """ Test plot removal """
[2e3e959]307        # Add two plots
308        self.plotter.show()
309        self.plotter.plot(self.data)
310        data2 = Data1D(x=[1.0, 2.0, 3.0],
311                       y=[11.0, 12.0, 13.0],
312                       dx=[0.1, 0.2, 0.3],
313                       dy=[0.1, 0.2, 0.3])
314        data2.title="Test data 2"
315        data2.name="Test name 2"
316        data2.id = 2
317        data2._xaxis = "XAXIS"
318        data2._xunit = "furlong*fortnight^{-1}"
319        data2._yaxis = "YAXIS"
320        data2._yunit = "cake"
321        data2.hide_error = True
322        self.plotter.plot(data2)
323
324        # delete plot 1
325        self.plotter.removePlot(1)
326
327        # See that the labels didn't change
328        xl = self.plotter.ax.xaxis.label.get_text()
329        yl = self.plotter.ax.yaxis.label.get_text()
330        self.assertEqual(xl, "$XAXIS(furlong*fortnight^{-1})$")
331        self.assertEqual(yl, "$YAXIS(cake)$")
332        # The hide_error flag should also remain
[5b144c6]333        self.assertTrue(self.plotter.plot_dict['Test name 2'].hide_error)
[53c771e]334        self.plotter.figure.clf()
[b46f285]335
336    def testOnToggleHideError(self):
337        """ Test the error bar toggle on plots """
[2e3e959]338        # Add two plots
339        self.plotter.show()
340        self.plotter.plot(self.data)
341        data2 = Data1D(x=[1.0, 2.0, 3.0],
342                       y=[11.0, 12.0, 13.0],
343                       dx=[0.1, 0.2, 0.3],
344                       dy=[0.1, 0.2, 0.3])
345        data2.title="Test data 2"
346        data2.name="Test name 2"
347        data2.id = 2
348        data2._xaxis = "XAXIS"
349        data2._xunit = "furlong*fortnight^{-1}"
350        data2._yaxis = "YAXIS"
351        data2._yunit = "cake"
352        error_status = True
353        data2.hide_error = error_status
354        self.plotter.plot(data2)
355
356        # Reverse the toggle
[5b144c6]357        self.plotter.onToggleHideError('Test name 2')
[2e3e959]358        # See that the labels didn't change
359        xl = self.plotter.ax.xaxis.label.get_text()
360        yl = self.plotter.ax.yaxis.label.get_text()
361        self.assertEqual(xl, "$XAXIS(furlong*fortnight^{-1})$")
362        self.assertEqual(yl, "$YAXIS(cake)$")
363        # The hide_error flag should toggle
[5b144c6]364        self.assertEqual(self.plotter.plot_dict['Test name 2'].hide_error, not error_status)
[53c771e]365        self.plotter.figure.clf()
[b46f285]366
367    def testOnFitDisplay(self):
368        """ Test the fit line display on the chart """
[2e3e959]369        self.assertIsInstance(self.plotter.fit_result, Data1D)
370        self.assertEqual(self.plotter.fit_result.symbol, 13)
371        self.assertEqual(self.plotter.fit_result.name, "Fit")
372
373        # fudge some init data
374        fit_data = [[0.0,0.0], [5.0,5.0]]
375        # Call the method
376        self.plotter.plot = MagicMock()
377        self.plotter.onFitDisplay(fit_data)
378        self.assertTrue(self.plotter.plot.called)
379        # Look at arguments passed to .plot()
380        self.plotter.plot.assert_called_with(data=self.plotter.fit_result,
381                                             hide_error=True, marker='-')
[53c771e]382        self.plotter.figure.clf()
[87cc73a]383
384    def testReplacePlot(self):
385        """ Test the plot refresh functionality """
[2e3e959]386        # Add original data
387        self.plotter.show()
388        self.plotter.plot(self.data)
389        # See the default labels
390        xl = self.plotter.ax.xaxis.label.get_text()
391        yl = self.plotter.ax.yaxis.label.get_text()
[63319b0]392        self.assertEqual(xl, "")
393        self.assertEqual(yl, "")
[2e3e959]394
395        # Prepare new data
396        data2 = Data1D(x=[1.0, 2.0, 3.0],
397                       y=[11.0, 12.0, 13.0],
398                       dx=[0.1, 0.2, 0.3],
399                       dy=[0.1, 0.2, 0.3])
400        data2.title="Test data 2"
401        data2.name="Test name 2"
402        data2.id = 2
403        data2._xaxis = "XAXIS"
404        data2._xunit = "furlong*fortnight^{-1}"
405        data2._yaxis = "YAXIS"
406        data2._yunit = "cake"
407        error_status = True
408        data2.hide_error = error_status
409
410        # Replace data in plot
411        self.plotter.replacePlot(1, data2)
412
413        # See that the labels changed
414        xl = self.plotter.ax.xaxis.label.get_text()
415        yl = self.plotter.ax.yaxis.label.get_text()
416        self.assertEqual(xl, "$XAXIS(furlong*fortnight^{-1})$")
417        self.assertEqual(yl, "$YAXIS(cake)$")
418        # The hide_error flag should be as set
[5b144c6]419        self.assertEqual(self.plotter.plot_dict['Test name 2'].hide_error, error_status)
[53c771e]420        self.plotter.figure.clf()
[87cc73a]421
[83eb5208]422    def notestOnModifyPlot(self):
[87cc73a]423        """ Test the functionality for changing plot properties """
[2e3e959]424        # Prepare new data
425        data2 = Data1D(x=[1.0, 2.0, 3.0],
426                       y=[11.0, 12.0, 13.0],
427                       dx=[0.1, 0.2, 0.3],
428                       dy=[0.1, 0.2, 0.3])
429        data2.title="Test data 2"
430        data2.name="Test name 2"
431        data2.id = 2
432        data2.custom_color = None
433        data2.symbol = 1
434        data2.markersize = 11
435
436        self.plotter.plot(data2)
437
[83eb5208]438        with patch('sas.qtgui.Plotting.PlotProperties.PlotProperties') as mock:
[2e3e959]439            instance = mock.return_value
[53c771e]440            QtWidgets.QDialog.exec_ = MagicMock(return_value=QtWidgets.QDialog.Accepted)
[2e3e959]441            instance.symbol.return_value = 7
442
443            self.plotter.onModifyPlot(2)
[53c771e]444        self.plotter.figure.clf()
[2e3e959]445
[b46f285]446
[6d05e1d]447if __name__ == "__main__":
448    unittest.main()
Note: See TracBrowser for help on using the repository browser.