source: sasview/src/sas/qtgui/UnitTesting/PlotterTest.py @ 9a05a8d5

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 9a05a8d5 was 2e3e959, checked in by Piotr Rozyczko <rozyczko@…>, 8 years ago

Code review issues addressed.
More unit tests for plotting.

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