source: sasview/src/sas/qtgui/PlotterBase.py @ 0ba0774

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 0ba0774 was 27313b7, checked in by Piotr Rozyczko <rozyczko@…>, 7 years ago

Added window title GUI for charts

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