Changeset aadf0af1 in sasview for src/sas/qtgui/Plotter.py
- Timestamp:
- Jan 4, 2017 4:35:08 AM (7 years ago)
- 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
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/sas/qtgui/Plotter.py
r257bd57 raadf0af1 1 1 from PyQt4 import QtGui 2 from PyQt4 import QtCore 3 import functools 4 import copy 2 5 3 6 import matplotlib.pyplot as plt … … 5 8 6 9 from sas.sasgui.guiframe.dataFitting import Data1D 7 from sas.sasgui.plottools import transform8 from sas.sasgui.plottools.convert_units import convert_unit9 10 from sas.qtgui.PlotterBase import PlotterBase 11 import sas.qtgui.GuiUtils as GuiUtils 10 12 from sas.qtgui.AddText import AddText 11 13 from sas.qtgui.SetGraphRange import SetGraphRange … … 20 22 self.addText = AddText(self) 21 23 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 22 30 @property 23 31 def data(self): … … 30 38 self.xLabel = "%s(%s)"%(value._xaxis, value._xunit) 31 39 self.yLabel = "%s(%s)"%(value._yaxis, value._yunit) 32 self.title(title=value. title)40 self.title(title=value.name) 33 41 34 42 def plot(self, data=None, marker=None, linestyle=None, hide_error=False): 35 43 """ 36 Plot self._data44 Add a new plot of self._data to the chart. 37 45 """ 38 46 # Data1D … … 50 58 linestyle = '' 51 59 60 if not self._title: 61 self.title(title=self.data.name) 62 52 63 # plot data with/without errorbars 53 64 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, 55 66 marker=marker, 56 67 linestyle=linestyle, … … 58 69 picker=True) 59 70 else: 60 ax.errorbar(self._data.view.x, self._data.view.y,61 yerr=self._data.view.d x, xerr=None,71 line = ax.errorbar(self._data.view.x, self._data.view.y, 72 yerr=self._data.view.dy, xerr=None, 62 73 capsize=2, linestyle='', 63 74 barsabove=False, … … 68 79 picker=True) 69 80 81 # Update the list of data sets (plots) in chart 82 self.plot_dict[self._data.id] = self.data 83 70 84 # Now add the legend with some customizations. 71 85 self.legend = ax.legend(loc='upper right', shadow=True) 72 #self.legend.get_frame().set_alpha(0.4)73 86 self.legend.set_picker(True) 74 87 … … 92 105 self.canvas.draw() 93 106 94 def c ontextMenu(self):107 def createContextMenu(self): 95 108 """ 96 109 Define common context menu and associated actions for the MPL widget 97 110 """ 98 111 self.defaultContextMenu() 112 113 # Separate plots 114 self.addPlotsToContextMenu() 99 115 100 116 # Additional menu items … … 112 128 self.contextMenu.addAction("Reset Graph Range") 113 129 # Add the title change for dialogs 114 if self.parent:115 116 130 #if self.parent: 131 self.contextMenu.addSeparator() 132 self.actionWindowTitle = self.contextMenu.addAction("Window Title") 117 133 118 134 # Define the callbacks … … 125 141 self.actionWindowTitle.triggered.connect(self.onWindowsTitle) 126 142 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): 128 191 """ 129 192 Define context menu and associated actions for the quickplot MPL widget … … 231 294 self.canvas.draw_idle() 232 295 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 233 385 def xyTransform(self, xLabel="", yLabel=""): 234 386 """ … … 239 391 self.ax.cla() 240 392 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 340 398 341 399 # Plot the updated chart … … 347 405 348 406 QtGui.QDialog.__init__(self) 349 PlotterWidget.__init__(self, manager=parent, quickplot=quickplot)407 PlotterWidget.__init__(self, parent=self, manager=parent, quickplot=quickplot) 350 408 icon = QtGui.QIcon() 351 409 icon.addPixmap(QtGui.QPixmap(":/res/ball.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
Note: See TracChangeset
for help on using the changeset viewer.