IA: Minor README changes
[pyplotsuite.git] / pyplotsuite / plotfile2.py
blob31633403437f970b788b299a594c66c8b29b0a25
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 VERSION file)
6 # This program is part of PyPlotSuite <http://pyplotsuite.sourceforge.net>.
8 # Copyright (C) 2007 Antonio Ingargiola <tritemio@gmail.com>
10 # This program is free software; you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation; either version 2 of the License, or
13 # (at your option) any later version.
15 import sys
16 import os.path
17 import imp
18 rootdir = os.path.abspath(imp.find_module('pyplotsuite')[1]) + '/'
19 sourcedir = rootdir + 'plotfile/'
21 import gtk
22 from matplotlib.lines import Line2D
23 from pyplotsuite.common.gtk_generic_windows import \
24 GenericMainPlotWindow, DialogWindowWithCancel,\
25 GenericOpenFileDialog, GenericSecondaryWindow
26 from pyplotsuite.common.filedata import xyLabelFromFile
27 from pyplotsuite.common.version import read_version
28 from numpy import arange, array, min
30 # XML GUI Description file
31 gladefile = sourcedir + 'plotfile2.glade'
33 # Minimum default axis value in log scale when the original value was <= 0
34 LOGMIN = 1e-3
36 # How many centimeter is an inch
37 CM_PER_INCHES = 2.54
39 class DataSet:
40 """An object describing data series with a shared X axis."""
41 def __init__(self, x=None, y1=None, name=None):
42 # self.x is the X axis shared for all y series
43 self.x = x
44 self.len = len(x)
45 self.name = name
47 # self.y is a list of series of data
48 self.y = []
49 if y1 != None: self.add(y1)
51 # self.yline is a list of plotted lines from the current DataSet
52 self.yline = []
54 # Set the plot style, maker and linestyle attributes
55 # Marker and linestyle are separate variables so we can switch them off
56 # and then recover the style information when we turn them on
57 self.marker = '.'
58 self.linestyle = '-'
60 def add(self, yi):
61 if len(yi) != self.len:
62 raise IndexError, 'Y data length (%d) must be == len(x) (%d)'\
63 % (len(yi), self.len)
64 else:
65 self.y.append(yi)
67 class AxesProperty:
68 """Simple struct to store any properties that has different values for X
69 and Y axes"""
70 x = None
71 y = None
74 # Main window class
76 class PlotFileApp(GenericMainPlotWindow):
77 """
78 This class implements an interactive plot windows with various options.
79 """
80 def __init__(self, x=None, y=None, title='Title', debug=False):
81 GenericMainPlotWindow.__init__(self, 'PlotFileWindow', gladefile)
83 self.set_defaults()
84 self.title = title
85 self.debug = debug
86 self.negative = False
88 self.setup_gui_widgets()
90 # Data: self.data is a list of DataSet() instances
91 if x != None:
92 self.data.append( DataSet(x, y, 'Plot 1') )
93 if min(y) <= 0:
94 self.negative = True
96 # Try to load the file passed as parameter
97 if x == None and y == None:
98 try:
99 self.load(sys.argv[1])
100 except:
101 pass
102 self.plot()
104 self.open_file_dialog = OpenFileDialog(self)
106 def set_defaults(self):
107 # Clear data
108 self.data = []
110 # Plot Defaults
111 self.title = 'Title'
112 self.xlabel = 'X Axis'
113 self.ylabel = 'Y Axis'
114 self.xscale = 'linear'
115 self.yscale = 'linear'
116 self.showPoints = True
117 self.showLines = True
118 self.grid = True
120 # Reset ranges
121 self.xmin, self.xmax, self.ymin, self.ymax = None, None, None, None
122 self.axes_limits = AxesProperty()
123 self.axes_limits.x = dict(linear=None, log=None)
124 self.axes_limits.y = dict(linear=None, log=None)
126 def reset_scale_buttons(self):
127 self.setup = True
128 if self.xscale == 'log':
129 self.xscaleCheckB.set_active(True)
130 else:
131 self.xscaleCheckB.set_active(False)
132 if self.yscale == 'log':
133 self.yscaleCheckB.set_active(True)
134 else:
135 self.yscaleCheckB.set_active(False)
136 self.setup = False
138 def setup_gui_widgets(self):
139 # Create the text entry handler
140 self.xminEntry = self.widgetTree.get_widget('xmin_entry')
141 self.xmaxEntry = self.widgetTree.get_widget('xmax_entry')
142 self.yminEntry = self.widgetTree.get_widget('ymin_entry')
143 self.ymaxEntry = self.widgetTree.get_widget('ymax_entry')
145 # Initialize the check buttons to the correct value
146 self.pointsCheckB = self.widgetTree.get_widget('points_chk_butt')
147 self.linesCheckB = self.widgetTree.get_widget('lines_chk_butt')
148 self.xscaleCheckB = self.widgetTree.get_widget('xlog_chk_butt')
149 self.yscaleCheckB = self.widgetTree.get_widget('ylog_chk_butt')
150 self.reset_scale_buttons()
152 self.cooPickerCheckB = self.widgetTree.get_widget('coordinatePicker')
153 self.moreGridCheckB = self.widgetTree.get_widget('moreGrid')
155 self.window.show_all()
156 if self.debug: print 'end of setup_gui_widgets()'
158 def is_ydata_positive(self):
159 for d in self.data:
160 for yi in d.y:
161 if (yi <= 0).any(): return False
162 return True
164 def plot_data(self, n=0):
165 """Plot the n-th data from the self.data list of DataSet()."""
167 if self.debug: print 'plot_data method'
169 d = self.data[n]
170 d.yline = range(len(d.y))
171 for i, yi in enumerate(d.y):
172 d.yline[i], = self.axis.plot(d.x, yi, ls=d.linestyle,
173 marker=d.marker)
175 self.axis.set_title(self.title)
176 self.axis.set_xlabel(self.xlabel)
177 self.axis.set_ylabel(self.ylabel)
179 self.set_xlim()
180 self.set_ylim()
181 self.canvas.draw()
183 #self.update_axis_limits_entry()
185 def update_axis_limits_entry(self):
187 xmin, xmax = self.axis.get_xlim()
188 self.xminEntry.set_text(str(xmin))
189 self.xmaxEntry.set_text(str(xmax))
191 ymin, ymax = self.axis.get_ylim()
192 self.yminEntry.set_text(str(ymin))
193 self.ymaxEntry.set_text(str(ymax))
196 def plot(self):
197 if self.debug: print 'plot method'
199 if self.yscale == 'log' and not self.is_ydata_positive():
200 self.writeStatusBar('WARNING: Negative Y values in log scale.')
202 self.axis.clear()
204 self.axis.set_yscale('linear')
205 self.axis.set_xscale('linear')
207 for d in self.data:
208 d.yline = range(len(d.y))
209 for i, yi in enumerate(d.y):
210 d.yline[i], = self.axis.plot(d.x, yi, ls=d.linestyle,
211 marker=d.marker)
213 self.axis.set_title(self.title)
214 self.axis.set_xlabel(self.xlabel)
215 self.axis.set_ylabel(self.ylabel)
216 self.axis.grid(self.grid)
218 print 'x', self.xscale, 'y', self.yscale
219 self.axis.set_yscale(self.yscale)
220 self.axis.set_xscale(self.xscale)
222 if len(self.data) > 0:
223 self.set_xlim()
224 if len(self.data[0].y) > 0:
225 self.set_ylim()
227 self.canvas.draw()
229 def set_xlim(self):
230 if self.axes_limits.x[self.xscale] == None:
231 if self.debug: print 'autoscaling...'
232 self.axis.autoscale_view(scalex=True, scaley=False)
233 self.xmin, self.xmax = self.axis.get_xlim()
234 else:
235 if self.debug: print 'using old axis limit', self.axes_limits.x
236 self.xmin, self.xmax = self.axes_limits.x[self.xscale]
237 if self.xscale == 'log':
238 if self.xmin <= 0: self.xmin = LOGMIN
239 if self.xmax <= self.xmin: self.xmax = self.xmin+1
240 self.axis.set_xlim(xmin=self.xmin, xmax=self.xmax)
242 if self.debug: print 'xmin:', self.xmin, 'xmax:', self.xmax
243 self.xminEntry.set_text(str(self.xmin))
244 self.xmaxEntry.set_text(str(self.xmax))
246 def set_ylim(self):
247 if self.axes_limits.y[self.yscale] == None:
248 if self.debug: print 'autoscaling...'
249 self.axis.autoscale_view(scaley=True, scalex=False)
250 self.ymin, self.ymax = self.axis.get_ylim()
251 else:
252 if self.debug: print 'using old axis limit'
253 self.ymin, self.ymax = self.axes_limits.y[self.yscale]
254 if self.yscale == 'log':
255 if self.ymin <= 0: self.ymin = LOGMIN
256 if self.ymax <= self.ymin: self.ymax = self.ymin+1
257 self.axis.set_ylim(ymin=self.ymin, ymax=self.ymax)
259 if self.debug: print 'ymin:', self.ymin, 'ymax:', self.ymax
260 self.yminEntry.set_text(str(self.ymin))
261 self.ymaxEntry.set_text(str(self.ymax))
263 def load(self, filename):
264 try:
265 x, y , xlab, ylab = xyLabelFromFile(filename)
266 except IOError:
267 self.writeStatusBar("Can't open file '%s'" % filename)
268 return False
269 except:
270 self.writeStatusBar("File '%s': file format unknown." % filename)
271 return False
272 else:
273 filename = os.path.basename(filename)
274 self.data.append(DataSet(x,y, filename))
275 self.title = filename
276 if xlab is not None: self.xlabel = xlab
277 if ylab is not None: self.ylabel = ylab
278 self.axes_limits.x = dict(linear=None, log=None)
279 self.axes_limits.y = dict(linear=None, log=None)
280 self.writeStatusBar("File '%s' loaded." % filename)
281 if y.min() <= 0:
282 self.negative = True
283 return True
285 def warn(self, msg):
286 self.writeStatusBar('Warning: '+msg)
289 # The following are GUI callback methods
291 def on_xscale_toggled(self, widget, *args):
292 if not self.setup:
293 self.axes_limits.x[self.xscale] = self.axis.get_xlim()
294 if self.xscaleCheckB.get_active(): self.xscale = 'log'
295 else: self.xscale = 'linear'
296 if self.debug: print "XScale:", self.xscale
297 self.axis.set_xscale(self.xscale)
298 self.set_xlim()
299 self.canvas.draw()
300 self.writeStatusBar('X Axis Scale: %s.' % self.xscale)
303 def on_yscale_toggled(self, widget, *args):
304 if not self.setup:
305 self.axes_limits.y[self.yscale] = self.axis.get_ylim()
306 if self.yscaleCheckB.get_active(): self.yscale = 'log'
307 else: self.yscale = 'linear'
308 if self.debug: print "YScale:", self.yscale
309 self.axis.set_yscale(self.yscale)
310 self.set_ylim()
311 self.canvas.draw()
313 if self.negative and self.yscale == 'log':
314 self.warn('Negative values not displayed in log-scale, lines '+\
315 'may appear discontinuos!')
316 else:
317 self.writeStatusBar('Y Axis Scale: %s.' % self.yscale)
320 def on_points_toggled(self, widget, *args):
321 self.showPoints = not self.showPoints
322 if self.debug: print "Show Points:", self.showPoints
323 for d in self.data:
324 if self.showPoints:
325 # Restore the previous marker style
326 d.yline[0].set_marker(d.marker)
327 else:
328 # Turn off the marker visualization
329 d.yline[0].set_marker('')
330 self.canvas.draw()
332 def on_lines_toggled(self, widget, *args):
333 self.showLines = not self.showLines
334 if self.debug: print "Show Lines:", self.showLines
335 for d in self.data:
336 if self.showLines:
337 # Restore the previous linestyle
338 d.yline[0].set_linestyle(d.linestyle)
339 else:
340 # Turn off the line visualization
341 d.yline[0].set_linestyle('')
342 self.canvas.draw()
344 def on_grid_toggled(self, widget, *args):
345 self.grid = not self.grid
346 if self.debug: print "Show Grid:", self.grid
347 self.axis.grid(self.grid)
348 self.canvas.draw()
350 def on_xmin_entry_activate(self, widget, *args):
351 if self.debug: print 'X Min Entry Activated'
352 s = self.xminEntry.get_text()
353 try:
354 val = float(s)
355 except ValueError:
356 self.statusBar.push(self.context, 'Wrong X axis min limit.')
357 self.xminEntry.set_text('')
358 else:
359 if self.xscale == 'log' and val <= 0:
360 val = LOGMIN
361 self.warn('Only values > 0 are allowed in log scale.')
362 self.xminEntry.set_text(str(val))
363 self.xmin = val
364 self.axis.set_xlim(xmin=val)
365 self.canvas.draw()
367 def on_xmax_entry_activate(self, widget, *args):
368 if self.debug: print 'X Max Entry Activated'
369 s = self.xmaxEntry.get_text()
370 try:
371 val = float(s)
372 except ValueError:
373 self.statusBar.push(self.context, 'Wrong X axis max limit.')
374 self.xmaxEntry.set_text('')
375 else:
376 if self.xscale == 'log' and val <= 0:
377 val = self.xmin*10.0
378 self.warn('Only values > 0 are allowed in log scale.')
379 self.xmaxEntry.set_text(str(val))
380 self.xmax = val
381 self.axis.set_xlim(xmax=val)
382 self.canvas.draw()
384 def on_ymin_entry_activate(self, widget, *args):
385 if self.debug: print 'Y Min Entry Activated'
386 s = self.yminEntry.get_text()
387 try:
388 val = float(s)
389 except ValueError:
390 self.statusBar.push(self.context, 'Wrong Y axis min limit.')
391 self.yminEntry.set_text('')
392 else:
393 if self.yscale == 'log' and val <= 0:
394 val = LOGMIN
395 self.warn('Only values > 0 are allowed in log scale.')
396 self.yminEntry.set_text(str(val))
397 self.ymin = val
398 self.axis.set_ylim(ymin=val)
399 self.canvas.draw()
401 def on_ymax_entry_activate(self, widget, *args):
402 if self.debug: print 'Y Max Entry Activated'
403 s = self.ymaxEntry.get_text()
404 try:
405 val = float(s)
406 except ValueError:
407 self.statusBar.push(self.context, 'Wrong Y axis max limit.')
408 self.ymaxEntry.set_text('')
409 else:
410 if self.yscale == 'log' and val <= 0:
411 val = self.ymin*10.0
412 self.warn('Only values > 0 are allowed in log scale.')
413 self.ymaxEntry.set_text(str(val))
414 self.ymax = val
415 self.axis.set_ylim(ymax=val)
416 self.canvas.draw()
418 def on_apply_button_clicked(self, widget, *args):
419 sxmin = self.xminEntry.get_text()
420 sxmax = self.xmaxEntry.get_text()
421 symin = self.yminEntry.get_text()
422 symax = self.ymaxEntry.get_text()
423 try:
424 xmin_val = float(sxmin)
425 xmax_val = float(sxmax)
426 ymin_val = float(symin)
427 ymax_val = float(symax)
428 except ValueError:
429 self.statusBar.push(self.context, 'Wrong axis limit')
430 else:
431 if self.xscale == 'log':
432 if xmin_val <= 0: xmin_val = LOGMIN
433 if xmax_val <= 0: xmax_val = xmin_val*10
434 if ymin_val <= 0: ymin_val = LOGMIN
435 if ymax_val <= 0: ymax_val = ymin_val*10
436 self.xmin, self.xmax, self.ymin, self.ymax = \
437 xmin_val, xmax_val, ymin_val, ymax_val
438 self.axis.set_xlim(xmin=xmin_val)
439 self.axis.set_xlim(xmax=xmax_val)
440 self.axis.set_ylim(ymin=ymin_val)
441 self.axis.set_ylim(ymax=ymax_val)
442 self.canvas.draw()
445 # The following are MENU callback methods
448 ## Actions
449 def on_addDataSet_activate(self, widget, *args):
450 self.open_file_dialog.window.show()
451 def on_new_activate(self, widget, *args):
452 self.set_defaults()
453 self.reset_scale_buttons()
454 self.plot()
456 ## Tools
457 def on_autoscale_activate(self, widget, *args):
458 self.axis.autoscale_view()
459 self.canvas.draw()
460 def on_coordinatePicker_activate(self, widget, *args):
461 if self.cooPickerCheckB.get_active():
462 self.cid = self.canvas.mpl_connect('button_press_event',
463 get_coordinates_cb)
464 self.writeStatusBar('Click on the plot to log coordinates on '+\
465 'the terminal.')
466 elif self.cid != None:
467 self.canvas.mpl_disconnect(self.cid)
468 self.writeStatusBar('Coordinate picker disabled.')
469 else:
470 print "Error: tried to disconnect an unexistent event."
471 def on_moreGrid_activate(self, widget, *args):
472 if self.moreGridCheckB.get_active():
473 self.axis.xaxis.grid(True, which='minor', ls='--', alpha=0.5)
474 self.axis.yaxis.grid(True, which='minor', ls='--', alpha=0.5)
475 self.axis.xaxis.grid(True, which='major', ls='-', alpha=0.5)
476 self.axis.yaxis.grid(True, which='major', ls='-', alpha=0.5)
477 else:
478 self.axis.xaxis.grid(False, which='minor')
479 self.axis.yaxis.grid(False, which='minor')
480 self.axis.xaxis.grid(True, which='major', ls=':')
481 self.axis.yaxis.grid(True, which='major', ls=':')
482 self.canvas.draw()
484 ## Dialogs
485 def on_SizeAndResolution_activate(self, widget, *args):
486 DimentionAndResolution(self)
487 def on_plot_properties_activate(self, widget, *args):
488 PlotPropertiesDialog(self)
489 def on_makeInterpolation_activate(self, widget, *args):
490 InterpolationDialog(self)
491 def on_title_and_axes_labels_activate(self, widget, *args):
492 TitleAndAxesWindow(self)
493 def on_info_activate(self, widget, *args):
494 AboutDialog()
497 def get_coordinates_cb(event):
499 Callback for the coordinate picker tool. This function is not a class
500 method because I don't know how to connect an MPL event to a method instead
501 of a function.
503 if not event.inaxes: return
504 print "%3.4f\t%3.4f" % (event.xdata, event.ydata)
507 # Abstract dialogs classes
509 class DialogWithPlotList(DialogWindowWithCancel):
510 """Abstract class for dialogs with a list of current plots in them."""
512 def __init__(self, dialogName, gladefile, callerApp):
513 DialogWindowWithCancel.__init__(self, dialogName, gladefile, callerApp)
515 self.treeView = self.widgetTree.get_widget('treeview')
516 self.create_plotlist()
518 def create_plotlist(self):
519 # Add a column to the treeView
520 self.addListColumn('Plot List', 0)
522 # Create the listStore Model to use with the treeView
523 self.plotList = gtk.ListStore(str)
525 # Populate the list
526 self.insertPlotList()
528 # Attatch the model to the treeView
529 self.treeView.set_model(self.plotList)
531 def addListColumn(self, title, columnId):
532 """This function adds a column to the list view.
533 First it create the gtk.TreeViewColumn and then set
534 some needed properties"""
536 column = gtk.TreeViewColumn(title, gtk.CellRendererText(), text=0)
537 column.set_resizable(True)
538 column.set_sort_column_id(columnId)
539 self.treeView.append_column(column)
541 def insertPlotList(self):
542 for data in self.callerApp.data:
543 self.plotList.append([data.name])
545 def on_applyButton_clicked(self, widget, *args):
546 self.window.destroy()
548 def on_cancelButton_clicked(self, widget, *args):
549 self.window.destroy()
551 def on_okButton_clicked(self, widget, *args):
552 self.window.destroy()
555 # Dialogs classes
557 class InterpolationDialog(DialogWithPlotList):
558 def __init__(self, callerApp):
559 DialogWithPlotList.__init__(self, 'InterpolationDialog',
560 gladefile, callerApp)
561 # To be implemented ...
564 class PlotPropertiesDialog(DialogWithPlotList):
566 colors = 'bgrcmyk'
568 line_styles = ['-', '--', ':', '-.']
569 line_stylesd = {'Continuous': '-', 'Dashed': '--', 'Dotted': ':',
570 'Dot-Line': '-.'}
572 markers = 'os^v<>.+xdDhHp'
574 def __init__(self, callerApp):
575 DialogWithPlotList.__init__(self, 'PlotPropertiesDialog',
576 gladefile, callerApp)
578 if not self.callerApp.linesCheckB.get_active():
579 self.callerApp.linesCheckB.set_active(True)
581 if not self.callerApp.pointsCheckB.get_active():
582 self.callerApp.pointsCheckB.set_active(True)
584 self.load_widgets()
586 # Retrive the data list
587 self.data = self.callerApp.data
589 # Save all the lines properties in case of Cancell-button
590 self.orig_lines = range(len(self.data))
591 for i,d in enumerate(self.data):
592 self.orig_lines[i] = [Line2D([0], [0]), d.linestyle, d.marker]
593 self.orig_lines[i][0].update_from(d.yline[0])
595 self.selected_data = None
596 self.selected_line = None
597 self.allowReplot = False
599 def load_widgets(self):
600 self.lineWidthSpinButt = \
601 self.widgetTree.get_widget('lineWidthSpinButton')
602 self.lineStyleComboB = \
603 self.widgetTree.get_widget('lineStyleComboBox')
604 self.colorComboB = \
605 self.widgetTree.get_widget('lineColorComboBox')
606 self.markerComboB = \
607 self.widgetTree.get_widget('markerTypeComboBox')
608 self.markerSizeSpinButt = \
609 self.widgetTree.get_widget('markerSizeSpinButton')
610 self.markerEdgeColorComboB = \
611 self.widgetTree.get_widget('markerEdgeColComboBox')
612 self.markerFaceColorComboB = \
613 self.widgetTree.get_widget('markerFaceColComboBox')
614 self.markerEdgeWidthSpinButt = \
615 self.widgetTree.get_widget('markerEdgeWidthSpinButton')
617 def update_properties(self):
618 selected_line = self.selected_line
620 # Set the Spin Buttons with the values for the selected data
621 self.lineWidthSpinButt.set_value(selected_line.get_linewidth())
622 self.markerSizeSpinButt.set_value(selected_line.get_markersize())
623 mew = selected_line.get_markeredgewidth()
624 self.markerEdgeWidthSpinButt.set_value(mew)
626 # Set the Combo Boxes with the values for the selected data
627 self.set_combobox(self.lineStyleComboB, selected_line.get_linestyle,
628 self.line_styles)
629 self.set_combobox(self.colorComboB, selected_line.get_color,
630 self.colors)
631 self.set_combobox(self.markerComboB, selected_line.get_marker,
632 self.markers)
633 self.set_combobox(self.markerEdgeColorComboB, selected_line.get_mec,
634 self.colors)
635 self.set_combobox(self.markerFaceColorComboB, selected_line.get_mfc,
636 self.colors)
638 def set_combobox(self, cbox, retrive_fun, choses):
639 value = retrive_fun()
640 print choses, value
642 if value in choses:
643 i = choses.index(value)
644 cbox.set_active(i)
645 else:
646 print "WARNING: Unsupported value '%s'." % value
649 def set_line_prop_sbut(self, prop):
650 value = getattr(self, prop+'SpinButt').get_value()
651 self.set_line_prop(prop, value)
653 def set_line_prop_cbox(self, prop, choses=None):
655 text = getattr(self, prop+'ComboB').get_active_text()
657 if choses == None:
658 value = text[text.find('(') + 1]
659 elif text in choses.keys():
660 value = choses[text]
661 else:
662 print "WARNING: Unsupported value '%s'." % value
664 self.set_line_prop(prop, value)
666 def set_line_prop(self, prop, value):
667 if not self.allowReplot or self.selected_data is None: return
669 set_fun = getattr(self.selected_line, 'set_'+prop.lower())
670 set_fun(value)
671 self.callerApp.canvas.draw()
675 # GUI Callbacks
677 def on_treeview_cursor_changed(self, *args):
678 # Retrive the current plot/line reference
679 plot_index = self.treeView.get_cursor()[0][0]
680 self.selected_line = self.data[plot_index].yline[0]
681 self.selected_data = self.callerApp.data[plot_index]
683 # Update the plot with the current line/plot properties
684 self.allowReplot = False
685 self.update_properties()
686 self.allowReplot = True
688 def on_lineWidth_value_changed(self, *args):
689 self.set_line_prop_sbut('lineWidth')
691 def on_lineStyle_changed(self, *args):
692 self.set_line_prop_cbox('lineStyle', choses=self.line_stylesd)
694 def on_lineColor_changed(self, *args):
695 self.set_line_prop_cbox('color')
697 def on_markerType_changed(self, *args):
698 self.set_line_prop_cbox('marker')
700 def on_markerSize_value_changed(self, *args):
701 self.set_line_prop_sbut('markerSize')
703 def on_markerEdgeWidth_value_changed(self, *args):
704 self.set_line_prop_sbut('markerEdgeWidth')
706 def on_markerEdgeColor_changed(self, *args):
707 self.set_line_prop_cbox('markerEdgeColor')
709 def on_markerFaceColor_changed(self, *args):
710 self.set_line_prop_cbox('markerFaceColor')
713 def on_cancelButton_clicked(self, widget, *args):
714 # Restore the old style
715 for orig_line, d in zip(self.orig_lines, self.data):
716 d.yline[0].update_from(orig_line[0])
717 d.linestyle = orig_line[1]
718 d.marker = orig_line[2]
720 self.callerApp.canvas.draw()
721 self.window.destroy()
723 def on_okButton_clicked(self, widget, *args):
724 self.window.destroy()
727 class TitleAndAxesWindow(DialogWindowWithCancel):
729 Dialog for setting Title and axes labels.
731 def __init__(self, callerApp):
732 DialogWindowWithCancel.__init__(self, 'TitleAndAxesWindow', gladefile,
733 callerApp)
735 self.titleEntry = self.widgetTree.get_widget('titleEntry')
736 self.xlabelEntry = self.widgetTree.get_widget('xlabelEntry')
737 self.ylabelEntry = self.widgetTree.get_widget('ylabelEntry')
739 # Update the entries with the current values
740 def sync(field, entry):
741 if field != None: entry.set_text(field)
743 sync(self.callerApp.title, self.titleEntry)
744 sync(self.callerApp.xlabel, self.xlabelEntry)
745 sync(self.callerApp.ylabel, self.ylabelEntry)
747 def on_okButton_clicked(self, widget, *args):
748 print "OK Clicked"
749 self.callerApp.axis.set_title(self.titleEntry.get_text())
750 self.callerApp.axis.set_xlabel(self.xlabelEntry.get_text())
751 self.callerApp.axis.set_ylabel(self.ylabelEntry.get_text())
752 self.callerApp.canvas.draw()
754 self.callerApp.title = self.titleEntry.get_text()
755 self.callerApp.xlabel = self.ylabelEntry.get_text()
756 self.callerApp.ylabel = self.xlabelEntry.get_text()
758 self.window.destroy()
760 class DimentionAndResolution(DialogWindowWithCancel):
762 Dialog for setting Figure dimentions and resolution.
764 def __init__(self, callerApp):
765 DialogWindowWithCancel.__init__(self, 'DimentionsDialog', gladefile,
766 callerApp)
767 self.xdimSpinButton = self.widgetTree.get_widget('xdimSpinButton')
768 self.ydimSpinButton = self.widgetTree.get_widget('ydimSpinButton')
769 self.resolutionSpinButton = self.widgetTree.get_widget(
770 'resolutionSpinButton')
771 self.inchesRadioB = self.widgetTree.get_widget('inRadioButton')
773 self.xdim_o, self.ydim_o = self.callerApp.figure.get_size_inches()
774 self.dpi_o = self.callerApp.figure.get_dpi()
776 self.set_initial_values()
778 def set_values(self, xdim, ydim, dpi):
779 if not self.inchesRadioB.get_active():
780 xdim *= CM_PER_INCHES
781 ydim *= CM_PER_INCHES
782 self.xdimSpinButton.set_value(xdim)
783 self.ydimSpinButton.set_value(ydim)
784 self.resolutionSpinButton.set_value(dpi)
786 def set_initial_values(self):
787 self.set_values(self.xdim_o, self.ydim_o, self.dpi_o)
789 def set_default_values(self):
790 xdim, ydim = rcParams['figure.figsize']
791 dpi = rcParams['figure.dpi']
792 self.set_values(xdim, ydim, dpi)
794 def get_values(self):
795 self.xdim = self.xdimSpinButton.get_value()
796 self.ydim = self.ydimSpinButton.get_value()
797 self.resolution = self.resolutionSpinButton.get_value()
798 if not self.inchesRadioB.get_active():
799 self.xdim /= CM_PER_INCHES
800 self.ydim /= CM_PER_INCHES
802 def set_figsize(self):
803 self.callerApp.figure.set_size_inches(self.xdim, self.ydim)
804 self.callerApp.figure.set_dpi(self.resolution)
806 def on_unity_toggled(self, widget, *args):
807 xdim = self.xdimSpinButton.get_value()
808 ydim = self.ydimSpinButton.get_value()
809 if self.inchesRadioB.get_active():
810 xdim /= CM_PER_INCHES
811 ydim /= CM_PER_INCHES
812 else:
813 xdim *= CM_PER_INCHES
814 ydim *= CM_PER_INCHES
815 self.xdimSpinButton.set_value(xdim)
816 self.ydimSpinButton.set_value(ydim)
818 def on_okButton_clicked(self, widget, *args):
819 print "OK"
820 self.get_values()
821 self.set_figsize()
822 self.callerApp.canvas.draw()
823 self.window.destroy()
825 def on_restoreButton_clicked(self, widget, *args):
826 self.set_default_values()
829 class OpenFileDialog(GenericOpenFileDialog):
831 This class implements the "Open File" dialog.
833 def __init__(self, callerApp):
834 GenericOpenFileDialog.__init__(self, 'OpenFileDialog', gladefile,
835 callerApp)
836 self.window.hide()
838 def openSelectedFile(self):
839 loaded = self.callerApp.load( self.filename )
840 if loaded:
841 self.callerApp.plot_data(-1)
842 self.window.hide()
844 def on_cancelButton_clicked(self, widget, *args):
845 self.window.hide()
846 return True
850 class AboutDialog(GenericSecondaryWindow):
852 Object for the "About Dialog".
854 def __init__(self):
855 GenericSecondaryWindow.__init__(self, 'AboutDialog', gladefile)
856 self.window.set_version(read_version(rootdir))
857 self.window.connect("response", lambda d, r: d.destroy())
860 # Functions
862 def test():
863 x = arange(100)
864 y = sin(x/10.0)
865 p = PlotFileApp(x, y, title='Random Sequence', debug=True)
866 p.start()
868 def main():
869 p = PlotFileApp(debug=True)
870 # Try to open a sample file
871 if len(sys.argv) < 2 and os.path.isfile(sourcedir+'samples/data.txt'):
872 p.load(sourcedir+'samples/data.txt')
873 p.plot()
874 p.start()
876 if __name__ == '__main__': main()