source: sasview/src/sas/qtgui/Plotting/UnitTesting/PlotterTest.py @ 8d39961

Last change on this file since 8d39961 was b2a5042, checked in by Piotr Rozyczko <rozyczko@…>, 7 years ago

Allow QClipboard tests on windows only

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