Version retrival fixes for the About Dialogs
[pyplotsuite.git] / pyplotsuite / plotfile2.py
blob7d713a790c27fc508e11253ba2298b1bc1640de0
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
4 # PlotFile2 -- A tool to make quick plots from data series.
5 # Version: 0.1-alpha (see README)
7 # Copyright (C) 2007 Antonio Ingargiola <tritemio@gmail.com>
9 # This program is free software; you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 2 of the License, or
12 # (at your option) any later version.
14 import sys
15 import os.path
16 import imp
17 rootdir = os.path.abspath(imp.find_module('pyplotsuite')[1]) + '/'
18 sourcedir = rootdir + 'plotfile/'
20 import gtk
21 from matplotlib.lines import Line2D
22 from common.gtk_generic_windows import \
23 GenericMainPlotWindow, DialogWindowWithCancel,\
24 GenericOpenFileDialog, GenericSecondaryWindow
25 from common.filedata import xyLabelFromFile
26 from common.version import read_version
27 from numpy import arange, array, min
29 # XML GUI Description file
30 gladefile = sourcedir + 'plotfile2.glade'
32 # Minimum default axis value in log scale when the original value was <= 0
33 LOGMIN = 1e-3
35 # How many centimeter is an inch
36 CM_PER_INCHES = 2.54
38 class DataSet:
39 """An object describing data series with a shared X axis."""
40 def __init__(self, x=None, y1=None, name=None):
41 # self.x is the X axis shared for all y series
42 self.x = x
43 self.len = len(x)
44 self.name = name
46 # self.y is a list of series of data
47 self.y = []
48 if y1 != None: self.add(y1)
50 # self.yline is a list of plotted lines from the current DataSet
51 self.yline = []
53 # Set the plot style, maker and linestyle attributes
54 # Marker and linestyle are separate variables so we can switch them off
55 # and then recover the style information when we turn them on
56 self.marker = '.'
57 self.linestyle = '-'
59 def add(self, yi):
60 if len(yi) != self.len:
61 raise IndexError, 'Y data length (%d) must be == len(x) (%d)'\
62 % (len(yi), self.len)
63 else:
64 self.y.append(yi)
66 class AxesProperty:
67 """Simple struct to store any properties that has different values for X
68 and Y axes"""
69 x = None
70 y = None
73 # Main window class
75 class PlotFileApp(GenericMainPlotWindow):
76 """
77 This class implements an interactive plot windows with various options.
78 """
79 def __init__(self, x=None, y=None, title='Title', debug=False):
80 GenericMainPlotWindow.__init__(self, 'PlotFileWindow', gladefile)
82 self.set_defaults()
83 self.title = title
84 self.debug = debug
85 self.negative = False
87 self.setup_gui_widgets()
89 # Data: self.data is a list of DataSet() instances
90 if x != None:
91 self.data.append( DataSet(x, y, 'Plot 1') )
92 if min(y) <= 0:
93 self.negative = True
95 # Try to load the file passed as parameter
96 if x == None and y == None:
97 try:
98 self.load(sys.argv[1])
99 except:
100 pass
101 self.plot()
103 self.open_file_dialog = OpenFileDialog(self)
105 def set_defaults(self):
106 # Clear data
107 self.data = []
109 # Plot Defaults
110 self.title = 'Title'
111 self.xlabel = 'X Axis'
112 self.ylabel = 'Y Axis'
113 self.xscale = 'linear'
114 self.yscale = 'linear'
115 self.showPoints = True
116 self.showLines = True
117 self.grid = True
119 # Reset ranges
120 self.xmin, self.xmax, self.ymin, self.ymax = None, None, None, None
121 self.axes_limits = AxesProperty()
122 self.axes_limits.x = dict(linear=None, log=None)
123 self.axes_limits.y = dict(linear=None, log=None)
125 def reset_scale_buttons(self):
126 self.setup = True
127 if self.xscale == 'log':
128 self.xscaleCheckB.set_active(True)
129 else:
130 self.xscaleCheckB.set_active(False)
131 if self.yscale == 'log':
132 self.yscaleCheckB.set_active(True)
133 else:
134 self.yscaleCheckB.set_active(False)
135 self.setup = False
137 def setup_gui_widgets(self):
138 # Create the text entry handler
139 self.xminEntry = self.widgetTree.get_widget('xmin_entry')
140 self.xmaxEntry = self.widgetTree.get_widget('xmax_entry')
141 self.yminEntry = self.widgetTree.get_widget('ymin_entry')
142 self.ymaxEntry = self.widgetTree.get_widget('ymax_entry')
144 # Initialize the check buttons to the correct value
145 self.pointsCheckB = self.widgetTree.get_widget('points_chk_butt')
146 self.linesCheckB = self.widgetTree.get_widget('lines_chk_butt')
147 self.xscaleCheckB = self.widgetTree.get_widget('xlog_chk_butt')
148 self.yscaleCheckB = self.widgetTree.get_widget('ylog_chk_butt')
149 self.reset_scale_buttons()
151 self.cooPickerCheckB = self.widgetTree.get_widget('coordinatePicker')
152 self.moreGridCheckB = self.widgetTree.get_widget('moreGrid')
154 self.window.show_all()
155 if self.debug: print 'end of setup_gui_widgets()'
157 def is_ydata_positive(self):
158 for d in self.data:
159 for yi in d.y:
160 if (yi <= 0).any(): return False
161 return True
163 def plot_data(self, n=0):
164 """Plot the n-th data from the self.data list of DataSet()."""
166 if self.debug: print 'plot_data method'
168 d = self.data[n]
169 d.yline = range(len(d.y))
170 for i, yi in enumerate(d.y):
171 d.yline[i], = self.axis.plot(d.x, yi, ls=d.linestyle,
172 marker=d.marker)
174 self.axis.set_title(self.title)
175 self.axis.set_xlabel(self.xlabel)
176 self.axis.set_ylabel(self.ylabel)
178 self.set_xlim()
179 self.set_ylim()
180 self.canvas.draw()
182 #self.update_axis_limits_entry()
184 def update_axis_limits_entry(self):
186 xmin, xmax = self.axis.get_xlim()
187 self.xminEntry.set_text(str(xmin))
188 self.xmaxEntry.set_text(str(xmax))
190 ymin, ymax = self.axis.get_ylim()
191 self.yminEntry.set_text(str(ymin))
192 self.ymaxEntry.set_text(str(ymax))
195 def plot(self):
196 if self.debug: print 'plot method'
198 if self.yscale == 'log' and not self.is_ydata_positive():
199 self.writeStatusBar('WARNING: Negative Y values in log scale.')
201 self.axis.clear()
203 self.axis.set_yscale('linear')
204 self.axis.set_xscale('linear')
206 for d in self.data:
207 d.yline = range(len(d.y))
208 for i, yi in enumerate(d.y):
209 d.yline[i], = self.axis.plot(d.x, yi, ls=d.linestyle,
210 marker=d.marker)
212 self.axis.set_title(self.title)
213 self.axis.set_xlabel(self.xlabel)
214 self.axis.set_ylabel(self.ylabel)
215 self.axis.grid(self.grid)
217 print 'x', self.xscale, 'y', self.yscale
218 self.axis.set_yscale(self.yscale)
219 self.axis.set_xscale(self.xscale)
221 if len(self.data) > 0:
222 self.set_xlim()
223 if len(self.data[0].y) > 0:
224 self.set_ylim()
226 self.canvas.draw()
228 def set_xlim(self):
229 if self.axes_limits.x[self.xscale] == None:
230 if self.debug: print 'autoscaling...'
231 self.axis.autoscale_view(scalex=True, scaley=False)
232 self.xmin, self.xmax = self.axis.get_xlim()
233 else:
234 if self.debug: print 'using old axis limit', self.axes_limits.x
235 self.xmin, self.xmax = self.axes_limits.x[self.xscale]
236 if self.xscale == 'log':
237 if self.xmin <= 0: self.xmin = LOGMIN
238 if self.xmax <= self.xmin: self.xmax = self.xmin+1
239 self.axis.set_xlim(xmin=self.xmin, xmax=self.xmax)
241 if self.debug: print 'xmin:', self.xmin, 'xmax:', self.xmax
242 self.xminEntry.set_text(str(self.xmin))
243 self.xmaxEntry.set_text(str(self.xmax))
245 def set_ylim(self):
246 if self.axes_limits.y[self.yscale] == None:
247 if self.debug: print 'autoscaling...'
248 self.axis.autoscale_view(scaley=True, scalex=False)
249 self.ymin, self.ymax = self.axis.get_ylim()
250 else:
251 if self.debug: print 'using old axis limit'
252 self.ymin, self.ymax = self.axes_limits.y[self.yscale]
253 if self.yscale == 'log':
254 if self.ymin <= 0: self.ymin = LOGMIN
255 if self.ymax <= self.ymin: self.ymax = self.ymin+1
256 self.axis.set_ylim(ymin=self.ymin, ymax=self.ymax)
258 if self.debug: print 'ymin:', self.ymin, 'ymax:', self.ymax
259 self.yminEntry.set_text(str(self.ymin))
260 self.ymaxEntry.set_text(str(self.ymax))
262 def load(self, filename):
263 try:
264 x, y , xlab, ylab = xyLabelFromFile(filename)
265 except IOError:
266 self.writeStatusBar("Can't open file '%s'" % filename)
267 return False
268 except:
269 self.writeStatusBar("File '%s': file format unknown." % filename)
270 return False
271 else:
272 filename = os.path.basename(filename)
273 self.data.append(DataSet(x,y, filename))
274 self.title = filename
275 if xlab is not None: self.xlabel = xlab
276 if ylab is not None: self.ylabel = ylab
277 self.axes_limits.x = dict(linear=None, log=None)
278 self.axes_limits.y = dict(linear=None, log=None)
279 self.writeStatusBar("File '%s' loaded." % filename)
280 if y.min() <= 0:
281 self.negative = True
282 return True
284 def warn(self, msg):
285 self.writeStatusBar('Warning: '+msg)
288 # The following are GUI callback methods
290 def on_xscale_toggled(self, widget, *args):
291 if not self.setup:
292 self.axes_limits.x[self.xscale] = self.axis.get_xlim()
293 if self.xscaleCheckB.get_active(): self.xscale = 'log'
294 else: self.xscale = 'linear'
295 if self.debug: print "XScale:", self.xscale
296 self.axis.set_xscale(self.xscale)
297 self.set_xlim()
298 self.canvas.draw()
299 self.writeStatusBar('X Axis Scale: %s.' % self.xscale)
302 def on_yscale_toggled(self, widget, *args):
303 if not self.setup:
304 self.axes_limits.y[self.yscale] = self.axis.get_ylim()
305 if self.yscaleCheckB.get_active(): self.yscale = 'log'
306 else: self.yscale = 'linear'
307 if self.debug: print "YScale:", self.yscale
308 self.axis.set_yscale(self.yscale)
309 self.set_ylim()
310 self.canvas.draw()
312 if self.negative and self.yscale == 'log':
313 self.warn('Negative values not displayed in log-scale, lines '+\
314 'may appear discontinuos!')
315 else:
316 self.writeStatusBar('Y Axis Scale: %s.' % self.yscale)
319 def on_points_toggled(self, widget, *args):
320 self.showPoints = not self.showPoints
321 if self.debug: print "Show Points:", self.showPoints
322 for d in self.data:
323 if self.showPoints:
324 # Restore the previous marker style
325 d.yline[0].set_marker(d.marker)
326 else:
327 # Turn off the marker visualization
328 d.yline[0].set_marker('')
329 self.canvas.draw()
331 def on_lines_toggled(self, widget, *args):
332 self.showLines = not self.showLines
333 if self.debug: print "Show Lines:", self.showLines
334 for d in self.data:
335 if self.showLines:
336 # Restore the previous linestyle
337 d.yline[0].set_linestyle(d.linestyle)
338 else:
339 # Turn off the line visualization
340 d.yline[0].set_linestyle('')
341 self.canvas.draw()
343 def on_grid_toggled(self, widget, *args):
344 self.grid = not self.grid
345 if self.debug: print "Show Grid:", self.grid
346 self.axis.grid(self.grid)
347 self.canvas.draw()
349 def on_xmin_entry_activate(self, widget, *args):
350 if self.debug: print 'X Min Entry Activated'
351 s = self.xminEntry.get_text()
352 try:
353 val = float(s)
354 except ValueError:
355 self.statusBar.push(self.context, 'Wrong X axis min limit.')
356 self.xminEntry.set_text('')
357 else:
358 if self.xscale == 'log' and val <= 0:
359 val = LOGMIN
360 self.warn('Only values > 0 are allowed in log scale.')
361 self.xminEntry.set_text(str(val))
362 self.xmin = val
363 self.axis.set_xlim(xmin=val)
364 self.canvas.draw()
366 def on_xmax_entry_activate(self, widget, *args):
367 if self.debug: print 'X Max Entry Activated'
368 s = self.xmaxEntry.get_text()
369 try:
370 val = float(s)
371 except ValueError:
372 self.statusBar.push(self.context, 'Wrong X axis max limit.')
373 self.xmaxEntry.set_text('')
374 else:
375 if self.xscale == 'log' and val <= 0:
376 val = self.xmin*10.0
377 self.warn('Only values > 0 are allowed in log scale.')
378 self.xmaxEntry.set_text(str(val))
379 self.xmax = val
380 self.axis.set_xlim(xmax=val)
381 self.canvas.draw()
383 def on_ymin_entry_activate(self, widget, *args):
384 if self.debug: print 'Y Min Entry Activated'
385 s = self.yminEntry.get_text()
386 try:
387 val = float(s)
388 except ValueError:
389 self.statusBar.push(self.context, 'Wrong Y axis min limit.')
390 self.yminEntry.set_text('')
391 else:
392 if self.yscale == 'log' and val <= 0:
393 val = LOGMIN
394 self.warn('Only values > 0 are allowed in log scale.')
395 self.yminEntry.set_text(str(val))
396 self.ymin = val
397 self.axis.set_ylim(ymin=val)
398 self.canvas.draw()
400 def on_ymax_entry_activate(self, widget, *args):
401 if self.debug: print 'Y Max Entry Activated'
402 s = self.ymaxEntry.get_text()
403 try:
404 val = float(s)
405 except ValueError:
406 self.statusBar.push(self.context, 'Wrong Y axis max limit.')
407 self.ymaxEntry.set_text('')
408 else:
409 if self.yscale == 'log' and val <= 0:
410 val = self.ymin*10.0
411 self.warn('Only values > 0 are allowed in log scale.')
412 self.ymaxEntry.set_text(str(val))
413 self.ymax = val
414 self.axis.set_ylim(ymax=val)
415 self.canvas.draw()
417 def on_apply_button_clicked(self, widget, *args):
418 sxmin = self.xminEntry.get_text()
419 sxmax = self.xmaxEntry.get_text()
420 symin = self.yminEntry.get_text()
421 symax = self.ymaxEntry.get_text()
422 try:
423 xmin_val = float(sxmin)
424 xmax_val = float(sxmax)
425 ymin_val = float(symin)
426 ymax_val = float(symax)
427 except ValueError:
428 self.statusBar.push(self.context, 'Wrong axis limit')
429 else:
430 if self.xscale == 'log':
431 if xmin_val <= 0: xmin_val = LOGMIN
432 if xmax_val <= 0: xmax_val = xmin_val*10
433 if ymin_val <= 0: ymin_val = LOGMIN
434 if ymax_val <= 0: ymax_val = ymin_val*10
435 self.xmin, self.xmax, self.ymin, self.ymax = \
436 xmin_val, xmax_val, ymin_val, ymax_val
437 self.axis.set_xlim(xmin=xmin_val)
438 self.axis.set_xlim(xmax=xmax_val)
439 self.axis.set_ylim(ymin=ymin_val)
440 self.axis.set_ylim(ymax=ymax_val)
441 self.canvas.draw()
444 # The following are MENU callback methods
447 ## Actions
448 def on_addDataSet_activate(self, widget, *args):
449 self.open_file_dialog.window.show()
450 def on_new_activate(self, widget, *args):
451 self.set_defaults()
452 self.reset_scale_buttons()
453 self.plot()
455 ## Tools
456 def on_autoscale_activate(self, widget, *args):
457 self.axis.autoscale_view()
458 self.canvas.draw()
459 def on_coordinatePicker_activate(self, widget, *args):
460 if self.cooPickerCheckB.get_active():
461 self.cid = self.canvas.mpl_connect('button_press_event',
462 get_coordinates_cb)
463 self.writeStatusBar('Click on the plot to log coordinates on '+\
464 'the terminal.')
465 elif self.cid != None:
466 self.canvas.mpl_disconnect(self.cid)
467 self.writeStatusBar('Coordinate picker disabled.')
468 else:
469 print "Error: tried to disconnect an unexistent event."
470 def on_moreGrid_activate(self, widget, *args):
471 if self.moreGridCheckB.get_active():
472 self.axis.xaxis.grid(True, which='minor', ls='--', alpha=0.5)
473 self.axis.yaxis.grid(True, which='minor', ls='--', alpha=0.5)
474 self.axis.xaxis.grid(True, which='major', ls='-', alpha=0.5)
475 self.axis.yaxis.grid(True, which='major', ls='-', alpha=0.5)
476 else:
477 self.axis.xaxis.grid(False, which='minor')
478 self.axis.yaxis.grid(False, which='minor')
479 self.axis.xaxis.grid(True, which='major', ls=':')
480 self.axis.yaxis.grid(True, which='major', ls=':')
481 self.canvas.draw()
483 ## Dialogs
484 def on_SizeAndResolution_activate(self, widget, *args):
485 DimentionAndResolution(self)
486 def on_plot_properties_activate(self, widget, *args):
487 PlotPropertiesDialog(self)
488 def on_makeInterpolation_activate(self, widget, *args):
489 InterpolationDialog(self)
490 def on_title_and_axes_labels_activate(self, widget, *args):
491 TitleAndAxesWindow(self)
492 def on_info_activate(self, widget, *args):
493 AboutDialog()
496 def get_coordinates_cb(event):
498 Callback for the coordinate picker tool. This function is not a class
499 method because I don't know how to connect an MPL event to a method instead
500 of a function.
502 if not event.inaxes: return
503 print "%3.4f\t%3.4f" % (event.xdata, event.ydata)
506 # Abstract dialogs classes
508 class DialogWithPlotList(DialogWindowWithCancel):
509 """Abstract class for dialogs with a list of current plots in them."""
511 def __init__(self, dialogName, gladefile, callerApp):
512 DialogWindowWithCancel.__init__(self, dialogName, gladefile, callerApp)
514 self.treeView = self.widgetTree.get_widget('treeview')
515 self.create_plotlist()
517 def create_plotlist(self):
518 # Add a column to the treeView
519 self.addListColumn('Plot List', 0)
521 # Create the listStore Model to use with the treeView
522 self.plotList = gtk.ListStore(str)
524 # Populate the list
525 self.insertPlotList()
527 # Attatch the model to the treeView
528 self.treeView.set_model(self.plotList)
530 def addListColumn(self, title, columnId):
531 """This function adds a column to the list view.
532 First it create the gtk.TreeViewColumn and then set
533 some needed properties"""
535 column = gtk.TreeViewColumn(title, gtk.CellRendererText(), text=0)
536 column.set_resizable(True)
537 column.set_sort_column_id(columnId)
538 self.treeView.append_column(column)
540 def insertPlotList(self):
541 for data in self.callerApp.data:
542 self.plotList.append([data.name])
544 def on_applyButton_clicked(self, widget, *args):
545 self.window.destroy()
547 def on_cancelButton_clicked(self, widget, *args):
548 self.window.destroy()
550 def on_okButton_clicked(self, widget, *args):
551 self.window.destroy()
554 # Dialogs classes
556 class InterpolationDialog(DialogWithPlotList):
557 def __init__(self, callerApp):
558 DialogWithPlotList.__init__(self, 'InterpolationDialog',
559 gladefile, callerApp)
560 # To be implemented ...
563 class PlotPropertiesDialog(DialogWithPlotList):
565 colors = 'bgrcmyk'
567 line_styles = ['-', '--', ':', '-.']
568 line_stylesd = {'Continuous': '-', 'Dashed': '--', 'Dotted': ':',
569 'Dot-Line': '-.'}
571 markers = 'os^v<>.+xdDhHp'
573 def __init__(self, callerApp):
574 DialogWithPlotList.__init__(self, 'PlotPropertiesDialog',
575 gladefile, callerApp)
577 if not self.callerApp.linesCheckB.get_active():
578 self.callerApp.linesCheckB.set_active(True)
580 if not self.callerApp.pointsCheckB.get_active():
581 self.callerApp.pointsCheckB.set_active(True)
583 self.load_widgets()
585 # Retrive the data list
586 self.data = self.callerApp.data
588 # Save all the lines properties in case of Cancell-button
589 self.orig_lines = range(len(self.data))
590 for i,d in enumerate(self.data):
591 self.orig_lines[i] = [Line2D([0], [0]), d.linestyle, d.marker]
592 self.orig_lines[i][0].update_from(d.yline[0])
594 self.selected_data = None
595 self.selected_line = None
596 self.allowReplot = False
598 def load_widgets(self):
599 self.lineWidthSpinButt = \
600 self.widgetTree.get_widget('lineWidthSpinButton')
601 self.lineStyleComboB = \
602 self.widgetTree.get_widget('lineStyleComboBox')
603 self.colorComboB = \
604 self.widgetTree.get_widget('lineColorComboBox')
605 self.markerComboB = \
606 self.widgetTree.get_widget('markerTypeComboBox')
607 self.markerSizeSpinButt = \
608 self.widgetTree.get_widget('markerSizeSpinButton')
609 self.markerEdgeColorComboB = \
610 self.widgetTree.get_widget('markerEdgeColComboBox')
611 self.markerFaceColorComboB = \
612 self.widgetTree.get_widget('markerFaceColComboBox')
613 self.markerEdgeWidthSpinButt = \
614 self.widgetTree.get_widget('markerEdgeWidthSpinButton')
616 def update_properties(self):
617 selected_line = self.selected_line
619 # Set the Spin Buttons with the values for the selected data
620 self.lineWidthSpinButt.set_value(selected_line.get_linewidth())
621 self.markerSizeSpinButt.set_value(selected_line.get_markersize())
622 mew = selected_line.get_markeredgewidth()
623 self.markerEdgeWidthSpinButt.set_value(mew)
625 # Set the Combo Boxes with the values for the selected data
626 self.set_combobox(self.lineStyleComboB, selected_line.get_linestyle,
627 self.line_styles)
628 self.set_combobox(self.colorComboB, selected_line.get_color,
629 self.colors)
630 self.set_combobox(self.markerComboB, selected_line.get_marker,
631 self.markers)
632 self.set_combobox(self.markerEdgeColorComboB, selected_line.get_mec,
633 self.colors)
634 self.set_combobox(self.markerFaceColorComboB, selected_line.get_mfc,
635 self.colors)
637 def set_combobox(self, cbox, retrive_fun, choses):
638 value = retrive_fun()
639 print choses, value
641 if value in choses:
642 i = choses.index(value)
643 cbox.set_active(i)
644 else:
645 print "WARNING: Unsupported value '%s'." % value
648 def set_line_prop_sbut(self, prop):
649 value = getattr(self, prop+'SpinButt').get_value()
650 self.set_line_prop(prop, value)
652 def set_line_prop_cbox(self, prop, choses=None):
654 text = getattr(self, prop+'ComboB').get_active_text()
656 if choses == None:
657 value = text[text.find('(') + 1]
658 elif text in choses.keys():
659 value = choses[text]
660 else:
661 print "WARNING: Unsupported value '%s'." % value
663 self.set_line_prop(prop, value)
665 def set_line_prop(self, prop, value):
666 if not self.allowReplot or self.selected_data is None: return
668 set_fun = getattr(self.selected_line, 'set_'+prop.lower())
669 set_fun(value)
670 self.callerApp.canvas.draw()
674 # GUI Callbacks
676 def on_treeview_cursor_changed(self, *args):
677 # Retrive the current plot/line reference
678 plot_index = self.treeView.get_cursor()[0][0]
679 self.selected_line = self.data[plot_index].yline[0]
680 self.selected_data = self.callerApp.data[plot_index]
682 # Update the plot with the current line/plot properties
683 self.allowReplot = False
684 self.update_properties()
685 self.allowReplot = True
687 def on_lineWidth_value_changed(self, *args):
688 self.set_line_prop_sbut('lineWidth')
690 def on_lineStyle_changed(self, *args):
691 self.set_line_prop_cbox('lineStyle', choses=self.line_stylesd)
693 def on_lineColor_changed(self, *args):
694 self.set_line_prop_cbox('color')
696 def on_markerType_changed(self, *args):
697 self.set_line_prop_cbox('marker')
699 def on_markerSize_value_changed(self, *args):
700 self.set_line_prop_sbut('markerSize')
702 def on_markerEdgeWidth_value_changed(self, *args):
703 self.set_line_prop_sbut('markerEdgeWidth')
705 def on_markerEdgeColor_changed(self, *args):
706 self.set_line_prop_cbox('markerEdgeColor')
708 def on_markerFaceColor_changed(self, *args):
709 self.set_line_prop_cbox('markerFaceColor')
712 def on_cancelButton_clicked(self, widget, *args):
713 # Restore the old style
714 for orig_line, d in zip(self.orig_lines, self.data):
715 d.yline[0].update_from(orig_line[0])
716 d.linestyle = orig_line[1]
717 d.marker = orig_line[2]
719 self.callerApp.canvas.draw()
720 self.window.destroy()
722 def on_okButton_clicked(self, widget, *args):
723 self.window.destroy()
726 class TitleAndAxesWindow(DialogWindowWithCancel):
728 Dialog for setting Title and axes labels.
730 def __init__(self, callerApp):
731 DialogWindowWithCancel.__init__(self, 'TitleAndAxesWindow', gladefile,
732 callerApp)
734 self.titleEntry = self.widgetTree.get_widget('titleEntry')
735 self.xlabelEntry = self.widgetTree.get_widget('xlabelEntry')
736 self.ylabelEntry = self.widgetTree.get_widget('ylabelEntry')
738 # Update the entries with the current values
739 def sync(field, entry):
740 if field != None: entry.set_text(field)
742 sync(self.callerApp.title, self.titleEntry)
743 sync(self.callerApp.xlabel, self.xlabelEntry)
744 sync(self.callerApp.ylabel, self.ylabelEntry)
746 def on_okButton_clicked(self, widget, *args):
747 print "OK Clicked"
748 self.callerApp.axis.set_title(self.titleEntry.get_text())
749 self.callerApp.axis.set_xlabel(self.xlabelEntry.get_text())
750 self.callerApp.axis.set_ylabel(self.ylabelEntry.get_text())
751 self.callerApp.canvas.draw()
753 self.callerApp.title = self.titleEntry.get_text()
754 self.callerApp.xlabel = self.ylabelEntry.get_text()
755 self.callerApp.ylabel = self.xlabelEntry.get_text()
757 self.window.destroy()
759 class DimentionAndResolution(DialogWindowWithCancel):
761 Dialog for setting Figure dimentions and resolution.
763 def __init__(self, callerApp):
764 DialogWindowWithCancel.__init__(self, 'DimentionsDialog', gladefile,
765 callerApp)
766 self.xdimSpinButton = self.widgetTree.get_widget('xdimSpinButton')
767 self.ydimSpinButton = self.widgetTree.get_widget('ydimSpinButton')
768 self.resolutionSpinButton = self.widgetTree.get_widget(
769 'resolutionSpinButton')
770 self.inchesRadioB = self.widgetTree.get_widget('inRadioButton')
772 self.xdim_o, self.ydim_o = self.callerApp.figure.get_size_inches()
773 self.dpi_o = self.callerApp.figure.get_dpi()
775 self.set_initial_values()
777 def set_values(self, xdim, ydim, dpi):
778 if not self.inchesRadioB.get_active():
779 xdim *= CM_PER_INCHES
780 ydim *= CM_PER_INCHES
781 self.xdimSpinButton.set_value(xdim)
782 self.ydimSpinButton.set_value(ydim)
783 self.resolutionSpinButton.set_value(dpi)
785 def set_initial_values(self):
786 self.set_values(self.xdim_o, self.ydim_o, self.dpi_o)
788 def set_default_values(self):
789 xdim, ydim = rcParams['figure.figsize']
790 dpi = rcParams['figure.dpi']
791 self.set_values(xdim, ydim, dpi)
793 def get_values(self):
794 self.xdim = self.xdimSpinButton.get_value()
795 self.ydim = self.ydimSpinButton.get_value()
796 self.resolution = self.resolutionSpinButton.get_value()
797 if not self.inchesRadioB.get_active():
798 self.xdim /= CM_PER_INCHES
799 self.ydim /= CM_PER_INCHES
801 def set_figsize(self):
802 self.callerApp.figure.set_size_inches(self.xdim, self.ydim)
803 self.callerApp.figure.set_dpi(self.resolution)
805 def on_unity_toggled(self, widget, *args):
806 xdim = self.xdimSpinButton.get_value()
807 ydim = self.ydimSpinButton.get_value()
808 if self.inchesRadioB.get_active():
809 xdim /= CM_PER_INCHES
810 ydim /= CM_PER_INCHES
811 else:
812 xdim *= CM_PER_INCHES
813 ydim *= CM_PER_INCHES
814 self.xdimSpinButton.set_value(xdim)
815 self.ydimSpinButton.set_value(ydim)
817 def on_okButton_clicked(self, widget, *args):
818 print "OK"
819 self.get_values()
820 self.set_figsize()
821 self.callerApp.canvas.draw()
822 self.window.destroy()
824 def on_restoreButton_clicked(self, widget, *args):
825 self.set_default_values()
828 class OpenFileDialog(GenericOpenFileDialog):
830 This class implements the "Open File" dialog.
832 def __init__(self, callerApp):
833 GenericOpenFileDialog.__init__(self, 'OpenFileDialog', gladefile,
834 callerApp)
835 self.window.hide()
837 def openSelectedFile(self):
838 loaded = self.callerApp.load( self.filename )
839 if loaded:
840 self.callerApp.plot_data(-1)
841 self.window.hide()
843 def on_cancelButton_clicked(self, widget, *args):
844 self.window.hide()
845 return True
849 class AboutDialog(GenericSecondaryWindow):
851 Object for the "About Dialog".
853 def __init__(self):
854 GenericSecondaryWindow.__init__(self, 'AboutDialog', gladefile)
855 self.window.set_version(read_version(rootdir))
858 # Functions
860 def test():
861 x = arange(100)
862 y = sin(x/10.0)
863 p = PlotFileApp(x, y, title='Random Sequence', debug=True)
864 p.start()
866 def main():
867 p = PlotFileApp(debug=True)
868 # Try to open a sample file
869 if len(sys.argv) < 2 and os.path.isfile(sourcedir+'samples/data.txt'):
870 p.load(sourcedir+'samples/data.txt')
871 p.plot()
872 p.start()
874 if __name__ == '__main__': main()