Changeset aadf0af1 in sasview for src/sas/qtgui/Plotter.py


Ignore:
Timestamp:
Jan 4, 2017 4:35:08 AM (7 years ago)
Author:
Piotr Rozyczko <rozyczko@…>
Branches:
ESS_GUI, ESS_GUI_Docs, ESS_GUI_batch_fitting, ESS_GUI_bumps_abstraction, ESS_GUI_iss1116, ESS_GUI_iss879, ESS_GUI_iss959, ESS_GUI_opencl, ESS_GUI_ordering, ESS_GUI_sync_sascalc
Children:
570a58f9
Parents:
257bd57
Message:

Plot specific part of the context menu SASVIEW-427

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/sas/qtgui/Plotter.py

    r257bd57 raadf0af1  
    11from PyQt4 import QtGui 
     2from PyQt4 import QtCore 
     3import functools 
     4import copy 
    25 
    36import matplotlib.pyplot as plt 
     
    58 
    69from sas.sasgui.guiframe.dataFitting import Data1D 
    7 from sas.sasgui.plottools import transform 
    8 from sas.sasgui.plottools.convert_units import convert_unit 
    910from sas.qtgui.PlotterBase import PlotterBase 
     11import sas.qtgui.GuiUtils as GuiUtils 
    1012from sas.qtgui.AddText import AddText 
    1113from sas.qtgui.SetGraphRange import SetGraphRange 
     
    2022        self.addText = AddText(self) 
    2123 
     24        # Dictionary of {plot_id:Data1d} 
     25        self.plot_dict = {} 
     26 
     27        # Simple window for data display 
     28        self.txt_widget = QtGui.QTextEdit(None) 
     29 
    2230    @property 
    2331    def data(self): 
     
    3038        self.xLabel = "%s(%s)"%(value._xaxis, value._xunit) 
    3139        self.yLabel = "%s(%s)"%(value._yaxis, value._yunit) 
    32         self.title(title=value.title) 
     40        self.title(title=value.name) 
    3341 
    3442    def plot(self, data=None, marker=None, linestyle=None, hide_error=False): 
    3543        """ 
    36         Plot self._data 
     44        Add a new plot of self._data to the chart. 
    3745        """ 
    3846        # Data1D 
     
    5058            linestyle = '' 
    5159 
     60        if not self._title: 
     61            self.title(title=self.data.name) 
     62 
    5263        # plot data with/without errorbars 
    5364        if hide_error: 
    54             ax.plot(self._data.view.x, self._data.view.y, 
     65            line = ax.plot(self._data.view.x, self._data.view.y, 
    5566                    marker=marker, 
    5667                    linestyle=linestyle, 
     
    5869                    picker=True) 
    5970        else: 
    60             ax.errorbar(self._data.view.x, self._data.view.y, 
    61                         yerr=self._data.view.dx, xerr=None, 
     71            line = ax.errorbar(self._data.view.x, self._data.view.y, 
     72                        yerr=self._data.view.dy, xerr=None, 
    6273                        capsize=2, linestyle='', 
    6374                        barsabove=False, 
     
    6879                        picker=True) 
    6980 
     81        # Update the list of data sets (plots) in chart 
     82        self.plot_dict[self._data.id] = self.data 
     83 
    7084        # Now add the legend with some customizations. 
    7185        self.legend = ax.legend(loc='upper right', shadow=True) 
    72         #self.legend.get_frame().set_alpha(0.4) 
    7386        self.legend.set_picker(True) 
    7487 
     
    92105        self.canvas.draw() 
    93106 
    94     def contextMenu(self): 
     107    def createContextMenu(self): 
    95108        """ 
    96109        Define common context menu and associated actions for the MPL widget 
    97110        """ 
    98111        self.defaultContextMenu() 
     112 
     113        # Separate plots 
     114        self.addPlotsToContextMenu() 
    99115 
    100116        # Additional menu items 
     
    112128            self.contextMenu.addAction("Reset Graph Range") 
    113129        # Add the title change for dialogs 
    114         if self.parent: 
    115             self.contextMenu.addSeparator() 
    116             self.actionWindowTitle = self.contextMenu.addAction("Window Title") 
     130        #if self.parent: 
     131        self.contextMenu.addSeparator() 
     132        self.actionWindowTitle = self.contextMenu.addAction("Window Title") 
    117133 
    118134        # Define the callbacks 
     
    125141        self.actionWindowTitle.triggered.connect(self.onWindowsTitle) 
    126142 
    127     def contextMenuQuickPlot(self): 
     143    def addPlotsToContextMenu(self): 
     144        """ 
     145        Adds operations on all plotted sets of data to the context menu 
     146        """ 
     147        for id in self.plot_dict.keys(): 
     148            plot = self.plot_dict[id] 
     149            name = plot.name 
     150            plot_menu = self.contextMenu.addMenu('&%s' % name) 
     151 
     152            self.actionDataInfo = plot_menu.addAction("&DataInfo") 
     153            self.actionDataInfo.triggered.connect( 
     154                                functools.partial(self.onDataInfo, plot)) 
     155 
     156            self.actionSavePointsAsFile = plot_menu.addAction("&Save Points as a File") 
     157            self.actionSavePointsAsFile.triggered.connect( 
     158                                functools.partial(self.onSavePoints, plot)) 
     159            plot_menu.addSeparator() 
     160 
     161            if plot.id != 'fit': 
     162                self.actionLinearFit = plot_menu.addAction('&Linear Fit') 
     163                self.actionLinearFit.triggered.connect(self.onLinearFit) 
     164                plot_menu.addSeparator() 
     165 
     166            self.actionRemovePlot = plot_menu.addAction("Remove") 
     167            self.actionRemovePlot.triggered.connect( 
     168                                functools.partial(self.onRemovePlot, id)) 
     169 
     170            if not plot.is_data: 
     171                self.actionFreeze = plot_menu.addAction('&Freeze') 
     172                self.actionFreeze.triggered.connect( 
     173                                functools.partial(self.onFreeze, id)) 
     174            plot_menu.addSeparator() 
     175 
     176            if plot.is_data: 
     177                self.actionHideError = plot_menu.addAction("Hide Error Bar") 
     178                if plot.dy is not None and plot.dy != []: 
     179                    if plot.hide_error: 
     180                        self.actionHideError.setText('Show Error Bar') 
     181                else: 
     182                    self.actionHideError.setEnabled(False) 
     183                self.actionHideError.triggered.connect( 
     184                                functools.partial(self.onToggleHideError, id)) 
     185                plot_menu.addSeparator() 
     186 
     187            self.actionModifyPlot = plot_menu.addAction('&Modify Plot Property') 
     188            self.actionModifyPlot.triggered.connect(self.onModifyPlot) 
     189 
     190    def createContextMenuQuick(self): 
    128191        """ 
    129192        Define context menu and associated actions for the quickplot MPL widget 
     
    231294            self.canvas.draw_idle() 
    232295 
     296    def onDataInfo(self, plot_data): 
     297        """ 
     298        Displays data info text window for the selected plot 
     299        """ 
     300        text_to_show = GuiUtils.retrieveData1d(plot_data) 
     301        # Hardcoded sizes to enable full width rendering with default font 
     302        self.txt_widget.resize(420,600) 
     303 
     304        self.txt_widget.setReadOnly(True) 
     305        self.txt_widget.setWindowFlags(QtCore.Qt.Window) 
     306        self.txt_widget.setWindowIcon(QtGui.QIcon(":/res/ball.ico")) 
     307        self.txt_widget.setWindowTitle("Data Info: %s" % plot_data.filename) 
     308        self.txt_widget.insertPlainText(text_to_show) 
     309 
     310        self.txt_widget.show() 
     311        # Move the slider all the way up, if present 
     312        vertical_scroll_bar = self.txt_widget.verticalScrollBar() 
     313        vertical_scroll_bar.triggerAction(QtGui.QScrollBar.SliderToMinimum) 
     314 
     315    def onSavePoints(self, plot_data): 
     316        """ 
     317        Saves plot data to a file 
     318        """ 
     319        GuiUtils.saveData1D(plot_data) 
     320 
     321    def onLinearFit(self): 
     322        """ 
     323        Creates and displays a simple linear fit for the selected plot 
     324        """ 
     325        pass 
     326 
     327    def onRemovePlot(self, id): 
     328        """ 
     329        Deletes the selected plot from the chart 
     330        """ 
     331        selected_plot = self.plot_dict[id] 
     332 
     333        plot_dict = copy.deepcopy(self.plot_dict) 
     334 
     335        self.plot_dict = {} 
     336 
     337        plt.cla() 
     338        self.ax.cla() 
     339 
     340        for ids in plot_dict: 
     341            if ids != id: 
     342                self.plot(data=plot_dict[ids], hide_error=plot_dict[ids].hide_error)                 
     343 
     344        if len(self.plot_dict) == 0: 
     345            # last plot: graph is empty must be the panel must be destroyed 
     346                self.parent.close() 
     347 
     348    def onFreeze(self, id): 
     349        """ 
     350        Freezes the selected plot to a separate chart 
     351        """ 
     352        plot = self.plot_dict[id] 
     353        self.manager.add_data(data_list=[plot]) 
     354 
     355    def onModifyPlot(self): 
     356        """ 
     357        Allows for MPL modifications to the selected plot 
     358        """ 
     359        pass 
     360 
     361    def onToggleHideError(self, id): 
     362        """ 
     363        Toggles hide error/show error menu item 
     364        """ 
     365        selected_plot = self.plot_dict[id] 
     366        current = selected_plot.hide_error 
     367 
     368        # Flip the flag 
     369        selected_plot.hide_error = not current 
     370 
     371        plot_dict = copy.deepcopy(self.plot_dict) 
     372        self.plot_dict = {} 
     373 
     374        # Clean the canvas 
     375        plt.cla() 
     376        self.ax.cla() 
     377 
     378        # Recreate the plots but reverse the error flag for the current 
     379        for ids in plot_dict: 
     380            if ids == id: 
     381                self.plot(data=plot_dict[ids], hide_error=(not current)) 
     382            else: 
     383                self.plot(data=plot_dict[ids], hide_error=plot_dict[ids].hide_error)                 
     384 
    233385    def xyTransform(self, xLabel="", yLabel=""): 
    234386        """ 
     
    239391        self.ax.cla() 
    240392 
    241         # Changing the scale might be incompatible with 
    242         # currently displayed data (for instance, going 
    243         # from ln to log when all plotted values have 
    244         # negative natural logs). 
    245         # Go linear and only change the scale at the end. 
    246         self._xscale = "linear" 
    247         self._yscale = "linear" 
    248         _xscale = 'linear' 
    249         _yscale = 'linear' 
    250         # Local data is either 1D or 2D 
    251         if self.data.id == 'fit': 
    252             return 
    253  
    254         # control axis labels from the panel itself 
    255         yname, yunits = self.data.get_yaxis() 
    256         xname, xunits = self.data.get_xaxis() 
    257  
    258         # Goes through all possible scales 
    259         # self.x_label is already wrapped with Latex "$", so using the argument 
    260  
    261         # X 
    262         if xLabel == "x": 
    263             self.data.transformX(transform.toX, transform.errToX) 
    264             self.xLabel = "%s(%s)" % (xname, xunits) 
    265         if xLabel == "x^(2)": 
    266             self.data.transformX(transform.toX2, transform.errToX2) 
    267             xunits = convert_unit(2, xunits) 
    268             self.xLabel = "%s^{2}(%s)" % (xname, xunits) 
    269         if xLabel == "x^(4)": 
    270             self.data.transformX(transform.toX4, transform.errToX4) 
    271             xunits = convert_unit(4, xunits) 
    272             self.xLabel = "%s^{4}(%s)" % (xname, xunits) 
    273         if xLabel == "ln(x)": 
    274             self.data.transformX(transform.toLogX, transform.errToLogX) 
    275             self.xLabel = "\ln{(%s)}(%s)" % (xname, xunits) 
    276         if xLabel == "log10(x)": 
    277             self.data.transformX(transform.toX_pos, transform.errToX_pos) 
    278             _xscale = 'log' 
    279             self.xLabel = "%s(%s)" % (xname, xunits) 
    280         if xLabel == "log10(x^(4))": 
    281             self.data.transformX(transform.toX4, transform.errToX4) 
    282             xunits = convert_unit(4, xunits) 
    283             self.xLabel = "%s^{4}(%s)" % (xname, xunits) 
    284             _xscale = 'log' 
    285  
    286         # Y 
    287         if yLabel == "ln(y)": 
    288             self.data.transformY(transform.toLogX, transform.errToLogX) 
    289             self.yLabel = "\ln{(%s)}(%s)" % (yname, yunits) 
    290         if yLabel == "y": 
    291             self.data.transformY(transform.toX, transform.errToX) 
    292             self.yLabel = "%s(%s)" % (yname, yunits) 
    293         if yLabel == "log10(y)": 
    294             self.data.transformY(transform.toX_pos, transform.errToX_pos) 
    295             _yscale = 'log' 
    296             self.yLabel = "%s(%s)" % (yname, yunits) 
    297         if yLabel == "y^(2)": 
    298             self.data.transformY(transform.toX2, transform.errToX2) 
    299             yunits = convert_unit(2, yunits) 
    300             self.yLabel = "%s^{2}(%s)" % (yname, yunits) 
    301         if yLabel == "1/y": 
    302             self.data.transformY(transform.toOneOverX, transform.errOneOverX) 
    303             yunits = convert_unit(-1, yunits) 
    304             self.yLabel = "1/%s(%s)" % (yname, yunits) 
    305         if yLabel == "y*x^(2)": 
    306             self.data.transformY(transform.toYX2, transform.errToYX2) 
    307             xunits = convert_unit(2, xunits) 
    308             self.yLabel = "%s \ \ %s^{2}(%s%s)" % (yname, xname, yunits, xunits) 
    309         if yLabel == "y*x^(4)": 
    310             self.data.transformY(transform.toYX4, transform.errToYX4) 
    311             xunits = convert_unit(4, xunits) 
    312             self.yLabel = "%s \ \ %s^{4}(%s%s)" % (yname, xname, yunits, xunits) 
    313         if yLabel == "1/sqrt(y)": 
    314             self.data.transformY(transform.toOneOverSqrtX, 
    315                                  transform.errOneOverSqrtX) 
    316             yunits = convert_unit(-0.5, yunits) 
    317             self.yLabel = "1/\sqrt{%s}(%s)" % (yname, yunits) 
    318         if yLabel == "ln(y*x)": 
    319             self.data.transformY(transform.toLogXY, transform.errToLogXY) 
    320             self.yLabel = "\ln{(%s \ \ %s)}(%s%s)" % (yname, xname, yunits, xunits) 
    321         if yLabel == "ln(y*x^(2))": 
    322             self.data.transformY(transform.toLogYX2, transform.errToLogYX2) 
    323             xunits = convert_unit(2, xunits) 
    324             self.yLabel = "\ln (%s \ \ %s^{2})(%s%s)" % (yname, xname, yunits, xunits) 
    325         if yLabel == "ln(y*x^(4))": 
    326             self.data.transformY(transform.toLogYX4, transform.errToLogYX4) 
    327             xunits = convert_unit(4, xunits) 
    328             self.yLabel = "\ln (%s \ \ %s^{4})(%s%s)" % (yname, xname, yunits, xunits) 
    329         if yLabel == "log10(y*x^(4))": 
    330             self.data.transformY(transform.toYX4, transform.errToYX4) 
    331             xunits = convert_unit(4, xunits) 
    332             _yscale = 'log' 
    333             self.yLabel = "%s \ \ %s^{4}(%s%s)" % (yname, xname, yunits, xunits) 
    334  
    335         # Perform the transformation of data in data1d->View 
    336         self.data.transformView() 
    337  
    338         self.xscale = _xscale 
    339         self.yscale = _yscale 
     393        new_xlabel, new_ylabel, xscale, yscale = GuiUtils.xyTransform(self.data, xLabel, yLabel) 
     394        self.xscale = xscale 
     395        self.yscale = yscale 
     396        self.xLabel = new_xlabel 
     397        self.yLabel = new_ylabel 
    340398 
    341399        # Plot the updated chart 
     
    347405 
    348406        QtGui.QDialog.__init__(self) 
    349         PlotterWidget.__init__(self, manager=parent, quickplot=quickplot) 
     407        PlotterWidget.__init__(self, parent=self, manager=parent, quickplot=quickplot) 
    350408        icon = QtGui.QIcon() 
    351409        icon.addPixmap(QtGui.QPixmap(":/res/ball.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off) 
Note: See TracChangeset for help on using the changeset viewer.