source: sasview/src/sas/qtgui/PlotterBase.py @ c4e5400

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

Refactored context menu setup for plots

  • Property mode set to 100644
File size: 7.5 KB
Line 
1import pylab
2
3from PyQt4 import QtGui
4
5# TODO: Replace the qt4agg calls below with qt5 equivalent.
6# Requires some code modifications.
7# https://www.boxcontrol.net/embedding-matplotlib-plot-on-pyqt5-gui.html
8#
9from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
10from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar
11
12import matplotlib.pyplot as plt
13
14DEFAULT_CMAP = pylab.cm.jet
15from sas.qtgui.ScaleProperties import ScaleProperties
16import sas.qtgui.PlotHelper as PlotHelper
17
18class PlotterBase(QtGui.QWidget):
19    def __init__(self, parent=None, manager=None, quickplot=False):
20        super(PlotterBase, self).__init__(parent)
21
22        # Required for the communicator
23        self.manager = manager
24        self.quickplot = quickplot
25
26        # a figure instance to plot on
27        self.figure = plt.figure()
28
29        # Define canvas for the figure to be placed on
30        self.canvas = FigureCanvas(self.figure)
31
32        # ... and the toolbar with all the default MPL buttons
33        self.toolbar = NavigationToolbar(self.canvas, self)
34
35        # Set the layout and place the canvas widget in it.
36        layout = QtGui.QVBoxLayout()
37        layout.setMargin(0)
38        layout.addWidget(self.canvas)
39
40        # 1D plotter defaults
41        self.current_plot = 111
42        self._data = [] # Original 1D/2D object
43        self._xscale = 'log'
44        self._yscale = 'log'
45        self.qx_data = []
46        self.qy_data = []
47        self.color = 0
48        self.symbol = 0
49        self.grid_on = False
50        self.scale = 'linear'
51        self.x_label = "log10(x)"
52        self.y_label = "log10(y)"
53
54        # Pre-define the Scale properties dialog
55        self.properties = ScaleProperties(self,
56                                          init_scale_x=self.x_label,
57                                          init_scale_y=self.y_label)
58
59        # default color map
60        self.cmap = DEFAULT_CMAP
61
62        # Add the axes object -> subplot
63        # TODO: self.ax will have to be tracked and exposed
64        # to enable subplot specific operations
65        self.ax = self.figure.add_subplot(self.current_plot)
66
67        # Set the background color to white
68        self.canvas.figure.set_facecolor('#FFFFFF')
69
70        if not quickplot:
71            # set the layout
72            layout.addWidget(self.toolbar)
73            # Add the context menu
74            self.contextMenu()
75            # Notify PlotHelper about the new plot
76            self.upatePlotHelper()
77        else:
78            self.contextMenuQuickPlot()
79
80        self.setLayout(layout)
81
82    @property
83    def data(self):
84        """ data getter """
85        return self._data
86
87    @data.setter
88    def data(self, data=None):
89        """ Pure virtual data setter """
90        raise NotImplementedError("Data setter must be implemented in derived class.")
91
92    def title(self, title=""):
93        """ title setter """
94        self._title = title
95
96    @property
97    def xLabel(self, xlabel=""):
98        """ x-label setter """
99        return self.x_label
100
101    @xLabel.setter
102    def xLabel(self, xlabel=""):
103        """ x-label setter """
104        self.x_label = r'$%s$'% xlabel
105
106    @property
107    def yLabel(self, ylabel=""):
108        """ y-label setter """
109        return self.y_label
110
111    @yLabel.setter
112    def yLabel(self, ylabel=""):
113        """ y-label setter """
114        self.y_label = r'$%s$'% ylabel
115
116    @property
117    def yscale(self):
118        """ Y-axis scale getter """
119        return self._yscale
120
121    @yscale.setter
122    def yscale(self, scale='linear'):
123        """ Y-axis scale setter """
124        self.ax.set_yscale(scale, nonposy='clip')
125        self._yscale = scale
126
127    @property
128    def xscale(self):
129        """ X-axis scale getter """
130        return self._xscale
131
132    @xscale.setter
133    def xscale(self, scale='linear'):
134        """ X-axis scale setter """
135        self.ax.set_xscale(scale)
136        self._xscale = scale
137
138    def upatePlotHelper(self):
139        """
140        Notify the plot helper about the new plot
141        """
142        # Notify the helper
143        PlotHelper.addPlot(self)
144        # Notify the listeners about a new graph
145        self.manager.communicator.activeGraphsSignal.emit(PlotHelper.currentPlots())
146
147    def defaultContextMenu(self):
148        """
149        Content of the dialog-universal context menu:
150        Save, Print and Copy
151        """
152        # Actions
153        self.contextMenu = QtGui.QMenu(self)
154        self.actionSaveImage = self.contextMenu.addAction("Save Image")
155        self.actionPrintImage = self.contextMenu.addAction("Print Image")
156        self.actionCopyToClipboard = self.contextMenu.addAction("Copy to Clipboard")
157        self.contextMenu.addSeparator()
158
159        # Define the callbacks
160        self.actionSaveImage.triggered.connect(self.onImageSave)
161        self.actionPrintImage.triggered.connect(self.onImagePrint)
162        self.actionCopyToClipboard.triggered.connect(self.onClipboardCopy)
163
164    def contextMenu(self):
165        """
166        Define common context menu and associated actions for the MPL widget
167        TODO: move to plotter1d/plotter2d
168        """
169        raise NotImplementedError("Context menu method must be implemented in derived class.")
170
171    def contextMenuQuickPlot(self):
172        """
173        Define context menu and associated actions for the quickplot MPL widget
174        """
175        raise NotImplementedError("Context menu method must be implemented in derived class.")
176
177    def contextMenuEvent(self, event):
178        """
179        Display the context menu
180        """
181        self.contextMenu.exec_(self.canvas.mapToGlobal(event.pos()))
182
183    def clean(self):
184        """
185        Redraw the graph
186        """
187        self.figure.delaxes(self.ax)
188        self.ax = self.figure.add_subplot(self.current_plot)
189
190    def plot(self, marker=None, linestyle=None):
191        """
192        PURE VIRTUAL
193        Plot the content of self._data
194        """
195        raise NotImplementedError("Plot method must be implemented in derived class.")
196
197    def closeEvent(self, event):
198        """
199        Overwrite the close event adding helper notification
200        """
201        # Please remove me from your database.
202        PlotHelper.deletePlot(PlotHelper.idOfPlot(self))
203        # Notify the listeners
204        self.manager.communicator.activeGraphsSignal.emit(PlotHelper.currentPlots())
205        event.accept()
206
207    def onImageSave(self):
208        """
209        Use the internal MPL method for saving to file
210        """
211        self.toolbar.save_figure()
212
213    def onImagePrint(self):
214        """
215        Display printer dialog and print the MPL widget area
216        """
217        # Define the printer
218        printer = QtGui.QPrinter()
219
220        # Display the print dialog
221        dialog = QtGui.QPrintDialog(printer)
222        dialog.setModal(True)
223        dialog.setWindowTitle("Print")
224        if dialog.exec_() != QtGui.QDialog.Accepted:
225            return
226
227        painter = QtGui.QPainter(printer)
228        # Grab the widget screenshot
229        pmap = QtGui.QPixmap.grabWidget(self)
230        # Create a label with pixmap drawn
231        printLabel = QtGui.QLabel()
232        printLabel.setPixmap(pmap)
233
234        # Print the label
235        printLabel.render(painter)
236        painter.end()
237
238    def onClipboardCopy(self):
239        """
240        Copy MPL widget area to buffer
241        """
242        bmp = QtGui.QApplication.clipboard()
243        pixmap = QtGui.QPixmap.grabWidget(self.canvas)
244        bmp.setPixmap(pixmap)
245
246    def onGridToggle(self):
247        """
248        Add/remove grid lines from MPL plot
249        """
250        self.grid_on = (not self.grid_on)
251        self.ax.grid(self.grid_on)
252        self.canvas.draw_idle()
Note: See TracBrowser for help on using the repository browser.