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
RevLine 
[ef01be4]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
[416fa8f]18class PlotterBase(QtGui.QWidget):
19    def __init__(self, parent=None, manager=None, quickplot=False):
[ef01be4]20        super(PlotterBase, self).__init__(parent)
21
22        # Required for the communicator
[416fa8f]23        self.manager = manager
[ef01be4]24        self.quickplot = quickplot
25
26        # a figure instance to plot on
27        self.figure = plt.figure()
28
[3b7b218]29        # Define canvas for the figure to be placed on
[ef01be4]30        self.canvas = FigureCanvas(self.figure)
31
[3b7b218]32        # ... and the toolbar with all the default MPL buttons
[ef01be4]33        self.toolbar = NavigationToolbar(self.canvas, self)
34
[3b7b218]35        # Set the layout and place the canvas widget in it.
[ef01be4]36        layout = QtGui.QVBoxLayout()
[6d05e1d]37        layout.setMargin(0)
[ef01be4]38        layout.addWidget(self.canvas)
39
[3b7b218]40        # 1D plotter defaults
[ef01be4]41        self.current_plot = 111
[6d05e1d]42        self._data = [] # Original 1D/2D object
43        self._xscale = 'log'
44        self._yscale = 'log'
[ef01be4]45        self.qx_data = []
46        self.qy_data = []
[b4b8589]47        self.color = 0
48        self.symbol = 0
[ef01be4]49        self.grid_on = False
50        self.scale = 'linear'
[6d05e1d]51        self.x_label = "log10(x)"
52        self.y_label = "log10(y)"
[ef01be4]53
[3b7b218]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
[ef01be4]59        # default color map
60        self.cmap = DEFAULT_CMAP
61
[3b7b218]62        # Add the axes object -> subplot
63        # TODO: self.ax will have to be tracked and exposed
64        # to enable subplot specific operations
[ef01be4]65        self.ax = self.figure.add_subplot(self.current_plot)
[3b7b218]66
67        # Set the background color to white
[ef01be4]68        self.canvas.figure.set_facecolor('#FFFFFF')
69
70        if not quickplot:
[6d05e1d]71            # set the layout
[ef01be4]72            layout.addWidget(self.toolbar)
[6d05e1d]73            # Add the context menu
74            self.contextMenu()
[3b7b218]75            # Notify PlotHelper about the new plot
76            self.upatePlotHelper()
[ef01be4]77        else:
78            self.contextMenuQuickPlot()
79
80        self.setLayout(layout)
81
82    @property
83    def data(self):
[b4b8589]84        """ data getter """
[ef01be4]85        return self._data
86
87    @data.setter
88    def data(self, data=None):
[3b7b218]89        """ Pure virtual data setter """
90        raise NotImplementedError("Data setter must be implemented in derived class.")
[ef01be4]91
92    def title(self, title=""):
93        """ title setter """
[6d05e1d]94        self._title = title
[ef01be4]95
[6d05e1d]96    @property
97    def xLabel(self, xlabel=""):
98        """ x-label setter """
99        return self.x_label
100
101    @xLabel.setter
[ef01be4]102    def xLabel(self, xlabel=""):
103        """ x-label setter """
104        self.x_label = r'$%s$'% xlabel
105
[6d05e1d]106    @property
107    def yLabel(self, ylabel=""):
108        """ y-label setter """
109        return self.y_label
110
111    @yLabel.setter
[ef01be4]112    def yLabel(self, ylabel=""):
113        """ y-label setter """
114        self.y_label = r'$%s$'% ylabel
115
[6d05e1d]116    @property
117    def yscale(self):
118        """ Y-axis scale getter """
119        return self._yscale
120
[ef01be4]121    @yscale.setter
[6d05e1d]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
[ef01be4]132    @xscale.setter
[6d05e1d]133    def xscale(self, scale='linear'):
134        """ X-axis scale setter """
135        self.ax.set_xscale(scale)
136        self._xscale = scale
[ef01be4]137
[3b7b218]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
[c4e5400]147    def defaultContextMenu(self):
[ef01be4]148        """
[c4e5400]149        Content of the dialog-universal context menu:
150        Save, Print and Copy
[ef01be4]151        """
152        # Actions
[6d05e1d]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)
[ef01be4]161        self.actionPrintImage.triggered.connect(self.onImagePrint)
162        self.actionCopyToClipboard.triggered.connect(self.onClipboardCopy)
[6d05e1d]163
[c4e5400]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
[6d05e1d]171    def contextMenuQuickPlot(self):
172        """
173        Define context menu and associated actions for the quickplot MPL widget
174        """
[3b7b218]175        raise NotImplementedError("Context menu method must be implemented in derived class.")
[6d05e1d]176
177    def contextMenuEvent(self, event):
178        """
179        Display the context menu
180        """
[b4b8589]181        self.contextMenu.exec_(self.canvas.mapToGlobal(event.pos()))
[6d05e1d]182
[ef01be4]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        """
[3b7b218]192        PURE VIRTUAL
[ef01be4]193        Plot the content of self._data
194        """
[3b7b218]195        raise NotImplementedError("Plot method must be implemented in derived class.")
[ef01be4]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
[416fa8f]204        self.manager.communicator.activeGraphsSignal.emit(PlotHelper.currentPlots())
[ef01be4]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
[6d05e1d]218        printer = QtGui.QPrinter()
219
220        # Display the print dialog
221        dialog = QtGui.QPrintDialog(printer)
222        dialog.setModal(True)
223        dialog.setWindowTitle("Print")
[b4b8589]224        if dialog.exec_() != QtGui.QDialog.Accepted:
[ef01be4]225            return
226
227        painter = QtGui.QPainter(printer)
[b4b8589]228        # Grab the widget screenshot
[ef01be4]229        pmap = QtGui.QPixmap.grabWidget(self)
[b4b8589]230        # Create a label with pixmap drawn
[ef01be4]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        """
[6d05e1d]242        bmp = QtGui.QApplication.clipboard()
243        pixmap = QtGui.QPixmap.grabWidget(self.canvas)
244        bmp.setPixmap(pixmap)
[ef01be4]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.