Package nMOLDYN :: Package GUI :: Module PlotNetCDFVariableDialog
[hide private]
[frames] | no frames]

Source Code for Module nMOLDYN.GUI.PlotNetCDFVariableDialog

   1  """This modules implements I{View-->Plot} dialog. 
   2   
   3  Classes: 
   4      * SettingsDialog: sets up the settings dialog. 
   5      * ASCIIToNetCDFConversionDialog: creates I{View-->Plot} dialog used to plot NetCDF variables. 
   6  """ 
   7   
   8  # The python distribution modules 
   9  import os 
  10  import sys 
  11   
  12  # The matplotlib modules 
  13  import pylab 
  14  import matplotlib 
  15  from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg 
  16  from matplotlib.colors import ColorConverter, LogNorm, Normalize, rgb2hex 
  17  from matplotlib.figure import Figure 
  18  from matplotlib.widgets import Cursor 
  19   
  20  # The Tcl/Tk modules 
  21  import _tkinter 
  22  from tkFileDialog import askopenfilename, asksaveasfilename 
  23  from Tkinter import * 
  24  import tkColorChooser 
  25   
  26  # The ScientificPython modules 
  27  from Scientific.IO.NetCDF import _NetCDFFile, NetCDFFile 
  28  from Scientific import N as Num 
  29   
  30  # The MMTK modules. 
  31  from MMTK.Trajectory import Trajectory 
  32   
  33  # The nMOLDYN modules 
  34  from nMOLDYN.Core.Error import Error 
  35  from nMOLDYN.Core.Logger import LogMessage 
  36  from nMOLDYN.Core.Preferences import PREFERENCES 
  37  from nMOLDYN.GUI.Widgets import * 
  38   
  39  # Some modules variables 
  40  # The tuple of the possible interpolations. 
  41  interpolations = ['bessel', 'bilinear', 'bicubic', 'blackman', 'catrom', 'hamming', 'hermite', 'hanning',\ 
  42                    'gaussian', 'kaiser', 'lanczos', 'mitchell', 'nearest', 'spline16', 'spline36', 'quadric', 'sinc'] 
  43   
  44  # The tuple of the possible color maps. 
  45  colorMaps = ['autumn', 'bone', 'cool', 'copper', 'flag', 'gray', 'hot', 'hsv', 'jet', 'pink', 'prism',\ 
  46               'spring', 'summer', 'winter', 'spectral'] 
  47   
  48  # The tuple of the possible line styles. 
  49  lineStyles = ['-', '--', '-.', ':', 'None'] 
  50   
  51  # The tuple of the possible marker styles. 
  52  markerStyles = ['+', '.', '<', '>', 'o', 'p', 's', 'v', 'x', '|', 'None'] 
  53   
  54  axisScales = ['linear', 'log'] 
  55   
56 -class SettingsDialog(Toplevel):
57 """Sets up a dialog tp perform some settings on the plots. 58 """ 59
60 - def __init__(self, parent):
61 """The constructor. 62 63 @param parent: the parent widget. 64 """ 65 66 Toplevel.__init__(self, parent) 67 self.transient(parent) 68 69 self.parent = parent 70 71 self.widgets = {} 72 self.settings = {} 73 74 self.selectedPlot = None 75 76 body = Frame(self) 77 self.initial_focus = self.body(body) 78 body.grid(row = 0, column = 0, sticky = EW) 79 80 self.buttonbox() 81 82 self.grab_set() 83 84 if not self.initial_focus: 85 self.initial_focus = self 86 87 self.protocol("WM_DELETE_WINDOW", self.cancel) 88 89 self.resizable(width = NO, height = NO) 90 91 self.title = 'Settings' 92 93 self.geometry("+%d+%d" % (parent.winfo_rootx()+50, parent.winfo_rooty()+50)) 94 95 self.initial_focus.focus_set() 96 97 self.wait_window(self)
98
99 - def body(self, master):
100 """ 101 Create dialog body. Return widget that should have initial focus. 102 """ 103 104 settingsFrame = LabelFrame(master, text = 'Settings', bd = 2, relief = GROOVE) 105 settingsFrame.grid(row = 0, column = 0, sticky = EW, padx = 3, pady = 3) 106 settingsFrame.grid_columnconfigure(0, weight = 1) 107 settingsFrame.grid_rowconfigure(0, weight = 1) 108 109 self.gFrame = LabelFrame(settingsFrame, text = 'Global', bd = 2, relief = GROOVE) 110 self.gFrame.grid(row = 0, column = 0, sticky = "NEW", padx = 3, pady = 3) 111 self.gFrame.grid_columnconfigure(0, weight = 1) 112 self.gFrame.grid_rowconfigure(0, weight = 1) 113 114 # All the attributes concerning the global and plot settings are set. 115 self.initGlobalSettings() 116 117 # The widget to change plot title. 118 self.widgets['plotTitle'] = ComboStringEntry(self.gFrame,frameLabel = 'Plot title', contents = self.settings['plotTitle']) 119 self.widgets['plotTitle'].grid(row = 1, column = 0, sticky = "NEW") 120 self.widgets['plotTitle'].grid_columnconfigure(0, weight = 1) 121 self.widgets['plotTitle'].entry.bind('<FocusOut>', lambda event : self.changeSettings(event, 'plotTitle')) 122 123 # The widget to change X-axis label. 124 self.widgets['xLabel'] = ComboStringEntry(self.gFrame,frameLabel = 'X label', contents = self.settings['xLabel']) 125 self.widgets['xLabel'].grid(row = 2, column = 0, sticky = "NEW") 126 self.widgets['xLabel'].grid_columnconfigure(0, weight = 1) 127 self.widgets['xLabel'].entry.bind('<FocusOut>', lambda event : self.changeSettings(event, 'xLabel')) 128 129 # The widget to change Y-axis label. 130 self.widgets['yLabel'] = ComboStringEntry(self.gFrame,frameLabel = 'Y label', contents = self.settings['yLabel']) 131 self.widgets['yLabel'].grid(row = 3, column = 0, sticky = "NEW") 132 self.widgets['yLabel'].grid_columnconfigure(0, weight = 1) 133 self.widgets['yLabel'].entry.bind('<FocusOut>', lambda event : self.changeSettings(event, 'yLabel')) 134 135 # The widget to change X-axis ticks contents. 136 self.widgets['xTicks'] = ComboStringEntry(self.gFrame,frameLabel = 'X ticks', contents = self.settings['xTicks']) 137 self.widgets['xTicks'].grid(row = 4, column = 0, sticky = "NEW") 138 self.widgets['xTicks'].grid_columnconfigure(0, weight = 1) 139 self.widgets['xTicks'].entry.bind('<FocusOut>', lambda event : self.changeSettings(event, 'xTicks')) 140 141 # The widget to change X-axis ticks size. 142 self.widgets['xTicksSize'] = ComboIntegerEntry(self.gFrame, frameLabel = 'X ticks size', contents = self.settings['xTicksSize']) 143 self.widgets['xTicksSize'].grid(row = 5, column = 0, sticky = "NEW") 144 self.widgets['xTicksSize'].grid_columnconfigure(0, weight = 1) 145 self.widgets['xTicksSize'].entry.bind('<FocusOut>', lambda event : self.changeSettings(event, 'xTicksSize')) 146 147 # The widget to change X-axis ticks angle. 148 self.widgets['xTicksAngle'] = ComboIntegerEntry(self.gFrame, frameLabel = 'X ticks angle', contents = self.settings['xTicksAngle']) 149 self.widgets['xTicksAngle'].grid(row = 6, column = 0, sticky = "NEW") 150 self.widgets['xTicksAngle'].grid_columnconfigure(0, weight = 1) 151 self.widgets['xTicksAngle'].entry.bind('<FocusOut>', lambda event : self.changeSettings(event, 'xTicksAngle')) 152 153 # The widget to change Y-axis ticks contents. 154 self.widgets['yTicks'] = ComboStringEntry(self.gFrame,frameLabel = 'Y ticks', contents = self.settings['yTicks']) 155 self.widgets['yTicks'].grid(row = 7, column = 0, sticky = "NEW") 156 self.widgets['yTicks'].grid_columnconfigure(0, weight = 1) 157 self.widgets['yTicks'].entry.bind('<FocusOut>', lambda event : self.changeSettings(event, 'yTicks')) 158 159 # The widget to change Y-axis ticks size. 160 self.widgets['yTicksSize'] = ComboIntegerEntry(self.gFrame, frameLabel = 'Y ticks size', contents = self.settings['yTicksSize']) 161 self.widgets['yTicksSize'].grid(row = 8, column = 0, sticky = "NEW") 162 self.widgets['yTicksSize'].grid_columnconfigure(0, weight = 1) 163 self.widgets['yTicksSize'].entry.bind('<FocusOut>', lambda event : self.changeSettings(event, 'yTicksSize')) 164 165 # The widget to change Y-axis ticks angle. 166 self.widgets['yTicksAngle'] = ComboIntegerEntry(self.gFrame, frameLabel = 'Y ticks angle', contents = self.settings['yTicksAngle']) 167 self.widgets['yTicksAngle'].grid(row = 9, column = 0, sticky = "NEW") 168 self.widgets['yTicksAngle'].grid_columnconfigure(0, weight = 1) 169 self.widgets['yTicksAngle'].entry.bind('<FocusOut>', lambda event : self.changeSettings(event, 'yTicksAngle')) 170 171 # The widget to change X-axis range. 172 self.widgets['xRange'] = ComboStringEntry(self.gFrame,frameLabel = 'X range', contents = self.settings['xRange']) 173 self.widgets['xRange'].grid(row = 10, column = 0, sticky = "NEW") 174 self.widgets['xRange'].grid_columnconfigure(0, weight = 1) 175 self.widgets['xRange'].entry.bind('<FocusOut>', lambda event : self.changeSettings(event, 'xRange')) 176 177 # The widget to change Y-axis range. 178 self.widgets['yRange'] = ComboStringEntry(self.gFrame,frameLabel = 'Y range', contents = self.settings['yRange']) 179 self.widgets['yRange'].grid(row = 11, column = 0, sticky = "NEW") 180 self.widgets['yRange'].grid_columnconfigure(0, weight = 1) 181 self.widgets['yRange'].entry.bind('<FocusOut>', lambda event : self.changeSettings(event, 'yRange')) 182 183 if len(self.parent.figure.gca().get_images()) == 0: 184 v = axisScales.index(self.settings['xScale']) 185 # The widget to change X-axis scale. 186 self.widgets['xScale'] = ComboRadiobutton(self.gFrame,\ 187 frameLabel = 'X scale',\ 188 contents = axisScales,\ 189 default = v,\ 190 layout = (1,2)) 191 self.widgets['xScale'].grid(row = 12, column = 0, sticky = "NEW") 192 self.widgets['xScale'].grid_columnconfigure(0, weight = 1) 193 for r in self.widgets['xScale'].radio: 194 r.bind('<ButtonRelease-1>', lambda event : self.changeSettings(event, 'xScale')) 195 196 v = axisScales.index(self.settings['yScale']) 197 # The widget to change Y-axis scale. 198 self.widgets['yScale'] = ComboRadiobutton(self.gFrame,\ 199 frameLabel = 'Y scale',\ 200 contents = axisScales,\ 201 default = v,\ 202 layout = (1,2)) 203 self.widgets['yScale'].grid(row = 13, column = 0, sticky = "NEW") 204 self.widgets['yScale'].grid_columnconfigure(0, weight = 1) 205 for r in self.widgets['yScale'].radio: 206 r.bind('<ButtonRelease-1>', lambda event : self.changeSettings(event, 'yScale')) 207 208 else: 209 v = axisScales.index(self.settings['zScale']) 210 # The widget to change Z-axis scale. 211 self.widgets['zScale'] = ComboRadiobutton(self.gFrame,\ 212 frameLabel = 'Z scale',\ 213 contents = axisScales,\ 214 default = v,\ 215 layout = (1,2)) 216 self.widgets['zScale'].grid(row = 12, column = 0, sticky = "NEW") 217 self.widgets['zScale'].grid_columnconfigure(0, weight = 1) 218 for r in self.widgets['zScale'].radio: 219 r.bind('<ButtonRelease-1>', lambda event : self.changeSettings(event, 'zScale')) 220 221 # The widget to change grid line width. 222 self.widgets['gridWidth'] = ComboFloatEntry(self.gFrame, frameLabel = 'Grid width', contents = self.settings['gridWidth']) 223 self.widgets['gridWidth'].grid(row = 15, column = 0, sticky = "NEW") 224 self.widgets['gridWidth'].grid_columnconfigure(0, weight = 1) 225 self.widgets['gridWidth'].entry.bind('<FocusOut>', lambda event : self.changeSettings(event, 'gridWidth')) 226 227 # The widget to change grid style. 228 self.widgets['gridStyle'] = ComboSpinbox(self.gFrame, frameLabel = 'Grid style', default = self.settings['gridStyle'], contents = tuple(lineStyles)) 229 self.widgets['gridStyle'].grid(row = 16, column = 0, sticky = "NEW") 230 self.widgets['gridStyle'].grid_columnconfigure(0, weight = 1) 231 self.widgets['gridStyle'].spinbox.config({'width' : 10, 'command' : lambda : self.changeSettings(None, 'gridStyle')}) 232 233 # The button to change grid color. 234 self.widgets['gridColor'] = ComboButton(self.gFrame,\ 235 frameLabel = 'Grid color') 236 self.widgets['gridColor'].grid(row = 17, column = 0, sticky = "NEW") 237 self.widgets['gridColor'].grid_columnconfigure(0, weight = 1) 238 self.widgets['gridColor'].button.config({'bg' : self.settings['gridColor'],\ 239 'activebackground' : self.settings['gridColor'],\ 240 'width' : 1,\ 241 'command' : lambda : self.changeSettings(None, 'gridColor')}) 242 self.widgets['gridColor'].results = self.settings['gridColor'] 243 244 self.pFrame = LabelFrame(settingsFrame, text = 'Plot', bd = 2, relief = GROOVE) 245 self.pFrame.grid(row = 0, column = 1, sticky = "NEW", padx = 3, pady = 3) 246 self.pFrame.grid_columnconfigure(1, weight = 1) 247 self.pFrame.grid_rowconfigure(0, weight = 1) 248 249 # The listbox that will contain the plot list. 250 self.plots = ComboListbox(self.pFrame, frameLabel = 'Available plots', contents = []) 251 self.plots.grid(row = 0, column = 0, sticky = "NEW") 252 self.plots.grid_columnconfigure(0, weight = 1) 253 self.plots.grid_rowconfigure(0, weight = 1) 254 self.plots.lb.config({'exportselection' : 0, 'width' : 28, 'height' : 4, 'selectmode' : SINGLE}) 255 self.plots.lb.bind('<ButtonRelease-1>', self.addPlotSettingsWidgets) 256 257 if self.parent.figure.gca().get_images(): 258 self.plots.lb.insert(END, self.parent.figure.gca().get_images()[0].get_label()) 259 260 else: 261 for f in self.parent.figure.gca().get_lines(): 262 self.plots.lb.insert(END, f.get_label()) 263 264 self.plots.lb.selection_set(0) 265 266 self.addPlotSettingsWidgets() 267 268 return None
269
270 - def buttonbox(self):
271 """ 272 Add standard button box. 273 """ 274 275 # The frame that contains the 'Cancel' and 'OK' buttons. 276 box = LabelFrame(self, text = 'Actions', bd = 2, relief = GROOVE) 277 box.grid(row = 1, column = 0, sticky = EW, padx = 3, pady = 3) 278 box.grid_columnconfigure(0, weight = 1) 279 280 w = Button(box, text = "Cancel", width = 10, command = self.cancel) 281 w.grid(row = 0, column = 0, sticky = E) 282 283 w = Button(box, text = "OK", width = 10, command = self.ok, default = ACTIVE) 284 w.grid(row = 0, column = 4, sticky = E) 285 286 self.bind("<Return>", self.ok) 287 self.bind("<Escape>", self.cancel)
288 289 # Standard button semantics.
290 - def ok(self, event = None):
291 292 if not self.validate(): 293 self.initial_focus.focus_set() 294 return 295 296 self.withdraw() 297 self.update_idletasks() 298 299 self.apply() 300 301 self.cancel()
302
303 - def cancel(self, event=None):
304 305 # Put focus back to the parent window 306 self.parent.grab_set() 307 self.parent.focus_set() 308 self.destroy()
309 310 # Command hooks
311 - def validate(self):
312 313 try: 314 self.storeSettings() 315 316 except: 317 LogMessage('warning','Bad input. Please try again.',['gui']) 318 return False 319 320 return True
321
322 - def apply(self):
323 try: 324 for k, v in self.settings.items(): 325 if k == 'plotTitle': 326 self.parent.figure.gca().set_title(v) 327 elif k == 'xRange': 328 xMin, xMax = [float(vv) for vv in v.split('-')] 329 self.parent.figure.gca().set_xlim((xMin, xMax)) 330 elif k == 'yRange': 331 yMin, yMax = [float(vv) for vv in v.split('-')] 332 self.parent.figure.gca().set_ylim((yMin,yMax)) 333 elif k == 'xLabel': 334 self.parent.figure.gca().set_xlabel(v) 335 elif k == 'yLabel': 336 self.parent.figure.gca().set_ylabel(v) 337 elif k == 'xScale': 338 self.parent.figure.gca().set_xscale(v) 339 elif k == 'yScale': 340 self.parent.figure.gca().set_yscale(v) 341 elif k == 'zScale': 342 if v == 'linear': 343 self.parent.figure.gca().get_images()[self.selectedPlot].set_norm(Normalize()) 344 else: 345 self.parent.figure.gca().get_images()[self.selectedPlot].set_norm(LogNorm()) 346 elif k == 'xTicks': 347 ticks, ticksLabels = [eval(t) for t in v.split(';')] 348 ticks = [float(t) for t in ticks] 349 ticksLabels = [str(t) for t in ticksLabels] 350 351 self.parent.figure.gca().set_xticks(ticks) 352 self.parent.figure.gca().set_xticklabels(ticksLabels) 353 elif k == 'xTicksSize': 354 [l.set_size(int(v)) for l in self.parent.figure.gca().get_xticklabels()] 355 elif k == 'xTicksAngle': 356 [l.set_rotation(int(v)) for l in self.parent.figure.gca().get_xticklabels()] 357 elif k == 'yTicks': 358 ticks, ticksLabels = [eval(t) for t in v.split(';')] 359 ticks = [float(t) for t in ticks] 360 ticksLabels = [str(t) for t in ticksLabels] 361 362 self.parent.figure.gca().set_yticks(ticks) 363 self.parent.figure.gca().set_yticklabels(ticksLabels) 364 elif k == 'yTicksSize': 365 [l.set_size(int(v)) for l in self.parent.figure.gca().get_yticklabels()] 366 elif k == 'yTicksAngle': 367 [l.set_rotation(int(v)) for l in self.parent.figure.gca().get_yticklabels()] 368 elif k == 'gridWidth': 369 self.parent.figure.gca().grid(True, linewidth = v) 370 elif k == 'gridStyle': 371 self.parent.figure.gca().grid(True, linestyle = v) 372 elif k == 'gridColor': 373 self.parent.figure.gca().grid(True, color = v) 374 elif isinstance(k, int): 375 for kk, vv in v.items(): 376 if kk == 'lineLabel': 377 self.parent.figure.gca().get_lines()[k].set_label(vv) 378 self.plots.lb.delete(k) 379 self.plots.lb.insert(k, vv) 380 elif kk == 'lineWidth': 381 self.parent.figure.gca().get_lines()[k].set_linewidth(vv) 382 elif kk == 'lineStyle': 383 self.parent.figure.gca().get_lines()[k].set_linestyle(vv) 384 elif kk == 'lineColor': 385 self.parent.figure.gca().get_lines()[k].set_color(vv) 386 elif kk == 'markerSize': 387 self.parent.figure.gca().get_lines()[k].set_markersize(vv) 388 elif kk == 'markerStyle': 389 self.parent.figure.gca().get_lines()[k].set_marker(vv) 390 elif kk == 'markerColor': 391 self.parent.figure.gca().get_lines()[k].set_markeredgecolor(vv) 392 elif kk == 'colorMap': 393 colorMap = eval('pylab.cm.' + vv) 394 self.parent.figure.gca().get_images()[k].set_cmap(colorMap) 395 elif kk == 'interpolation': 396 self.parent.figure.gca().get_images()[k].set_interpolation(vv) 397 elif kk == 'alpha': 398 self.parent.figure.gca().get_images()[k].set_alpha(vv) 399 400 self.parent.figure.gca().legend(loc = 'best') 401 self.parent.canvas.show() 402 403 except: 404 raise Error('Error when updating plots.')
405
406 - def initGlobalSettings(self):
407 408 self.settings['plotTitle'] = self.parent.figure.gca().title.get_text() 409 self.settings['xRange'] = '-'.join([str(v) for v in self.parent.figure.gca().get_xlim()]) 410 self.settings['yRange'] = '-'.join([str(v) for v in self.parent.figure.gca().get_ylim()]) 411 self.settings['xLabel'] = self.parent.figure.gca().xaxis.get_label().get_text() 412 self.settings['yLabel'] = self.parent.figure.gca().yaxis.get_label().get_text() 413 414 # The selected plot is a 2D plot. 415 if len(self.parent.figure.gca().get_images()) == 0: 416 self.settings['xScale'] = self.parent.figure.gca().get_xscale() 417 self.settings['yScale'] = self.parent.figure.gca().get_yscale() 418 else: 419 self.settings['xScale'] = 'linear' 420 self.settings['yScale'] = 'linear' 421 self.settings['zScale'] = 'linear' 422 423 self.settings['xTicks'] = str(list(self.parent.figure.gca().get_xticks())) 424 self.settings['xTicks'] += ';' + str([v.get_text() for v in self.parent.figure.gca().get_xticklabels()]) 425 self.settings['xTicksSize'] = int(self.parent.figure.gca().get_xticklabels()[0].get_size()) 426 self.settings['xTicksAngle'] = int(self.parent.figure.gca().get_xticklabels()[0].get_rotation()) 427 self.settings['yTicks'] = str(list(self.parent.figure.gca().get_yticks())) 428 self.settings['yTicks'] += ';' + str([v.get_text() for v in self.parent.figure.gca().get_yticklabels()]) 429 self.settings['yTicksSize'] = int(self.parent.figure.gca().get_yticklabels()[0].get_size()) 430 self.settings['yTicksAngle'] = int(self.parent.figure.gca().get_yticklabels()[0].get_rotation()) 431 self.settings['gridWidth'] = float(self.parent.figure.gca().get_xgridlines()[0].get_linewidth()) 432 self.settings['gridStyle'] = lineStyles.index(self.parent.figure.gca().get_xgridlines()[0].get_linestyle()) 433 self.settings['gridColor'] = rgb2hex(ColorConverter().to_rgb(self.parent.figure.gca().get_xgridlines()[0].get_color()))
434
435 - def initPlotSettings(self):
436 437 if self.selectedPlot is None: 438 return 439 440 else: 441 self.settings[self.selectedPlot] = {} 442 443 # The selected plot is a 2D plot. 444 if len(self.parent.figure.gca().get_images()) == 0: 445 # The instance of the plot to set up. 446 plot = self.parent.figure.get_axes()[0].get_lines()[self.selectedPlot] 447 448 self.settings[self.selectedPlot]['lineLabel'] = plot.get_label() 449 self.settings[self.selectedPlot]['lineWidth'] = int(float(plot.get_linewidth())) 450 451 self.settings[self.selectedPlot]['lineStyle'] = plot.get_linestyle() 452 self.settings[self.selectedPlot]['lineColor'] = rgb2hex(ColorConverter().to_rgb(plot.get_color())) 453 454 self.settings[self.selectedPlot]['markerStyle'] = plot.get_marker() 455 self.settings[self.selectedPlot]['markerSize'] = int(plot.get_markersize()) 456 self.settings[self.selectedPlot]['markerColor'] = rgb2hex(ColorConverter().to_rgb(plot.get_markeredgecolor())) 457 458 else: 459 # The instance of the plot to set up. 460 plot = self.parent.figure.gca().get_images()[self.selectedPlot] 461 462 self.settings[self.selectedPlot]['colorMap'] = plot.cmap.name 463 self.settings[self.selectedPlot]['interpolation'] = plot._interpolation 464 self.settings[self.selectedPlot]['alpha'] = plot.get_alpha()
465
466 - def storeSettings(self):
467 468 self.settings['plotTitle'] = self.widgets['plotTitle'].getValue() 469 self.settings['xRange'] = self.widgets['xRange'].getValue() 470 self.settings['yRange'] = self.widgets['yRange'].getValue() 471 self.settings['xLabel'] = self.widgets['xLabel'].getValue() 472 self.settings['yLabel'] = self.widgets['yLabel'].getValue() 473 474 self.settings['xTicks'] = self.widgets['xTicks'].getValue() 475 self.settings['xTicksSize'] = self.widgets['xTicksSize'].getValue() 476 self.settings['xTicksAngle'] = self.widgets['xTicksAngle'].getValue() 477 self.settings['yTicks'] = self.widgets['yTicks'].getValue() 478 self.settings['yTicksSize'] = self.widgets['yTicksSize'].getValue() 479 self.settings['yTicksAngle'] = self.widgets['yTicksAngle'].getValue() 480 481 self.settings['gridWidth'] = self.widgets['gridWidth'].getValue() 482 self.settings['gridStyle'] = self.widgets['gridStyle'].getValue() 483 self.settings['gridColor'] = self.widgets['gridColor'].getValue() 484 485 # The selected plot is a 2D plot. 486 if len(self.parent.figure.gca().get_images()) == 0: 487 self.settings['xScale'] = self.widgets['xScale'].getValue() 488 self.settings['yScale'] = self.widgets['yScale'].getValue() 489 490 self.settings[self.selectedPlot]['lineLabel'] = self.widgets['lineLabel'].getValue() 491 self.settings[self.selectedPlot]['lineWidth'] = self.widgets['lineWidth'].getValue() 492 self.settings[self.selectedPlot]['lineStyle'] = self.widgets['lineStyle'].getValue() 493 self.settings[self.selectedPlot]['lineColor'] = self.widgets['lineColor'].getValue() 494 495 self.settings[self.selectedPlot]['markerStyle'] = self.widgets['markerStyle'].getValue() 496 self.settings[self.selectedPlot]['markerSize'] = self.widgets['markerSize'].getValue() 497 self.settings[self.selectedPlot]['markerColor'] = self.widgets['markerColor'].getValue() 498 499 else: 500 self.settings['xScale'] = 'linear' 501 self.settings['yScale'] = 'linear' 502 self.settings['zScale'] = self.widgets['zScale'].getValue() 503 504 self.settings[self.selectedPlot]['colorMap'] = self.widgets['colorMap'].getValue() 505 self.settings[self.selectedPlot]['interpolation'] = self.widgets['interpolation'].getValue() 506 self.settings[self.selectedPlot]['alpha'] = self.widgets['alpha'].getValue()
507
508 - def selectColor(self, widget):
509 510 defaultColor = widget.button.cget('bg') 511 512 junk, selectedColor = tkColorChooser.askcolor(color = defaultColor, master = self) 513 if isinstance(selectedColor, _tkinter.Tcl_Obj): 514 selectedColor = selectedColor.string 515 516 elif isinstance(selectedColor, str): 517 pass 518 519 else: 520 selectedColor = defaultColor 521 522 widget.button.configure(bg = selectedColor, activebackground = selectedColor) 523 widget.results = selectedColor 524 525 return selectedColor
526
527 - def changeSettings(self, event, widgetName):
528 """ 529 Argument: 530 - event: either a Tkinter event, either a Tkinter control variable value that has been traced for changes. 531 """ 532 533 if not self.widgets.has_key(widgetName): 534 return 535 536 w = self.widgets[widgetName] 537 if widgetName == 'plotTitle': 538 self.parent.figure.gca().set_title(w.getValue()) 539 elif widgetName == 'xRange': 540 xMin, xMax = [float(v) for v in w.getValue().split('-')] 541 self.parent.figure.gca().set_xlim((xMin,xMax)) 542 elif widgetName == 'yRange': 543 yMin, yMax = [float(v) for v in w.getValue().split('-')] 544 self.parent.figure.gca().set_ylim((yMin,yMax)) 545 elif widgetName == 'xLabel': 546 self.parent.figure.gca().set_xlabel(w.getValue()) 547 elif widgetName == 'yLabel': 548 self.parent.figure.gca().set_ylabel(w.getValue()) 549 elif widgetName == 'xScale': 550 self.parent.figure.gca().set_xscale(w.getValue()) 551 elif widgetName == 'yScale': 552 self.parent.figure.gca().set_yscale(w.getValue()) 553 elif widgetName == 'zScale': 554 if w.getValue() == 'linear': 555 self.parent.figure.gca().get_images()[self.selectedPlot].set_norm(Normalize()) 556 else: 557 self.parent.figure.gca().get_images()[self.selectedPlot].set_norm(LogNorm()) 558 elif widgetName == 'gridWidth': 559 self.parent.figure.gca().grid(True, linewidth = w.getValue()) 560 elif widgetName == 'gridStyle': 561 self.parent.figure.gca().grid(True, linestyle = w.getValue()) 562 elif widgetName == 'gridColor': 563 color = self.selectColor(w) 564 self.parent.figure.gca().grid(True, color = color) 565 elif widgetName == 'xTicks': 566 ticks, ticksLabels = [eval(t) for t in w.getValue().split(';')] 567 ticks = [float(t) for t in ticks] 568 ticksLabels = [str(t) for t in ticksLabels] 569 self.parent.figure.gca().set_xticks(ticks) 570 self.parent.figure.gca().set_xticklabels(ticksLabels) 571 elif widgetName == 'xTicksSize': 572 [l.set_size(int(w.getValue())) for l in self.parent.figure.gca().get_xticklabels()] 573 elif widgetName == 'xTicksAngle': 574 [l.set_rotation(int(w.getValue())) for l in self.parent.figure.gca().get_xticklabels()] 575 elif widgetName == 'yTicks': 576 ticks, ticksLabels = [eval(t) for t in w.getValue().split(';')] 577 ticks = [float(t) for t in ticks] 578 ticksLabels = [str(t) for t in ticksLabels] 579 self.parent.figure.gca().set_yticks(ticks) 580 self.parent.figure.gca().set_yticklabels(ticksLabels) 581 elif widgetName == 'yTicksSize': 582 [l.set_size(int(w.getValue())) for l in self.parent.figure.gca().get_yticklabels()] 583 elif widgetName == 'yTicksAngle': 584 [l.set_rotation(int(w.getValue())) for l in self.parent.figure.gca().get_yticklabels()] 585 elif widgetName == 'lineLabel': 586 self.parent.figure.gca().get_lines()[self.selectedPlot].set_label(w.getValue()) 587 self.plots.lb.delete(self.selectedPlot) 588 self.plots.lb.insert(self.selectedPlot, w.getValue()) 589 elif widgetName == 'lineWidth': 590 self.parent.figure.gca().get_lines()[self.selectedPlot].set_linewidth(w.getValue()) 591 elif widgetName == 'lineStyle': 592 self.parent.figure.gca().get_lines()[self.selectedPlot].set_linestyle(w.getValue()) 593 elif widgetName == 'lineColor': 594 color = self.selectColor(w) 595 self.parent.figure.gca().get_lines()[self.selectedPlot].set_color(color) 596 elif widgetName == 'markerSize': 597 self.parent.figure.gca().get_lines()[self.selectedPlot].set_markersize(w.getValue()) 598 elif widgetName == 'markerStyle': 599 self.parent.figure.gca().get_lines()[self.selectedPlot].set_marker(w.getValue()) 600 elif widgetName == 'markerColor': 601 color = self.selectColor(w) 602 self.parent.figure.gca().get_lines()[self.selectedPlot].set_markeredgecolor(color) 603 elif widgetName == 'alpha': 604 self.parent.figure.gca().get_images()[self.selectedPlot].set_alpha(w.getValue()) 605 elif widgetName == 'colorMap': 606 colorMap = eval('pylab.cm.' + w.getValue()) 607 self.parent.figure.gca().get_images()[self.selectedPlot].set_cmap(colorMap) 608 elif widgetName == 'interpolation': 609 self.parent.figure.gca().get_images()[self.selectedPlot].set_interpolation(w.getValue()) 610 611 self.parent.figure.gca().legend(loc = 'best') 612 self.parent.canvas.show()
613
614 - def removePreviousPlotSettings(self):
615 """ 616 This method removes the previous plot settings widgets. 617 """ 618 619 # Loop over all the plot settings widgets. 620 for widget in self.pFrame.winfo_children(): 621 # Keep the plot settings list box 622 if widget == self.plots: 623 continue 624 625 # Destroys all the other ones. 626 else: 627 widget.destroy()
628
629 - def addPlotSettingsWidgets(self, event = None):
630 631 if event is not None: 632 if not event.widget.curselection(): 633 return 634 635 self.selectedPlot = int(self.plots.lb.curselection()[0]) 636 637 self.removePreviousPlotSettings() 638 639 self.initPlotSettings() 640 641 # The selected plot is a 2D plot. 642 if len(self.parent.figure.gca().get_images()) == 0: 643 644 self.widgets['lineLabel'] = ComboStringEntry(self.pFrame, frameLabel = 'Plot label', contents = self.settings[self.selectedPlot]['lineLabel']) 645 self.widgets['lineLabel'].grid(row = 1, column = 0, sticky = "NEW") 646 self.widgets['lineLabel'].grid_columnconfigure(0, weight = 1) 647 self.widgets['lineLabel'].grid_rowconfigure(1, weight = 1) 648 self.widgets['lineLabel'].entry.bind('<FocusOut>', lambda event : self.changeSettings(event, 'lineLabel')) 649 650 self.widgets['lineWidth'] = ComboIntegerEntry(self.pFrame, frameLabel = 'Line width', contents = self.settings[self.selectedPlot]['lineWidth']) 651 self.widgets['lineWidth'].grid(row = 2, column = 0, sticky = "NEW") 652 self.widgets['lineWidth'].grid_columnconfigure(0, weight = 1) 653 self.widgets['lineWidth'].grid_rowconfigure(2, weight = 1) 654 self.widgets['lineWidth'].entry.bind('<FocusOut>', lambda event : self.changeSettings(event, 'lineWidth')) 655 656 v = lineStyles.index(self.settings[self.selectedPlot]['lineStyle']) 657 self.widgets['lineStyle'] = ComboSpinbox(self.pFrame,\ 658 frameLabel = 'Line style',\ 659 default = v,\ 660 contents = tuple(lineStyles)) 661 self.widgets['lineStyle'].grid(row = 3, column = 0, sticky = "NEW") 662 self.widgets['lineStyle'].grid_columnconfigure(0, weight = 1) 663 self.widgets['lineStyle'].grid_rowconfigure(3, weight = 1) 664 self.widgets['lineStyle'].spinbox.config({'width' : 10, 'command' : lambda : self.changeSettings(None, 'lineStyle')}) 665 666 self.widgets['lineColor'] = ComboButton(self.pFrame, frameLabel = 'Line color') 667 self.widgets['lineColor'].grid(row = 4, column = 0, sticky = "NEW") 668 self.widgets['lineColor'].grid_columnconfigure(0, weight = 1) 669 self.widgets['lineColor'].grid_rowconfigure(4, weight = 1) 670 self.widgets['lineColor'].button.config({'bg' : self.settings[self.selectedPlot]['lineColor'],\ 671 'activebackground' : self.settings[self.selectedPlot]['lineColor'],\ 672 'width' : 1,\ 673 'command' : lambda : self.changeSettings(None, 'lineColor')}) 674 self.widgets['lineColor'].results = self.settings[self.selectedPlot]['lineColor'] 675 676 v = markerStyles.index(self.settings[self.selectedPlot]['markerStyle']) 677 self.widgets['markerStyle'] = ComboSpinbox(self.pFrame, frameLabel = 'Marker style',\ 678 default = v,\ 679 contents = tuple(markerStyles)) 680 self.widgets['markerStyle'].grid(row = 5, column = 0, sticky = "NEW") 681 self.widgets['markerStyle'].grid_columnconfigure(0, weight = 1) 682 self.widgets['markerStyle'].grid_rowconfigure(5, weight = 1) 683 self.widgets['markerStyle'].spinbox.config({'width' : 10, 'command' : lambda : self.changeSettings(None, 'markerStyle')}) 684 685 self.widgets['markerSize'] = ComboIntegerEntry(self.pFrame, frameLabel = 'Marker size', contents = self.settings[self.selectedPlot]['markerSize']) 686 self.widgets['markerSize'].grid(row = 6, column = 0, sticky = "NEW") 687 self.widgets['markerSize'].grid_columnconfigure(0, weight = 1) 688 self.widgets['markerSize'].grid_rowconfigure(6, weight = 1) 689 self.widgets['markerSize'].entry.bind('<FocusOut>', lambda event : self.changeSettings(event, 'markerSize')) 690 691 self.widgets['markerColor'] = ComboButton(self.pFrame, frameLabel = 'Marker color') 692 self.widgets['markerColor'].grid(row = 7, column = 0, sticky = "NEW") 693 self.widgets['markerColor'].grid_columnconfigure(0, weight = 1) 694 self.widgets['markerColor'].grid_rowconfigure(7, weight = 1) 695 self.widgets['markerColor'].button.config({'bg' : self.settings[self.selectedPlot]['markerColor'],\ 696 'activebackground' : self.settings[self.selectedPlot]['markerColor'],\ 697 'width' : 1,\ 698 'command' : lambda event : self.changeSettings(event, 'markerColor')}) 699 self.widgets['markerColor'].results = self.settings[self.selectedPlot]['markerColor'] 700 701 # The selected plot is a 3D plot. 702 else: 703 704 v = colorMaps.index(self.settings[self.selectedPlot]['colorMap']) 705 self.widgets['colorMap'] = ComboSpinbox(self.pFrame,\ 706 frameLabel = 'Color map',\ 707 default = v,\ 708 contents = tuple(colorMaps)) 709 self.widgets['colorMap'].grid(row = 1, column = 0, sticky = "NEW") 710 self.widgets['colorMap'].grid_columnconfigure(0, weight = 1) 711 self.widgets['colorMap'].grid_rowconfigure(5, weight = 1) 712 self.widgets['colorMap'].spinbox.config({'width' : 10,\ 713 'command' : lambda : self.changeSettings(None, 'colorMap')}) 714 715 v = interpolations.index(self.settings[self.selectedPlot]['interpolation']) 716 self.widgets['interpolation'] = ComboSpinbox(self.pFrame,\ 717 frameLabel = 'Interpolation',\ 718 default = v,\ 719 contents = tuple(interpolations)) 720 self.widgets['interpolation'].grid(row = 2, column = 0, sticky = "NEW") 721 self.widgets['interpolation'].grid_columnconfigure(0, weight = 1) 722 self.widgets['interpolation'].grid_rowconfigure(5, weight = 1) 723 self.widgets['interpolation'].spinbox.config({'width' : 10,\ 724 'command' : lambda : self.changeSettings(None, 'interpolation')}) 725 726 self.widgets['alpha'] = ComboFloatEntry(self.pFrame, frameLabel = 'Alpha', contents = self.settings[self.selectedPlot]['alpha']) 727 self.widgets['alpha'].grid(row = 3, column = 0, sticky = "NEW") 728 self.widgets['alpha'].grid_columnconfigure(0, weight = 1) 729 self.widgets['alpha'].grid_rowconfigure(0, weight = 1) 730 self.widgets['alpha'].entry.bind('<FocusOut>', lambda event : self.changeSettings(event, 'alpha'))
731
732 -class PlotNetCDFVariableDialog(Toplevel):
733 """Sets up a dialog used to plot variables present in a NetCDF file. 734 """ 735
736 - def __init__(self, parent, title = None, netcdf = None, xVar = None, yVar = None, zVar = None):
737 """The constructor. 738 739 @param parent: the parent widget. 740 741 @param title: a string specifying the title of the dialog. 742 @type title: string 743 744 @param netcdf: the name of a NetCDF file to plot (string) or an opened NetCDF trajectory file. 745 @type netcdf: a string or a Scientific.IO.NetCDF._NetCDFFile object 746 747 @param xVar: the NetCDF variable name of the X variable to plot. 748 @type xVar: string 749 750 @param yVar: the NetCDF variable name of the Y variable to plot. 751 @type yVar: 752 753 @param zVar: the NetCDF variable name of the Z variable to plot. 754 @type zVar: 755 """ 756 757 Toplevel.__init__(self, parent) 758 759 self.transient(parent) 760 761 if title: 762 self.title(title) 763 764 self.parent = parent 765 766 try: 767 if isinstance(netcdf, _NetCDFFile): 768 self.data = netcdf 769 770 elif isinstance(netcdf, Trajectory): 771 self.data = NetCDFFile(netcdf.filename, 'r') 772 773 elif isinstance(netcdf, str): 774 self.data = NetCDFFile(netcdf, 'r') 775 776 else: 777 raise 778 779 except: 780 self.data = None 781 782 self.xVar = xVar 783 self.yVar = yVar 784 self.zVar = zVar 785 786 body = Frame(self) 787 self.initial_focus = self.body(body) 788 body.grid(row = 0, column = 0, sticky = EW) 789 790 self.buttonbox() 791 792 # If a NetCDF file has been loaded in nMOLDYN then it is proposed by default for plotting. 793 if self.data is not None: 794 # The control variables are updated with the informations coming from the loaded trajectory. 795 self.fileBrowser.setValue(str(self.data)) 796 797 # The listbox storing the numerical 1D and 2D NetCDF data is filled up. 798 self.displayVariables() 799 800 if (self.xVar is not None) & (self.yVar is not None): 801 if self.zVar is not None: 802 self.plotXYZ() 803 else: 804 self.plotXY() 805 806 self.grab_set() 807 808 if not self.initial_focus: 809 self.initial_focus = self 810 811 self.protocol("WM_DELETE_WINDOW", lambda : self.cancel(self)) 812 813 self.resizable(width = NO, height = NO) 814 815 self.geometry("+%d+%d" % (parent.winfo_rootx()+50, parent.winfo_rooty()+50)) 816 817 self.initial_focus.focus_set() 818 819 self.wait_window(self)
820
821 - def body(self, master):
822 """ 823 Create dialog body. Return widget that should have initial focus. 824 """ 825 826 settingsFrame = LabelFrame(master, text = 'Settings', bd = 2, relief = GROOVE) 827 settingsFrame.grid(row = 0, column = 0, sticky = EW, padx = 3, pady = 3) 828 settingsFrame.grid_columnconfigure(0, weight = 1) 829 830 # The combo widget for the file browser. 831 self.fileBrowser = ComboFileBrowser(settingsFrame,\ 832 frameLabel = "NetCDF input file",\ 833 contents = '',\ 834 save = False,\ 835 command = self.openNetCDF) 836 self.fileBrowser.grid(row = 0, column = 0, padx = 2, pady = 2, sticky = EW) 837 self.fileBrowser.grid_columnconfigure(0, weight = 1) 838 self.fileBrowser.entry.bind('<Return>', self.openNetCDF) 839 840 # The frame that will host the different listboxes of the dialog. 841 listboxesFrame = LabelFrame(settingsFrame, text = 'Variables', bd = 2, relief = GROOVE) 842 listboxesFrame.grid(row = 1, column = 0, padx = 2, pady = 2, sticky = W) 843 844 # The combo listbox that will contain the X variables. 845 self.xVarLb = ComboListbox(listboxesFrame, 'X', []) 846 self.xVarLb.lb.config({'exportselection' : 0, 'width' : 22, 'height' : 4, 'selectmode' : SINGLE}) 847 self.xVarLb.config({'relief' : FLAT}) 848 self.xVarLb.grid(row = 0, column = 0) 849 self.xVarLb.lb.bind('<ButtonRelease-1>', self.selectXVariable) 850 851 # The combo listbox that will contain the Y variables. 852 self.yVarLb = ComboListbox(listboxesFrame, 'Y', []) 853 self.yVarLb.config({'relief' : FLAT}) 854 self.yVarLb.grid(row = 0, column = 1) 855 self.yVarLb.lb.config({'exportselection' : 0, 'width' : 22, 'height' : 4, 'selectmode' : SINGLE}) 856 857 # The combo listbox that will contain the Z variables. 858 self.zVarLb = ComboListbox(listboxesFrame, 'Z', []) 859 self.zVarLb.config({'relief' : FLAT}) 860 self.zVarLb.grid(row = 0, column = 2) 861 self.zVarLb.lb.config({'exportselection' : 0, 'width' : 22, 'height' : 4, 'selectmode' : SINGLE}) 862 863 # The frame that will host the pylab figure displaying the plot and the global settings widgets. 864 plotFrame = LabelFrame(master, text = 'Plot', bd = 2, relief = GROOVE) 865 plotFrame.grid(row = 3, column = 0, padx = 2, pady = 2, sticky = EW) 866 plotFrame.grid_columnconfigure(0, weight = 1) 867 868 # The subframe that will host the figure. 869 figureFrame = Frame(plotFrame, relief = FLAT) 870 figureFrame.grid(row = 0, column = 0, sticky = 'EW') 871 figureFrame.grid_columnconfigure(0, weight = 1) 872 873 # The figure. 874 self.figure = Figure(dpi = 72) 875 self.canvas = FigureCanvasTkAgg(self.figure, master = figureFrame) 876 877 self.canvas.get_tk_widget().pack() 878 self.canvas._tkcanvas.pack() 879 self.toolbar = NavigationToolbar2TkAgg(self.canvas, figureFrame) 880 self.toolbar.update() 881 882 return None
883
884 - def buttonbox(self):
885 """ 886 Add standard button box. 887 """ 888 889 # The frame that contains the action buttons. 890 box = LabelFrame(self, text = 'Actions', bd = 2, relief = GROOVE) 891 box.grid(row = 1, column = 0, sticky = EW, padx = 3, pady = 3) 892 box.grid_columnconfigure(0, weight = 1) 893 894 w = Button(box, text = "Cancel", width = 10, command = lambda : self.cancel(self)) 895 w.grid(row = 0, column = 0, sticky = E) 896 897 w = Button(box, text = "Settings", width = 10, command = self.openSettingsDialog) 898 w.grid(row = 0, column = 1, sticky = E) 899 900 w = Button(box, text = "Reset", width = 10, command = self.resetPlots) 901 w.grid(row = 0, column = 3, sticky = E) 902 903 w = Button(box, text = "Export plot", width = 10, command = self.exportPlotDialog) 904 w.grid(row = 0, column = 4, sticky = E) 905 906 w = Button(box, text = "OK", width = 10, command = self.ok, default = ACTIVE) 907 w.grid(row = 0, column = 5, sticky = E) 908 909 self.bind("<Return>", self.ok) 910 self.bind("<Escape>", lambda event : self.cancel(self, event))
911 912 # Standard button semantics.
913 - def ok(self, event = None):
914 915 if not self.validate(): 916 self.initial_focus.focus_set() 917 return 918 919 self.update_idletasks() 920 921 self.apply()
922
923 - def cancel(self, dialog, event = None):
924 925 dialog.parent.grab_set() 926 dialog.parent.focus_set() 927 dialog.destroy()
928 929 # Command hooks
930 - def validate(self):
931 932 if not self.xVarLb.lb.curselection(): 933 raise Error('Please select a X variable.') 934 self.xVar = self.xVarLb.lb.get(int(self.xVarLb.lb.curselection()[0])) 935 dimX = self.data.variables[self.xVar].dimensions[0] 936 937 if not self.yVarLb.lb.curselection(): 938 raise Error('Please select a Y variable.') 939 self.yVar = self.yVarLb.lb.get(int(self.yVarLb.lb.curselection()[0])) 940 dimY = self.data.variables[self.yVar].dimensions[0] 941 942 if not self.zVarLb.lb.curselection(): 943 self.zVar = None 944 945 # The variable must have the same dimension than the selected Y variable to be retained. 946 if dimX != dimY: 947 raise Error('X (dim = %d) and Y (dim = %d) do not have the same dimension.' % (dimX,dimY)) 948 949 else: 950 self.zVar = self.zVarLb.lb.get(int(self.zVarLb.lb.curselection()[0])) 951 dimZ = self.data.variables[self.zVar].dimensions 952 if (dimX != dimZ[0]) or (dimY != dimZ[1]): 953 raise Error('X (dim = %d) and Y (dim = %d) dimensions do not match Z (dim = %d) dimensions.' % (dimX,dimY,dimZ)) 954 955 return True
956
957 - def apply(self):
958 959 try: 960 if self.zVar is None: 961 self.plotXY() 962 963 else: 964 self.plotXYZ() 965 except: 966 raise Error('Error when plotting datas.')
967 968 # The class specific methods.
969 - def openSettingsDialog(self):
970 """This method will open the dialog to set up the global settings. 971 """ 972 973 if not self.figure.gca().get_lines(): 974 LogMessage('warning', 'No plot defined.', ['gui']) 975 return 976 977 g = SettingsDialog(self)
978
979 - def resetPlots(self):
980 """This method will clear up all the displayed plots. 981 """ 982 983 # The figure is cleared up. 984 self.figure.clear() 985 986 if hasattr(self.figure,'xValues'): 987 delattr(self.figure, 'xValues') 988 989 if hasattr(self.figure,'yValues'): 990 delattr(self.figure, 'yValues') 991 992 if hasattr(self.figure,'zValues'): 993 delattr(self.figure, 'zValues') 994 995 # The canvas is updated. 996 self.canvas.show()
997
998 - def exportPlotDialog(self):
999 """This method pops up a dialog from which the plotted datas can be exported to an ASCII file. 1000 """ 1001 1002 if not self.figure.gca().get_lines(): 1003 LogMessage('warning', 'No plot defined.', ['gui']) 1004 return 1005 1006 self.exportDialog = Toplevel(self) 1007 1008 self.exportDialog.parent = self 1009 1010 self.exportDialog.transient(self) 1011 1012 self.exportDialog.title('Export plot to ASCII') 1013 1014 self.exportDialog.grab_set() 1015 1016 # The frame that contains the action buttons. 1017 settingsFrame = LabelFrame(self.exportDialog, text = 'Settings', bd = 2, relief = GROOVE) 1018 settingsFrame.grid(row = 0, column = 0, sticky = EW, padx = 3, pady = 3) 1019 settingsFrame.grid_columnconfigure(0, weight = 1) 1020 1021 # Windows not resizable 1022 self.exportDialog.resizable(width = NO, height = NO) 1023 1024 self.exportDialog.geometry("+%d+%d" % (self.winfo_rootx()+50, self.winfo_rooty()+50)) 1025 1026 if self.figure.gca().get_images(): 1027 self.xIndexMinEntry = ComboIntegerEntry(settingsFrame, frameLabel = 'X Index min', contents = 1) 1028 self.xIndexMinEntry.grid(row = 0, column = 0, sticky = "EW") 1029 self.xIndexMinEntry.grid_columnconfigure(0, weight = 1) 1030 1031 self.xIndexMaxEntry = ComboIntegerEntry(settingsFrame, frameLabel = 'X Index max',\ 1032 contents = self.figure.gca().get_images()[0].get_array().shape[1]) 1033 self.xIndexMaxEntry.grid(row = 1, column = 0, sticky = "EW") 1034 self.xIndexMaxEntry.grid_columnconfigure(0, weight = 1) 1035 1036 self.yIndexMinEntry = ComboIntegerEntry(settingsFrame, frameLabel = 'Y Index min', contents = 1) 1037 self.yIndexMinEntry.grid(row = 2, column = 0, sticky = "EW") 1038 self.yIndexMinEntry.grid_columnconfigure(0, weight = 1) 1039 1040 self.yIndexMaxEntry = ComboIntegerEntry(settingsFrame, frameLabel = 'Y Index max',\ 1041 contents = self.figure.gca().get_images()[0].get_array().shape[0]) 1042 self.yIndexMaxEntry.grid(row = 3, column = 0, sticky = "EW") 1043 self.yIndexMaxEntry.grid_columnconfigure(0, weight = 1) 1044 1045 else: 1046 self.indexMinEntry = ComboIntegerEntry(settingsFrame, frameLabel = 'Index min', contents = 1) 1047 self.indexMinEntry.grid(row = 0, column = 0, sticky = "EW") 1048 self.indexMinEntry.grid_columnconfigure(0, weight = 1) 1049 1050 self.indexMaxEntry = ComboIntegerEntry(settingsFrame, frameLabel = 'Index max',\ 1051 contents = len(self.figure.gca().get_lines()[0].get_xdata())) 1052 self.indexMaxEntry.grid(row = 1, column = 0, sticky = "EW") 1053 self.indexMaxEntry.grid_columnconfigure(0, weight = 1) 1054 1055 # The filebrowser for the output ASCII file. 1056 self.exportedFileBrowser = ComboFileBrowser(settingsFrame,\ 1057 frameLabel = "ASCII output file",\ 1058 contents = '',\ 1059 save = True) 1060 self.exportedFileBrowser.grid(row = 4, column = 0, padx = 2, pady = 2, sticky = EW) 1061 self.exportedFileBrowser.grid_columnconfigure(0, weight = 1) 1062 1063 # The frame that contains the action buttons. 1064 box = LabelFrame(self.exportDialog, text = 'Actions', bd = 2, relief = GROOVE) 1065 box.grid(row = 1, column = 0, sticky = EW, padx = 3, pady = 3) 1066 box.grid_columnconfigure(0, weight = 1) 1067 1068 w = Button(box, text = "Cancel", width = 10, command = lambda : self.cancel(self.exportDialog)) 1069 w.grid(row = 0, column = 0, sticky = E) 1070 1071 w = Button(box, text = "OK", width = 10, command = self.exportPlot, default = ACTIVE) 1072 w.grid(row = 0, column = 1, sticky = E) 1073 1074 self.exportDialog.protocol("WM_DELETE_WINDOW", lambda : self.cancel(self.exportDialog)) 1075 self.exportDialog.bind("<Return>", self.exportPlot) 1076 self.exportDialog.bind("<Escape>", lambda event : self.cancel(self.exportDialog, event))
1077
1078 - def exportPlot(self, event = None):
1079 """This method exports plotted datas to an ASCII file. 1080 """ 1081 1082 filename = self.exportedFileBrowser.getValue() 1083 if not filename: 1084 LogMessage('warning', 'No output file defined.', ['gui']) 1085 return 1086 1087 if filename[-4:] != '.dat': 1088 filename += '.dat' 1089 1090 try: 1091 1092 fFmt = '%20.8e ' 1093 sFmt = '%20s ' 1094 f = open(filename, 'w') 1095 1096 if self.figure.gca().get_images(): 1097 xIndexMin = self.xIndexMinEntry.getValue() - 1 1098 xIndexMax = self.xIndexMaxEntry.getValue() 1099 1100 if xIndexMin < 0: 1101 xIndexMin = 0 1102 if xIndexMax > self.figure.gca().get_images()[0].get_array().shape[1]: 1103 xIndexMax = self.figure.gca().get_images()[0].get_array().shape[1] 1104 1105 yIndexMin = self.yIndexMinEntry.getValue() - 1 1106 yIndexMax = self.yIndexMaxEntry.getValue() 1107 if yIndexMin < 0: 1108 yIndexMin = 0 1109 yIndexMax = self.yIndexMaxEntry.getValue() 1110 if yIndexMax > self.figure.gca().get_images()[0].get_array().shape[0]: 1111 yIndexMax = self.figure.gca().get_images()[0].get_array().shape[0] 1112 1113 f.write('datas = %s\n' % self.figure.gca().get_images()[0].get_label()) 1114 f.write('1st line = %s\n' % self.figure.gca().get_images()[0].get_axes().get_ylabel()) 1115 f.write('1st column = %s\n\n' % self.figure.gca().get_images()[0].get_axes().get_xlabel()) 1116 1117 data = self.figure.gca().get_images()[0].get_array() 1118 1119 # The first line is written with the Y values. 1120 f.write(sFmt % 'NaN') 1121 for v in range(yIndexMin,yIndexMax): 1122 f.write(fFmt % self.figure.yValues[v]) 1123 f.write('\n') 1124 1125 # The 2D datas are written. 1126 for ix in range(xIndexMin,xIndexMax): 1127 f.write(fFmt % self.figure.xValues[ix]) 1128 for iy in range(yIndexMin,yIndexMax): 1129 v = self.figure.zValues[iy,ix] 1130 try: 1131 f.write(fFmt % v) 1132 except: 1133 f.write(sFmt % v) 1134 1135 f.write('\n') 1136 1137 else: 1138 indexMin = self.indexMinEntry.getValue() - 1 1139 indexMax = self.indexMaxEntry.getValue() 1140 if indexMin < 0: 1141 indexMin = 0 1142 if indexMax > len(self.figure.gca().get_lines()[0].get_xdata()): 1143 indexMax = len(self.figure.gca().get_lines()[0].get_xdata()) 1144 1145 data = [] 1146 comp = 1 1147 for p in self.figure.gca().get_lines(): 1148 f.write('columns-%d = %s\n' % (comp,p.get_axes().get_xlabel())) 1149 f.write('columns-%d = %s\n' % (comp+1,p.get_axes().get_ylabel())) 1150 data.append(list(p.get_xdata())[indexMin:indexMax]) 1151 data.append(list(p.get_ydata())[indexMin:indexMax]) 1152 comp += 2 1153 data = [[r[col] for r in data] for col in range(len(data[0]))] 1154 1155 f.write('\n') 1156 1157 for d in data: 1158 for dd in d: 1159 try: 1160 f.write(fFmt % dd) 1161 except: 1162 f.write(sFmt % dd) 1163 f.write('\n') 1164 f.close() 1165 except: 1166 raise Error('Error when exporting plotted data.') 1167 finally: 1168 self.cancel(self.exportDialog)
1169
1170 - def selectXVariable(self, event):
1171 1172 self.yVarLb.lb.selection_clear(0, END) 1173 self.zVarLb.lb.selection_clear(0, END)
1174
1175 - def displayVariables(self):
1176 """ 1177 This method display the numeric variables found in the NetCDF file into their appropriate listbox. 1178 """ 1179 1180 # The X, Y and Z variables listboxes are cleared up first. 1181 self.xVarLb.lb.delete(0, END) 1182 self.yVarLb.lb.delete(0, END) 1183 self.zVarLb.lb.delete(0, END) 1184 1185 # Loop over the variables NetCDF dictionnary items. 1186 for varName in sorted(self.data.variables.keys()): 1187 variable = self.data.variables[varName] 1188 1189 if len(variable.shape) > 2: 1190 continue 1191 1192 # If the NetCDF variable is not numeric then loop to the next one. 1193 if variable.typecode() not in [Num.Float, Num.Float0, Num.Int, Num.Int32, Num.Character]: 1194 continue 1195 1196 # If the variable is 1D then it is appended to the X and Y listboxes. 1197 if len(variable.shape) == 1: 1198 self.xVarLb.lb.insert(END, varName) 1199 self.yVarLb.lb.insert(END, varName) 1200 1201 # If the variable is 2D then it is appended to the Z listbox. 1202 elif len(variable.shape) == 2: 1203 if variable.typecode() == Num.Character: 1204 self.xVarLb.lb.insert(END, varName) 1205 self.yVarLb.lb.insert(END, varName) 1206 1207 else: 1208 self.zVarLb.lb.insert(END, varName)
1209
1210 - def openNetCDF(self, event = None):
1211 """ 1212 This method opens a NetCDF file and updates the dialog with the data read from that file. 1213 Arguments: 1214 -event: Tkinter event. 1215 """ 1216 1217 if event is not None: 1218 filename = self.fileBrowser.getValue() 1219 1220 else: 1221 # The name of the NetCDF file to load. 1222 filename = askopenfilename(parent = self,\ 1223 filetypes = [('NetCDF file','*.nc')],\ 1224 initialdir = PREFERENCES.outputfile_path) 1225 1226 # The file must exist. 1227 if filename: 1228 try: 1229 self.data = NetCDFFile(filename, 'r') 1230 1231 self.fileBrowser.setValue(filename) 1232 1233 # The X, Y and Z variables listboxes are filled up. 1234 self.displayVariables() 1235 1236 except: 1237 LogMessage('warning','The file %s could not be read.' % filename,['gui']) 1238 1239 return 'break'
1240
1241 - def plotXY(self):
1242 """ 1243 This method display a 2D plot. 1244 """ 1245 1246 if (self.xVar is None) or (self.yVar is None): 1247 return 1248 1249 if self.yVar is None: 1250 return 1251 1252 if self.figure.gca().get_images(): 1253 self.resetPlots() 1254 1255 if self.data.variables[self.xVar].typecode() == Num.Character: 1256 temp = self.data.variables[self.xVar].getValue() 1257 xValues = Num.arange(temp.shape[0]) 1258 else: 1259 xValues = self.data.variables[self.xVar].getValue() 1260 1261 if self.data.variables[self.yVar].typecode() == Num.Character: 1262 temp = self.data.variables[self.yVar].getValue() 1263 yValues = Num.arange(temp.shape[0]) 1264 else: 1265 yValues = self.data.variables[self.yVar].getValue() 1266 1267 self.figure.gca().plot(xValues, yValues, label = self.yVar + ' vs ' + self.xVar) 1268 1269 self.figure.gca().grid(True) 1270 1271 if self.data.variables[self.xVar].typecode() == Num.Character: 1272 xTicks = xValues[:] 1273 xTicksLabels = ['%s' % temp[v,:].tostring().rstrip('\x00') for v in range(len(temp))] 1274 self.figure.gca().set_xticks(xTicks) 1275 self.figure.gca().set_xticklabels(xTicksLabels) 1276 1277 if self.data.variables[self.yVar].typecode() == Num.Character: 1278 yTicks = yValues[:] 1279 yTicksLabels = ['%s' % temp[v,:].tostring().rstrip('\x00') for v in range(len(temp))] 1280 self.figure.gca().set_yticks(yTicks) 1281 self.figure.gca().set_yticklabels(yTicksLabels) 1282 1283 # Set the title. 1284 try: 1285 self.figure.get_axes()[0].set_title(self.data.title) 1286 except AttributeError: 1287 self.figure.get_axes()[0].set_title('') 1288 1289 # Sets the X-axis label. 1290 try: 1291 self.figure.get_axes()[0].set_xlabel('%s (%s)' % (self.xVar, self.data.variables[self.xVar].units)) 1292 except AttributeError: 1293 self.figure.get_axes()[0].set_xlabel(self.xVar) 1294 1295 # Sets the Y-axis label. 1296 try: 1297 self.figure.get_axes()[0].set_ylabel('%s (%s)' % (self.yVar, self.data.variables[self.yVar].units)) 1298 except AttributeError: 1299 self.figure.get_axes()[0].set_ylabel(self.yVar) 1300 1301 # Set the legend. 1302 self.figure.get_axes()[0].legend(loc = 'best') 1303 1304 self.canvas.show()
1305
1306 - def displayPlotSlices(self, event):
1307 """ 1308 This call back plot the orthogonal slices defined by the moving cursor of a 3D plot. 1309 """ 1310 1311 # The event triggering the call back must be the right mouse button. 1312 if event.button != 3: 1313 return 1314 1315 # If the event does not occur into the plot then do nothing. 1316 if event.inaxes is None: 1317 return 1318 1319 # The plot that will contain the horizontal slice. 1320 horizontalSlice = pylab.subplot(211) 1321 if self.data.variables[self.xVar].typecode() == Num.Character: 1322 temp = self.data.variables[self.xVar].getValue() 1323 xValue = Num.arange(len(temp)) 1324 xTicks = ['%s' % temp[v,:].tostring().rstrip('\x00') for v in range(len(temp))] 1325 horizontalSlice.set_xticks(range(len(xTicks))) 1326 horizontalSlice.set_xticklabels(xTicks) 1327 else: 1328 xValue = self.data.variables[self.xVar].getValue() 1329 1330 # The horizontal slice plot. 1331 horizontalSlice.plot(xValue, self.data.variables[self.zVar][:,int(event.ydata)]) 1332 1333 # Sets the X-axis label. 1334 if hasattr(self.data.variables[self.xVar], 'units'): 1335 horizontalSlice.set_xlabel('%s (%s)' % (self.xVar, self.data.variables[self.xVar].units)) 1336 else: 1337 horizontalSlice.set_xlabel('%s (Unknown unit)' % self.xVar) 1338 1339 # Sets the Y-axis label. 1340 if self.data.variables[self.yVar].typecode() == Num.Character: 1341 value = self.data.variables[self.yVar].getValue()[int(event.ydata),:].tostring() 1342 horizontalSlice.set_ylabel('%s %s = %s' % (self.zVar,self.yVar, value), fontsize = 7) 1343 else: 1344 value = self.data.variables[self.yVar].getValue()[int(event.ydata)] 1345 horizontalSlice.set_ylabel('%s %s = %.3f' % (self.zVar,self.yVar, value), fontsize = 7) 1346 1347 # The plot that will contain the vertical slice. 1348 verticalSlice = pylab.subplot(212) 1349 1350 if self.data.variables[self.yVar].typecode() == Num.Character: 1351 temp = self.data.variables[self.yVar].getValue() 1352 xValue = Num.arange(len(temp)) 1353 xTicks = ['%s' % temp[v,:].tostring().rstrip('\x00') for v in range(len(temp))] 1354 verticalSlice.set_xticks(range(len(xTicks))) 1355 verticalSlice.set_xticklabels(xTicks) 1356 else: 1357 xValue = self.data.variables[self.yVar].getValue() 1358 1359 # The vertical slice plot. 1360 verticalSlice.plot(xValue, self.data.variables[self.zVar][int(event.xdata),:]) 1361 # The x label of the horizontal slice plot. 1362 verticalSlice.set_xlabel(self.yVar) 1363 if self.data.variables[self.xVar].typecode() == Num.Character: 1364 value = self.data.variables[self.xVar].getValue()[int(event.xdata),:].tostring() 1365 verticalSlice.set_ylabel('%s %s = %s' % (self.zVar,self.xVar, value), fontsize = 7) 1366 else: 1367 value = self.data.variables[self.xVar].getValue()[int(event.xdata)] 1368 verticalSlice.set_ylabel('%s %s = %.3f' % (self.zVar,self.xVar, value), fontsize = 7) 1369 1370 pylab.show()
1371
1372 - def plotXYZ(self):
1373 """ 1374 This method display a 2D plot. 1375 """ 1376 1377 if (self.xVar is None) or (self.yVar is None) or (self.zVar is None): 1378 return 1379 1380 self.resetPlots() 1381 1382 xValues = self.data.variables[self.xVar].getValue() 1383 yValues = self.data.variables[self.yVar].getValue() 1384 zValues = pylab.transpose(self.data.variables[self.zVar].getValue()) 1385 1386 self.figure.gca().imshow(zValues, aspect = 'auto', label = self.zVar + ' vs ' + self.xVar + ' and ' + self.yVar) 1387 self.figure.xValues = xValues 1388 self.figure.yValues = yValues 1389 self.figure.zValues = zValues 1390 1391 # The image colorbar. 1392 self.figure.colorbar(self.figure.gca().get_images()[0]) 1393 1394 # Creation of a cursor to plot orthogonal slices of the 3D plot. 1395 cursor = Cursor(self.figure.gca(), useblit = True, color ='red', linewidth = 1) 1396 cursor.ax.set_xlim((0, zValues.shape[1]-1)) 1397 cursor.ax.set_ylim((0, zValues.shape[0]-1)) 1398 1399 if self.data.variables[self.xVar].typecode() == Num.Character: 1400 self.figure.gca().set_xticks(range(len(xValues))) 1401 xTickLabels = ['%s' % xValues[v,:].tostring().rstrip('\x00') for v in range(len(xValues))] 1402 self.figure.gca().set_xticklabels(xTickLabels) 1403 else: 1404 xStep = len(xValues)/10 1405 if xStep < 1: 1406 xStep = 1 1407 self.figure.gca().set_xticks(range(0, len(xValues), xStep)) 1408 self.figure.gca().set_xticklabels(['%.3f' % xValues[v] for v in range(0, len(xValues), xStep)]) 1409 1410 if self.data.variables[self.yVar].typecode() == Num.Character: 1411 self.figure.gca().set_yticks(range(len(yValues))) 1412 yTickLabels = ['%s' % yValues[v,:].tostring().rstrip('\x00') for v in range(len(yValues))] 1413 self.figure.gca().set_yticklabels(yTickLabels) 1414 else: 1415 yStep = len(yValues)/10 1416 if yStep < 1: 1417 yStep = 1 1418 self.figure.gca().set_yticks(range(0, len(yValues), yStep)) 1419 self.figure.gca().set_yticklabels(['%.3f' % yValues[v] for v in range(0, len(yValues), yStep)]) 1420 1421 # Set the title. 1422 try: 1423 self.figure.gca().set_title(self.data.title) 1424 1425 except AttributeError: 1426 self.figure.gca().set_title('') 1427 1428 # Sets the X-axis label. 1429 try: 1430 self.figure.gca().set_xlabel('%s (%s)' % (self.xVar, self.data.variables[self.xVar].units)) 1431 1432 except AttributeError: 1433 self.figure.gca().set_xlabel(self.xVar) 1434 1435 # Sets the Y-axis label. 1436 try: 1437 self.figure.gca().set_ylabel('%s (%s)' % (self.yVar, self.data.variables[self.yVar].units)) 1438 except AttributeError: 1439 self.figure.gca().set_ylabel(self.yVar) 1440 1441 # Bind the plot to the callback |self.displayPlotSlices|. 1442 self.canvas.mpl_connect('button_press_event', self.displayPlotSlices) 1443 1444 self.canvas.show()
1445