P: More color support: markeredgecolor and makerfacecolor.
[pyplotsuite.git] / plotfile2.py
blobb59d96b6ee31589f6414823e669199a21227d98f
1 #!/usr/bin/env python
2 # -*- coding: UTF8 -*-
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 rootdir = sys.path[0] + '/'
16 sourcedir = rootdir + 'plotfile/'
18 import os.path
19 import gtk
20 from matplotlib.lines import Line2D
21 from common.gtk_generic_windows import \
22 GenericMainPlotWindow, DialogWindowWithCancel,\
23 GenericOpenFileDialog, GenericSecondaryWindow
24 from common.plotfile import xyfromfile
25 from numpy import arange, array
27 # XML GUI Description file
28 gladefile = sourcedir + 'plotfile2.glade'
30 # Minimum default axis value in log scale when the original value was <= 0
31 LOGMIN = 1e-3
33 # How many centimeter is an inch
34 CM_PER_INCHES = 2.54
36 class DataSet:
37 """An object describing data series with a shared X axis."""
38 def __init__(self, x=None, y1=None, name=None):
39 # self.x is the X axis shared for all y series
40 self.x = x
41 self.len = len(x)
42 self.name = name
44 # self.y is a list of series of data
45 self.y = []
46 if y1 != None: self.add(y1)
48 # self.yline is a list of plotted lines from the current DataSet
49 self.yline = []
51 # Set the plot style, maker and linestyle attributes
52 # Marker and linestyle are separate variables so we can switch them off
53 # and then recover the style information when we turn them on
54 self.marker = '.'
55 self.linestyle = '-'
56 self.plot_kwargs = dict(
57 linestyle = self.linestyle,
58 linewidth = 1.5,
59 marker = self.marker,
60 markersize = 5,
61 alpha = 1
64 def add(self, yi):
65 if len(yi) != self.len:
66 raise IndexError, 'Y data length (%d) must be == len(x) (%d)'\
67 % (len(yi), self.len)
68 else:
69 self.y.append(yi)
71 class AxesProperty:
72 """Simple struct to store any properties that has different values for X
73 and Y axes"""
74 x = None
75 y = None
78 # Main window class
80 class PlotFileApp(GenericMainPlotWindow):
81 """
82 This class implements an interactive plot windows with various options.
83 """
84 def __init__(self, x=None, y=None, title='Title', debug=False):
85 GenericMainPlotWindow.__init__(self, 'PlotFileWindow', gladefile)
87 self.set_defaults()
88 self.title = title
89 self.debug = debug
91 self.setup_gui_widgets()
93 # Data: self.data is a list of DataSet() instances
94 if x != None:
95 self.data.append( DataSet(x, y, 'Plot 1') )
97 # Try to load the file passed as parameter
98 if x == None and y == None:
99 try:
100 self.load(sys.argv[1])
101 except:
102 pass
103 self.plot()
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):
164 if self.debug: print 'plot_data method'
166 d = self.data[n]
167 d.yline = range(len(d.y))
168 for i, yi in enumerate(d.y):
169 d.yline[i], = self.axis.plot(d.x, yi, ls=d.linestyle,
170 marker=d.marker)
172 self.canvas.draw()
174 def plot(self):
175 if self.debug: print 'plot method'
177 if self.yscale == 'log' and not self.is_ydata_positive():
178 self.writeStatusBar('WARNING: Negative Y values in log scale.')
180 self.axis.clear()
182 self.axis.set_yscale('linear')
183 self.axis.set_xscale('linear')
185 for d in self.data:
186 d.yline = range(len(d.y))
187 for i, yi in enumerate(d.y):
188 d.yline[i], = self.axis.plot(d.x, yi, ls=d.linestyle,
189 marker=d.marker)
191 self.axis.set_title(self.title)
192 self.axis.set_xlabel(self.xlabel)
193 self.axis.set_ylabel(self.ylabel)
194 self.axis.grid(self.grid)
196 print 'x', self.xscale, 'y', self.yscale
197 self.axis.set_yscale(self.yscale)
198 self.axis.set_xscale(self.xscale)
200 if len(self.data) > 0:
201 self.set_xlim()
202 if len(self.data[0].y) > 0:
203 self.set_ylim()
205 self.canvas.draw()
207 def set_xlim(self):
208 if self.axes_limits.x[self.xscale] == None:
209 if self.debug: print 'autoscaling...'
210 self.axis.autoscale_view(scalex=True, scaley=False)
211 self.xmin, self.xmax = self.axis.get_xlim()
212 else:
213 if self.debug: print 'using old axis limit', self.axes_limits.x
214 self.xmin, self.xmax = self.axes_limits.x[self.xscale]
215 if self.xscale == 'log':
216 if self.xmin <= 0: self.xmin = LOGMIN
217 if self.xmax <= self.xmin: self.xmax = self.xmin+1
218 self.axis.set_xlim(xmin=self.xmin, xmax=self.xmax)
220 if self.debug: print 'xmin:', self.xmin, 'xmax:', self.xmax
221 self.xminEntry.set_text(str(self.xmin))
222 self.xmaxEntry.set_text(str(self.xmax))
224 def set_ylim(self):
225 if self.axes_limits.y[self.yscale] == None:
226 if self.debug: print 'autoscaling...'
227 self.axis.autoscale_view(scaley=True, scalex=False)
228 self.ymin, self.ymax = self.axis.get_ylim()
229 else:
230 if self.debug: print 'using old axis limit'
231 self.ymin, self.ymax = self.axes_limits.y[self.yscale]
232 if self.yscale == 'log':
233 if self.ymin <= 0: self.ymin = LOGMIN
234 if self.ymax <= self.ymin: self.ymax = self.ymin+1
235 self.axis.set_ylim(ymin=self.ymin, ymax=self.ymax)
237 if self.debug: print 'ymin:', self.ymin, 'ymax:', self.ymax
238 self.yminEntry.set_text(str(self.ymin))
239 self.ymaxEntry.set_text(str(self.ymax))
241 def load(self, filename):
242 try:
243 x, y = xyfromfile(filename, returnarray=True)
244 except IOError:
245 self.writeStatusBar("Can't open file '%s'" % filename)
246 except:
247 self.writeStatusBar("File '%s': file format unknown." % filename)
248 else:
249 filename = os.path.basename(filename)
250 self.data.append(DataSet(x,y, filename))
251 self.title = filename
252 self.axes_limits.x = dict(linear=None, log=None)
253 self.axes_limits.y = dict(linear=None, log=None)
256 # The following are menu callback methods
258 def on_title_and_axes_labels_activate(self, widget, *args):
259 TitleAndAxesWindow(self)
262 # The following are GUI callback methods
264 def on_xscale_toggled(self, widget, *args):
265 if not self.setup:
266 self.axes_limits.x[self.xscale] = self.axis.set_xlim()
267 if self.xscaleCheckB.get_active(): self.xscale = 'log'
268 else: self.xscale = 'linear'
269 if self.debug: print "XScale:", self.xscale
270 self.axis.set_xscale(self.xscale)
271 self.set_xlim()
272 self.canvas.draw()
274 def on_yscale_toggled(self, widget, *args):
275 if not self.setup:
276 self.axes_limits.y[self.yscale] = self.axis.set_ylim()
277 if self.yscaleCheckB.get_active(): self.yscale = 'log'
278 else: self.yscale = 'linear'
279 if self.debug: print "YScale:", self.yscale
280 self.axis.set_yscale(self.yscale)
281 self.set_ylim()
282 self.canvas.draw()
284 def on_points_toggled(self, widget, *args):
285 self.showPoints = not self.showPoints
286 if self.debug: print "Show Points:", self.showPoints
287 for d in self.data:
288 if self.showPoints:
289 # Restore the previous marker style
290 d.yline[0].set_marker(d.marker)
291 else:
292 # Turn off the marker visualization
293 d.yline[0].set_marker('')
294 self.canvas.draw()
296 def on_lines_toggled(self, widget, *args):
297 self.showLines = not self.showLines
298 if self.debug: print "Show Lines:", self.showLines
299 for d in self.data:
300 if self.showLines:
301 # Restore the previous linestyle
302 d.yline[0].set_linestyle(d.linestyle)
303 else:
304 # Turn off the line visualization
305 d.yline[0].set_linestyle('')
306 self.canvas.draw()
308 def on_grid_toggled(self, widget, *args):
309 self.grid = not self.grid
310 if self.debug: print "Show Grid:", self.grid
311 self.axis.grid(self.grid)
312 self.canvas.draw()
314 def on_xmin_entry_activate(self, widget, *args):
315 if self.debug: print 'X Min Entry Activated'
316 s = self.xminEntry.get_text()
317 try:
318 val = float(s)
319 except ValueError:
320 self.statusBar.push(self.context, 'Wrong X axis min limit')
321 else:
322 if self.xscale == 'log' and val <= 0: val = LOGMIN
323 self.xmin = val
324 self.axis.set_xlim(xmin=val)
325 self.canvas.draw()
327 def on_xmax_entry_activate(self, widget, *args):
328 if self.debug: print 'X Max Entry Activated'
329 s = self.xmaxEntry.get_text()
330 try:
331 val = float(s)
332 except ValueError:
333 self.statusBar.push(self.context, 'Wrong X axis max limit')
334 else:
335 if self.xscale == 'log' and val <= 0: val = self.xmin*10.0
336 self.xmax = val
337 self.axis.set_xlim(xmax=val)
338 self.canvas.draw()
340 def on_ymin_entry_activate(self, widget, *args):
341 if self.debug: print 'Y Min Entry Activated'
342 s = self.yminEntry.get_text()
343 try:
344 val = float(s)
345 except ValueError:
346 self.statusBar.push(self.context, 'Wrong Y axis min limit')
347 else:
348 if self.yscale == 'log' and val <= 0: val = LOGMIN
349 self.ymin = val
350 self.axis.set_ylim(ymin=val)
351 self.canvas.draw()
353 def on_ymax_entry_activate(self, widget, *args):
354 if self.debug: print 'Y Max Entry Activated'
355 s = self.ymaxEntry.get_text()
356 try:
357 val = float(s)
358 except ValueError:
359 self.statusBar.push(self.context, 'Wrong Y axis max limit')
360 else:
361 if self.yscale == 'log' and val <= 0: val = self.ymin*10.0
362 self.ymax = val
363 self.axis.set_ylim(ymax=val)
364 self.canvas.draw()
366 def on_apply_button_clicked(self, widget, *args):
367 sxmin = self.xminEntry.get_text()
368 sxmax = self.xmaxEntry.get_text()
369 symin = self.yminEntry.get_text()
370 symax = self.ymaxEntry.get_text()
371 try:
372 xmin_val = float(sxmin)
373 xmax_val = float(sxmax)
374 ymin_val = float(symin)
375 ymax_val = float(symax)
376 except ValueError:
377 self.statusBar.push(self.context, 'Wrong axis limit')
378 else:
379 if self.xscale == 'log':
380 if xmin_val <= 0: xmin_val = LOGMIN
381 if xmax_val <= 0: xmax_val = xmin_val*10
382 if ymin_val <= 0: ymin_val = LOGMIN
383 if ymax_val <= 0: ymax_val = ymin_val*10
384 self.xmin, self.xmax, self.ymin, self.ymax = \
385 xmin_val, xmax_val, ymin_val, ymax_val
386 self.axis.set_xlim(xmin=xmin_val)
387 self.axis.set_xlim(xmax=xmax_val)
388 self.axis.set_ylim(ymin=ymin_val)
389 self.axis.set_ylim(ymax=ymax_val)
390 self.canvas.draw()
393 # The following are MENU callback methods
395 def on_addDataSet_activate(self, widget, *args):
396 OpenFileDialog(self)
397 def on_new_activate(self, widget, *args):
398 self.set_defaults()
399 self.reset_scale_buttons()
400 self.plot()
401 def on_dimensionsResolution_activate(self, widget, *args):
402 DimentionAndResolution(self)
403 def on_autoscale_activate(self, widget, *args):
404 self.axis.autoscale_view()
405 self.canvas.draw()
406 def on_coordinatePicker_activate(self, widget, *args):
407 if self.cooPickerCheckB.get_active():
408 self.cid = self.canvas.mpl_connect('button_press_event',
409 get_coordinates_cb)
410 self.writeStatusBar('Click on the plot to log coordinates on '+\
411 'the terminal.')
412 elif self.cid != None:
413 self.canvas.mpl_disconnect(self.cid)
414 self.writeStatusBar('Coordinate picker disabled.')
415 else:
416 print "Error: tried to disconnect an unexistent event."
417 def on_moreGrid_activate(self, widget, *args):
418 if self.moreGridCheckB.get_active():
419 self.axis.xaxis.grid(True, which='minor', ls='--', alpha=0.5)
420 self.axis.yaxis.grid(True, which='minor', ls='--', alpha=0.5)
421 self.axis.xaxis.grid(True, which='major', ls='-', alpha=0.5)
422 self.axis.yaxis.grid(True, which='major', ls='-', alpha=0.5)
423 else:
424 self.axis.xaxis.grid(False, which='minor')
425 self.axis.yaxis.grid(False, which='minor')
426 self.axis.xaxis.grid(True, which='major', ls=':')
427 self.axis.yaxis.grid(True, which='major', ls=':')
428 self.canvas.draw()
429 def on_info_activate(self, widget, *args):
430 AboutDialog()
431 def on_plot_properties_activate(self, widget, *args):
432 PlotPropertiesDialog(self)
434 def get_coordinates_cb(event):
436 Callback for the coordinate picker tool. This function is not a class
437 method because I don't know how to connect an MPL event to a method instead
438 of a function.
440 if not event.inaxes: return
441 print "%3.4f\t%3.4f" % (event.xdata, event.ydata)
444 # Dialogs classes
446 class PlotPropertiesDialog(DialogWindowWithCancel):
447 def __init__(self, callerApp):
448 DialogWindowWithCancel.__init__(self, 'PlotPropertiesDialog',
449 gladefile, callerApp)
451 self.treeView = self.widgetTree.get_widget('treeview')
452 self.create_plotlist()
453 self.load_widgets()
455 # Retrive the data list
456 self.data = self.callerApp.data
458 # Save all the lines properties in case of Cancell-button
459 self.orig_lines = range(len(self.data))
460 for i,d in enumerate(self.data):
461 self.orig_lines[i] = [Line2D([0], [0]), d.linestyle, d.marker]
462 self.orig_lines[i][0].update_from(d.yline[0])
464 self.selected_data = None
465 self.selected_line = None
466 self.allowReplot = False
468 def load_widgets(self):
469 self.lineWidthSpinButt = \
470 self.widgetTree.get_widget('lineWidthSpinButton')
471 self.lineStyleComboB = \
472 self.widgetTree.get_widget('lineStyleComboBox')
473 self.lineColorComboB = \
474 self.widgetTree.get_widget('lineColorComboBox')
475 self.markerTypeComboB = \
476 self.widgetTree.get_widget('markerTypeComboBox')
477 self.markerSizeSpinButt = \
478 self.widgetTree.get_widget('markerSizeSpinButton')
479 self.markerEdgeColorComboB = \
480 self.widgetTree.get_widget('markerEdgeColComboBox')
481 self.markerFaceColorComboB = \
482 self.widgetTree.get_widget('markerFaceColComboBox')
484 def create_plotlist(self):
485 # Add a column to the treeView
486 self.addListColumn('Plot List', 0)
488 # Create the listStore Model to use with the treeView
489 self.plotList = gtk.ListStore(str)
491 # Populate the list
492 self.insertPlotList()
494 # Attatch the model to the treeView
495 self.treeView.set_model(self.plotList)
497 def addListColumn(self, title, columnId):
498 """This function adds a column to the list view.
499 First it create the gtk.TreeViewColumn and then set
500 some needed properties"""
502 column = gtk.TreeViewColumn(title, gtk.CellRendererText(), text=0)
503 column.set_resizable(True)
504 column.set_sort_column_id(columnId)
505 self.treeView.append_column(column)
507 def insertPlotList(self):
508 for data in self.callerApp.data:
509 self.plotList.append([data.name])
511 def update_properties(self):
512 # Set the Spin Buttons with the values for the selected data
513 self.lineWidthSpinButt.set_value(self.selected_line.get_linewidth())
514 self.markerSizeSpinButt.set_value(self.selected_line.get_markersize())
516 # Set the Combo Boxes with the values for the selected data
517 self.set_current_linestyle(self.selected_data)
518 self.set_current_marker(self.selected_data)
519 self.set_current_lineColor(self.selected_line)
520 self.set_current_markerEdgeColor(self.selected_line)
521 self.set_current_markerFaceColor(self.selected_line)
523 def set_current_lineColor(self, data_line):
524 lc = data_line.get_color()
525 colors = 'bgrcmyk'
526 if lc in colors:
527 ic = colors.index(lc)
528 self.lineColorComboB.set_active(ic)
529 else:
530 print "WARNING: Unsupported color '%s'." % lc
532 def set_current_markerEdgeColor(self, data_line):
533 mec = data_line.get_mec()
534 colors = 'bgrcmyk'
535 if mec in colors:
536 ic = colors.index(mec)
537 self.lineColorComboB.set_active(ic)
538 else:
539 print "WARNING: Unsupported color '%s'." % mec
541 def set_current_markerFaceColor(self, data_line):
542 mfc = data_line.get_mfc()
543 colors = 'bgrcmyk'
544 if mfc in colors:
545 ic = colors.index(mfc)
546 self.lineColorComboB.set_active(ic)
547 else:
548 print "WARNING: Unsupported color '%s'." % mfc
550 def set_current_linestyle(self, data):
551 ls = data.linestyle
552 line_styles = ['-', '--', ':', '-.']
554 if ls in line_styles:
555 il = line_styles.index(ls)
556 self.lineStyleComboB.set_active(il)
557 else:
558 print "WARNING: Linestyle '%s' not supported." % ls
560 def set_current_marker(self, data):
561 m = data.marker
562 markers = 'os^v<>.+xdDhHp'
563 if m in markers:
564 im = markers.index(m)
565 self.markerTypeComboB.set_active(im)
566 else:
567 print "WARNING: Marker type '%s' not supported." % m
571 # GUI Callbacks
573 def on_treeview_cursor_changed(self, *args):
574 plot_index = self.treeView.get_cursor()[0][0]
575 self.selected_line = self.data[plot_index].yline[0]
576 self.selected_data = self.callerApp.data[plot_index]
578 self.allowReplot = False
579 self.update_properties()
580 self.allowReplot = True
582 def on_lineWidth_value_changed(self, *args):
583 if self.allowReplot and self.selected_line is not None:
584 prop = 'linewidth'
585 lw = self.lineWidthSpinButt.get_value()
587 self.selected_line.set_linewidth(lw)
588 self.callerApp.canvas.draw()
590 def on_lineStyle_changed(self, *args):
591 if self.allowReplot and self.selected_line is not None:
592 if not self.callerApp.linesCheckB.get_active():
593 self.callerApp.linesCheckB.set_active(True)
595 prop = 'linestyle'
596 ls = self.lineStyleComboB.get_active_text()
598 line_styles = {'Continuous': '-', 'Dashed': '--',
599 'Dotted': ':', 'Dot-Line': '-.'}
601 if ls in line_styles.keys():
602 self.selected_line.set_linestyle(line_styles[ls])
603 self.callerApp.canvas.draw()
604 self.selected_data.linestyle = line_styles[ls]
605 else:
606 print "WARNING: Unsupported line style '%s'." % ls
608 def on_lineColor_changed(self, *args):
609 if self.allowReplot and self.selected_line is not None:
610 prop = 'color'
611 text = self.lineColorComboB.get_active_text()
612 color = text[text.find('(') + 1]
614 self.selected_line.set_color(color)
615 self.callerApp.canvas.draw()
617 def on_markerType_changed(self, *args):
618 if self.allowReplot and self.selected_line is not None:
619 if not self.callerApp.pointsCheckB.get_active():
620 self.callerApp.pointsCheckB.set_active(True)
622 prop = 'marker'
623 text = self.markerTypeComboB.get_active_text()
624 m = text[text.find('(') + 1]
626 self.selected_line.set_marker(m)
627 self.callerApp.canvas.draw()
628 self.selected_data.marker = m
630 def on_markerSize_value_changed(self, *args):
631 if self.allowReplot and self.selected_line is not None:
632 prop = 'markersize'
633 ms = self.markerSizeSpinButt.get_value()
635 self.selected_line.set_markersize(ms)
636 self.callerApp.canvas.draw()
638 def on_markerEdgeColor_changed(self, *args):
639 if self.allowReplot and self.selected_data is not None:
640 prop = 'markeredgecolor'
641 text = self.markerEdgeColorComboB.get_active_text()
642 color = text[text.find('(') + 1]
644 self.selected_line.set_markeredgecolor(color)
645 self.callerApp.canvas.draw()
647 def on_markerFaceColor_changed(self, *args):
648 if self.allowReplot and self.selected_data is not None:
649 prop = 'markerfacecolor'
650 text = self.markerFaceColorComboB.get_active_text()
651 color = text[text.find('(') + 1]
653 self.selected_line.set_markerfacecolor(color)
654 self.callerApp.canvas.draw()
657 def on_cancelButton_clicked(self, widget, *args):
658 # Restore the old style
659 for orig_line, d in zip(self.orig_lines, self.data):
660 d.yline[0].update_from(orig_line[0])
661 d.linestyle = orig_line[1]
662 d.marker = orig_line[2]
664 self.callerApp.canvas.draw()
665 self.window.destroy()
667 def on_okButton_clicked(self, widget, *args):
668 self.window.destroy()
670 class TitleAndAxesWindow(DialogWindowWithCancel):
672 Dialog for setting Title and axes labels.
674 def __init__(self, callerApp):
675 DialogWindowWithCancel.__init__(self, 'TitleAndAxesWindow', gladefile,
676 callerApp)
678 self.titleEntry = self.widgetTree.get_widget('titleEntry')
679 self.xlabelEntry = self.widgetTree.get_widget('xlabelEntry')
680 self.ylabelEntry = self.widgetTree.get_widget('ylabelEntry')
682 def sync(field, entry):
683 if field != None: entry.set_text(field)
685 sync(self.callerApp.title, self.titleEntry)
686 sync(self.callerApp.xlabel, self.xlabelEntry)
687 sync(self.callerApp.ylabel, self.ylabelEntry)
689 def on_okButton_clicked(self, widget, *args):
690 print "OK Clicked"
691 self.callerApp.axis.set_title(self.titleEntry.get_text())
692 self.callerApp.axis.set_xlabel(self.xlabelEntry.get_text())
693 self.callerApp.axis.set_ylabel(self.ylabelEntry.get_text())
694 self.callerApp.canvas.draw()
696 self.callerApp.title = self.titleEntry.get_text()
697 self.callerApp.xlabel = self.ylabelEntry.get_text()
698 self.callerApp.ylabel = self.xlabelEntry.get_text()
700 self.window.destroy()
702 class DimentionAndResolution(DialogWindowWithCancel):
704 Dialog for setting Figure dimentions and resolution.
706 def __init__(self, callerApp):
707 DialogWindowWithCancel.__init__(self, 'DimentionsDialog', gladefile,
708 callerApp)
709 self.xdimSpinButton = self.widgetTree.get_widget('xdimSpinButton')
710 self.ydimSpinButton = self.widgetTree.get_widget('ydimSpinButton')
711 self.resolutionSpinButton = self.widgetTree.get_widget(
712 'resolutionSpinButton')
713 self.inchesRadioB = self.widgetTree.get_widget('inRadioButton')
715 self.xdim_o, self.ydim_o = self.callerApp.figure.get_size_inches()
716 self.dpi_o = self.callerApp.figure.get_dpi()
718 self.set_initial_values()
720 def set_values(self, xdim, ydim, dpi):
721 if not self.inchesRadioB.get_active():
722 xdim *= CM_PER_INCHES
723 ydim *= CM_PER_INCHES
724 self.xdimSpinButton.set_value(xdim)
725 self.ydimSpinButton.set_value(ydim)
726 self.resolutionSpinButton.set_value(dpi)
728 def set_initial_values(self):
729 self.set_values(self.xdim_o, self.ydim_o, self.dpi_o)
731 def set_default_values(self):
732 xdim, ydim = rcParams['figure.figsize']
733 dpi = rcParams['figure.dpi']
734 self.set_values(xdim, ydim, dpi)
736 def get_values(self):
737 self.xdim = self.xdimSpinButton.get_value()
738 self.ydim = self.ydimSpinButton.get_value()
739 self.resolution = self.resolutionSpinButton.get_value()
740 if not self.inchesRadioB.get_active():
741 self.xdim /= CM_PER_INCHES
742 self.ydim /= CM_PER_INCHES
744 def set_figsize(self):
745 self.callerApp.figure.set_size_inches(self.xdim, self.ydim)
746 self.callerApp.figure.set_dpi(self.resolution)
748 def on_unity_toggled(self, widget, *args):
749 xdim = self.xdimSpinButton.get_value()
750 ydim = self.ydimSpinButton.get_value()
751 if self.inchesRadioB.get_active():
752 xdim /= CM_PER_INCHES
753 ydim /= CM_PER_INCHES
754 else:
755 xdim *= CM_PER_INCHES
756 ydim *= CM_PER_INCHES
757 self.xdimSpinButton.set_value(xdim)
758 self.ydimSpinButton.set_value(ydim)
760 def on_okButton_clicked(self, widget, *args):
761 print "OK"
762 self.get_values()
763 self.set_figsize()
764 self.callerApp.canvas.draw()
765 self.window.destroy()
767 def on_restoreButton_clicked(self, widget, *args):
768 self.set_default_values()
770 class OpenFileDialog(GenericOpenFileDialog):
772 This class implements the "Open File" dialog.
774 def __init__(self, callerApp):
775 GenericOpenFileDialog.__init__(self, 'OpenFileDialog', gladefile,
776 callerApp)
778 def openSelectedFile(self):
779 self.callerApp.load( self.filename )
780 self.callerApp.plot_data(-1)
781 self.window.destroy()
783 class AboutDialog(GenericSecondaryWindow):
785 Object for the "About Dialog".
787 def __init__(self):
788 GenericSecondaryWindow.__init__(self, 'AboutDialog', gladefile)
789 self.window.set_version(read_version())
792 # Functions
794 def read_version():
795 """ Extract version from README file. """
796 file = open(rootdir+'README')
797 ver = None
798 for line in file:
799 if line.strip().startswith('*Latest Version*'):
800 s = line.split()
801 ver = s[2]
802 break
803 file.close()
804 return ver
806 def plot_from_file(fname):
807 try:
808 datafile = open(fname)
809 except:
810 pass
812 def test():
813 x = arange(100)
814 y = sin(x/10.0)
815 p = PlotFileApp(x, y, title='Random Sequence', debug=True)
816 p.start()
818 def main():
819 p = PlotFileApp(debug=True)
820 # Try to open a sample file
821 if len(sys.argv) < 2 and os.path.isfile(sourcedir+'samples/data.txt'):
822 p.load(sourcedir+'samples/data.txt')
823 p.plot()
824 p.start()
826 if __name__ == '__main__': main()