source: sasview/src/sas/qtgui/Plotting/UnitTesting/PlotterTest.py @ 6c7ebb88

Last change on this file since 6c7ebb88 was 6c7ebb88, checked in by GitHub <noreply@…>, 5 years ago

Merge d32a594acc82ad29555832f498167b51564c75f3 into f994f188e28dca36e7823b2deb3bf2bfc351c35c

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