source: sasview/src/sas/qtgui/Plotting/UnitTesting/PlotterTest.py @ 7fb471d

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalc
Last change on this file since 7fb471d was 7fb471d, checked in by Piotr Rozyczko <rozyczko@…>, 6 years ago

Update for unit tests and minor functionality quirks

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