source: sasview/src/sas/qtgui/Plotting/UnitTesting/PlotterTest.py @ 464cd07

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 464cd07 was 464cd07, checked in by Piotr Rozyczko <rozyczko@…>, 7 years ago

Use singleton QApplication in unit tests to avoid issues on Ubuntu. SASVIEW-485

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