/[ascend]/branches/ksenija2/pygtk/observer.py
ViewVC logotype

Contents of /branches/ksenija2/pygtk/observer.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2866 - (show annotations) (download) (as text)
Sun Mar 22 13:18:17 2015 UTC (7 years, 4 months ago) by jpye
File MIME type: text/x-python
File size: 31628 byte(s)
tried changing plot line-style to remove the markers. we might want to revert this.

1 import pygtk
2 pygtk.require('2.0')
3 import gtk
4 import pango
5 import os.path
6
7 from study import *
8 from unitsdialog import *
9
10 OBSERVER_EDIT_COLOR = "#008800"
11 OBSERVER_NOEDIT_COLOR = "#000088"
12 OBSERVER_NORMAL_COLOR = "black"
13 OBSERVER_TAINTED_COLOR = "#FFBBBB"
14 OBSERVER_DEAD_COLOR = "#ababab"
15 # This code uses the techniques described in
16 # http://www.daa.com.au/pipermail/pygtk/2006-February/011777.html
17 # http://piman.livejournal.com/361173.html
18
19 OBSERVER_NUM=0
20
21 class ClickableTreeColumn(gtk.TreeViewColumn):
22 def __init__(self, title="", *args, **kwargs):
23 super(ClickableTreeColumn, self).__init__(None, *args, **kwargs)
24 self.label = gtk.Label("%s" % title)
25 self.label.show()
26 self.set_widget(self.label)
27 self.title = title
28 #self.set_sort_column_id(0)
29 #self.set_clickable(True)
30
31 def do_connect(self):
32 """ Connect the defined 'on_click' method. Note: must be called after
33 this object (ClickableTreeColumn) has been added to the TreeView,
34 eg mytreeview.append_column(col). """
35 button = self.label.get_ancestor(gtk.Button)
36 h = button.connect("clicked",self.on_click)
37 #button.clicked()
38
39 def on_click(self,widget,*args):
40 print "RECEIVED EVENT"
41
42 class ObserverColumn:
43 """
44 A class to identify the instance that relates to a specify column
45 and the units of measurement and column title, etc.
46 """
47 def __init__(self,instance,index,name=None,units=None,browser=None,eventdata=None):
48 self.instance = instance
49 self.name = name
50 self.index = index
51
52 if name==None:
53 if browser == None:
54 name = "UNNAMED"
55 else:
56 name = browser.sim.getInstanceName(instance)
57
58 if units is None:
59 units = instance.getType().getPreferredUnits()
60 if units is None:
61 units = instance.getType().getDimensions().getDefaultUnits()
62
63 uname = str(units.getName())
64 if len(uname) or uname.find("/")!=-1:
65 uname = "["+uname+"]"
66
67 if uname == "":
68 _title = "%s" % (name)
69 else:
70 _title = "%s / %s" % (name, uname)
71
72 self.title = _title
73 self.units = units
74 self.uname = uname
75 self.name = name
76 self.eventdata = eventdata
77
78 def __repr__(self):
79 return "ObserverColumn(name="+self.name+")"
80
81 def cellvalue(self, column, cell, model, row_iter, user_data=None):
82 _rowobject = model.get_value(row_iter,0)
83
84 cell.set_property('editable',False)
85 cell.set_property('weight',400)
86 try:
87 if _rowobject.active or _rowobject.dead:
88 _rawval = self.instance.getRealValue()
89 if self.instance.getType().isRefinedSolverVar():
90 if self.instance.isFixed():
91 cell.set_property('editable',True)
92 cell.set_property('weight',700)
93 cell.set_property('foreground',OBSERVER_EDIT_COLOR)
94 else:
95 cell.set_property('foreground',OBSERVER_NOEDIT_COLOR)
96 _dataval = _rawval / self.units.getConversion()
97 else:
98 cell.set_property('foreground',OBSERVER_NORMAL_COLOR)
99 try :
100 _rawval = _rowobject.values[self.index]
101 _dataval = _rawval / self.units.getConversion()
102 except:
103 _dataval = ""
104 if _rowobject.tainted is True:
105 cell.set_property('background', OBSERVER_TAINTED_COLOR)
106 elif _rowobject.dead or user_data == True:
107 cell.set_property('background', OBSERVER_DEAD_COLOR)
108 cell.set_property('editable', False)
109 else:
110 cell.set_property('background', None)
111 except IndexError:
112 _dataval = ""
113
114 cell.set_property('text', _dataval)
115
116 class ObserverRow:
117 """
118 Just a container for a vector of values, but with columns that
119 should correspond to those in the Observer object's vector of
120 ObserverColumn objects.
121 """
122 def __init__(self,values=None,active=True,tainted=False):
123 if values==None:
124 values={}
125 self.tainted = tainted
126 self.values = values
127 self.active = active
128 self.dead = False
129 self.error_msg = None
130
131 def make_static(self,table):
132 self.active = False
133 #print "TABLE COLS:",table.cols
134 #print "ROW VALUES:",self.values
135 _v = {}
136 for col in table.cols.values():
137 _v[col.index] = col.instance.getRealValue()
138 self.values = _v
139 #print "Made static, values:",self.values
140
141 def get_values(self,table):
142 vv = {}
143 if not self.active:
144 for k,v in table.cols.iteritems():
145 try:
146 vv[k]=(self.values[v.index]/v.units.getConversion())
147 except:
148 vv[k]=""
149 return vv
150 else:
151 for index, col in table.cols.iteritems():
152 vv[index] = float(col.instance.getRealValue())/col.units.getConversion()
153 return vv
154
155 class ObserverTab:
156
157 def __init__(self,browser,tab,name=None,alive=True):
158 global OBSERVER_NUM
159 self.colindex = 0
160 if name==None:
161 OBSERVER_NUM=OBSERVER_NUM+1
162 name = "Observer %d" % OBSERVER_NUM
163 self.name = name
164 self.browser=browser
165 self.browser.builder.connect_signals(self)
166 self.view = self.browser.builder.get_object('observerview')
167 self.view.set_has_tooltip(True)
168 self.addbutton = self.browser.builder.get_object('add')
169 self.tab = tab
170 self.alive=alive
171 self.reloaded = False
172 self.old_path = None
173 self.current_instance = None
174 if self.alive:
175 self.browser.reporter.reportNote("New observer is 'alive'")
176
177 self.keptimg = gtk.Image()
178 self.activeimg = gtk.Image()
179 self.errorimg = gtk.Image()
180 self.activeimg.set_from_file(os.path.join(browser.options.assets_dir,"active.png"))
181 self.errorimg.set_from_file(os.path.join(browser.options.assets_dir,"solveerror.png"))
182 # create PixBuf objects from these?
183 self.rows = []
184 _store = gtk.TreeStore(object)
185 self.cols = {}
186 self.tvcols = {}
187 self.renderers = {}
188
189 # create the 'active' pixbuf column
190 _renderer = gtk.CellRendererPixbuf()
191 _col = ClickableTreeColumn("")
192 _col.pack_start(_renderer,False)
193 _col.set_cell_data_func(_renderer, self.activepixbufvalue)
194 self.view.append_column(_col)
195 _col.do_connect()
196
197 # get the context menu
198 self.treecontext=self.browser.builder.get_object("observercontext")
199 self.studycolumnmenuitem=self.browser.builder.get_object("study_column")
200 self.unitsmenuitem=self.browser.builder.get_object("units2")
201 self.deleterowmenuitem=self.browser.builder.get_object("delete_row")
202 self.deletecolumnmenuitem=self.browser.builder.get_object("delete_column")
203 self.plotmenuitem=self.browser.builder.get_object("plotmenuitem")
204 self.columnplotevents=self.browser.builder.get_object("column_plot_events")
205 # initially there will not be any other columns
206
207 if self.alive:
208 # for a 'live' Observer, create the 'active' bottom row
209 self.browser.reporter.reportNote("Adding empty row to store")
210 _row = ObserverRow()
211 self.activeiter = _store.append(None, [_row] )
212 self.rows.append(_row)
213 else:
214 self.activeiter = None
215
216 self.view.set_model(_store)
217 self.browser.reporter.reportNote("Created observer '%s'" % self.name)
218
219 _sel = self.view.get_selection()
220 _sel.set_mode(gtk.SELECTION_MULTIPLE)
221
222 def activepixbufvalue(self,column,cell,model,iter):
223 _rowobject = model.get_value(iter,0)
224 if _rowobject.active:
225 cell.set_property('pixbuf',self.activeimg.get_pixbuf())
226 elif _rowobject.tainted:
227 cell.set_property('pixbuf',self.errorimg.get_pixbuf())
228 else:
229 cell.set_property('pixbuf',self.keptimg.get_pixbuf())
230
231 def on_add_clicked(self,*args):
232 self.do_add_row()
233
234 def on_clear_clicked(self,*args):
235 if self.alive is False:
236 self.on_close_observer_clicked()
237 return
238 _store = self.view.get_model()
239 _store.clear();
240 self.rows = []
241 _row = ObserverRow()
242 self.activeiter = _store.append(None, [_row] )
243 self.rows.append(_row)
244
245 def plot(self,x=None,y=None):
246 """Create a plot from specified columns in the ObserverTable
247
248 There will be points for each timestep in the 'samplelist', and also
249 points for each event/boundary-crossing if any occurred.
250 """
251 import platform
252 import matplotlib
253 matplotlib.use('GTKAgg')
254 import pylab
255 pylab.ioff()
256
257 # nothing provided: use the first and second columns
258 if x is None or y is None:
259 if len(self.cols)<2:
260 raise Exception("Not enough columns to plot (need 2+)")
261 if x is None:
262 x=self.cols[0]
263 if y is None:
264 y=[self.cols[1]]
265
266 # if column indices are provided instead of columns, convert them
267 if x.__class__ is int and x>=0 and x<len(self.cols):
268 x=self.cols[x]
269 if y.__class__ is int and y>=0 and y<len(self.cols):
270 y=[self.cols[y]]
271
272 start = None
273 _p = self.browser.prefs
274 _ignore = _p.getBoolPref("PlotDialog", "ignore_error_points", True)
275 r = {}
276 # FIXME this is not nicely written; we need to collapse the follow if/else
277 # cases into a single bit of code.
278 if _ignore == False:
279 # get all rows, including ones that didn't solve properly
280 for i in range(len(self.rows)):
281 try:
282 r = self.rows[i].get_values(self)
283 # flag if any row are empty -- no data? FIXME why would that happen?
284 flag = True
285 for j in y:
286 if r[j.index]=="":
287 flag = False
288 break
289 if r[x.index]!="" and flag==True:
290 if start == None:
291 start = i
292 break
293 except:
294 continue
295 if start == None:
296 self.browser.reporter.reportError("Can't plot, could not get enough points.")
297 return
298 A = pylab.zeros((len(self.rows)-1-start,len(y)+1),'f')
299 i = 0
300 j = start
301 while j <len(self.rows)-1:
302 r = self.rows[j].get_values(self)
303 A[i,0]=r[x.index]
304 for k in range(len(y)):
305 A[i,k+1]=r[y[k].index]
306 j+=1
307 i+=1
308 else:
309 # ignore error points: get just the non-error rows
310 j = 0
311 k = 0
312 l = 0
313 # count the error-free rows (FIXME: why aren't we just checking the 'tainted' property??)
314 for i in range(len(self.rows)-1):
315 if self.rows[i].tainted is False:
316 try:
317 r = self.rows[i].get_values(self)
318 flag = True
319 for l in y:
320 if r[l.index]=="":
321 flag = False
322 break
323 if r[x.index]!="" and flag == True:
324 if start == None:
325 start = i
326 j=0
327 j+=1
328 except:
329 continue
330 if start == None:
331 self.browser.reporter.reportError("Can't plot, could not get enough points.")
332 return
333 A = pylab.zeros((j,len(y)+1),'f')
334 while start<len(self.rows)-1:
335 if self.rows[start].tainted is True:
336 start+=1
337 continue
338 r = self.rows[start].get_values(self)
339 A[k,0]=r[x.index]
340 for j in range(len(y)):
341 A[k,j+1]=r[y[j].index]
342 k+=1
343 start+=1
344
345 fig = pylab.figure()
346
347 if len(y) == 2:
348 # two y vectors: use two different y axes on one plot
349 ax1 = pylab.subplot(111)
350 # TODO: second y axis label gets cut off?
351 #pylab.axis('auto')
352 ax1.set_xlabel(x.title)
353 ax1.set_ylabel(y[0].title,labelpad=20)
354 l1 = ax1.plot(A[:,0],A[:,1],'-bo',label=y[0].title)
355 ax2 = ax1.twinx()
356 l2 = ax2.plot(A[:,0],A[:,2],'-ro',label=y[1].title)
357 ax2.set_ylabel(y[1].title,labelpad=20)
358 ax2.yaxis.tick_right()
359 l = l1+l2
360 labels = [i.get_label() for i in l]
361 leg = ax1.legend(l,labels,loc='upper left')
362 leg.get_frame().set_alpha(0.3)
363 leg.draggable() #doesn't work?
364 #FIXME the events haven't been plotted in this case
365 else :
366 _colcyc = ['r','g','b','y','m','c']
367 _ncc = len(_colcyc)
368 sharex = None
369 j = 0.83/len(y)
370 for i in range(len(y)):
371 if i == 0:
372 ax = pylab.subplot(len(y),1,i+1)
373 sharex = ax
374 else:
375 ax = pylab.subplot(len(y),1,i+1,sharex=sharex)
376 #ax[i] = fig.add_axes([0.27, 0.08+(i*(j+0.02)), 0.65, j-0.01], **axprops)
377 if y[i].eventdata:
378 # FIXME the 'get_values' function used above does unit conversion
379 # but this 'eventdata' (hack!) doesn't do that, which breaks the plots
380 # when there are non-base-SI units used in the Observer.
381 arrx = []
382 arry = []
383 for _vals in y[i].eventdata:
384 arry.append(_vals[1])
385 for _vals in x.eventdata:
386 arrx.append(_vals[1])
387
388 pylab.plot(A[:,0],A[:,i+1],'-',color=_colcyc[i%_ncc],marker='',lw=2,label=y[i].title)
389 pylab.plot(arrx,arry,'s',color='black')
390 else:
391 pylab.plot(A[:,0],A[:,i+1],'-',color=_colcyc[i%_ncc],market='o',label=y[i].title)
392
393 # put the x-axis label only on the last plot
394 if i+1 != len(y):
395 pylab.setp(ax.get_xticklabels(),visible=False)
396 else:
397 ax.set_xlabel(x.title)
398
399 # only use a y-axis label if it's a single plot, else put legend on each plot
400 if len(y)==1:
401 pylab.ylabel(y[i].title)
402 else:
403 leg = pylab.legend(loc='upper left')
404 leg.get_frame().set_alpha(0.3)
405
406 # FIXME why can't I drag the legend?
407
408 pylab.ion()
409 pylab.show()
410
411 def on_plot_clicked(self,*args):
412 """This is the 'plot' button at the top of the observer tab"""
413 try:
414 if len(self.cols)<2:
415 raise Exception("Not enough columns to plot (need 2+)")
416 _plotwin = PlotDialog(self.browser, self)
417 _plot = _plotwin.run()
418 if _plot:
419 self.plot(x=_plotwin.xcol, y=_plotwin.ycol)
420 except Exception,e:
421 self.browser.reporter.reportError(str(e))
422
423 def do_add_row(self,values=None):
424 _store = self.view.get_model()
425 if self.alive:
426 _row = ObserverRow()
427 self.rows.append(_row)
428 if self.activeiter is not None:
429 _oldrow = _store.get_value(self.activeiter,0)
430 _oldrow.make_static(self)
431 self.activeiter = _store.append(None,[_row])
432 _path = _store.get_path(self.activeiter)
433 _oldpath,_oldcol = self.view.get_cursor()
434 self.view.set_cursor(_path, _oldcol)
435 else:
436 _row = ObserverRow(values=values,active=False,tainted=False)
437 self.rows.append(_row)
438 _store.append(None,[_row])
439 #self.browser.reporter.reportNote("Added data row")
440
441 def on_view_cell_edited(self, renderer, path, newtext, col):
442 # we can assume it's always the self.activeiter that is edited...
443 if col.instance.isFixed():
444 val = float(newtext) * col.units.getConversion()
445 col.instance.setRealValue( val )
446 self.browser.reporter.reportNote("Updated value to %f" % float(newtext))
447 else:
448 self.browser.reporter.reportError("Can't set a FREE variable from the Observer")
449 return
450 self.browser.do_solve_if_auto()
451
452 def sync(self):
453 self.view.queue_draw()
454 #self.browser.reporter.reportNote("SYNC performed")
455
456 def add_instance(self,instance,edata=None):
457 _col = ObserverColumn(instance,self.colindex,browser=self.browser,eventdata=edata)
458
459 # the loop is to ensure that we dont add multiple columns for the same variable
460 for _cols in self.cols:
461 if self.cols[_cols].title == _col.title:
462 del(_col)
463 return
464 self.cols[self.colindex] = _col
465 self.colindex = self.colindex + 1
466
467 # create a new column
468 _renderer = gtk.CellRendererText()
469 _renderer.connect('edited',self.on_view_cell_edited, _col)
470 _tvcol = ClickableTreeColumn(_col.title)
471 _tvcol.pack_start(_renderer,False)
472 self.tvcols[self.colindex-1] = _tvcol
473 self.renderers[self.colindex-1] = _renderer
474 _tvcol.set_cell_data_func(_renderer, _col.cellvalue)
475 self.view.append_column(_tvcol);
476 _tvcol.do_connect()
477 #self.browser.reporter.reportError("cols = "+str(self.cols))
478
479 def copy_to_clipboard(self,clip):
480 _s = []
481 _s.append('\t'.join([_v.title for _k,_v in self.cols.iteritems()]))
482 #_cf = [_v.units.getConversion() for _k,_v in self.cols.iteritems()]
483 print "COPYING %d ROWS" % len(self.rows)
484 #print "CONVERSIONS:",_cf
485 for _r in self.rows:
486 _s.append("\t".join(["%s" % _v for _k, _v in _r.get_values(self).iteritems()]))
487
488 clip.set_text('\n'.join(_s),-1)
489
490 self.browser.reporter.reportNote("Observer '%s' data copied to clipboard" % self.name)
491
492 def on_observerview_query_tooltip(self, widget, _x, _y, keyboard_mode, _tooltip):
493 _store = self.view.get_model()
494 _pthinfo = self.view.get_path_at_pos(_x, _y)
495
496 if _pthinfo is None:
497 return False
498 _path, _col, _cellx, _celly = _pthinfo
499 _temp, = _path
500 if(_temp==0):
501 return False
502 _path = _temp-1,
503
504 # the folowing is to ensure that the tooltip
505 # gets refreshed for each row
506 if self.old_path == _path:
507 _iter = _store.get_iter(_path)
508 _rowobject = _store.get_value(_iter,0)
509 if _rowobject.error_msg is None:
510 return False
511 _tooltip.set_text(_rowobject.error_msg)
512 return True
513 else:
514 self.old_path = _path
515 return False
516
517 def set_all_menu_items_sensitive(self):
518 self.unitsmenuitem.set_sensitive(True)
519 self.studycolumnmenuitem.set_sensitive(True)
520 self.plotmenuitem.set_sensitive(True)
521 self.deletecolumnmenuitem.set_sensitive(True)
522 self.columnplotevents.set_sensitive(True)
523
524 def on_treeview_event(self,widget,event):
525
526 _path = None
527 _delete_row = False
528 _contextmenu = False
529
530 _sel = self.view.get_selection()
531 _model, _rowlist = _sel.get_selected_rows()
532 if event.type==gtk.gdk.KEY_PRESS:
533 _keyval = gtk.gdk.keyval_name(event.keyval)
534 _path, _col = self.view.get_cursor()
535 if _path is not None:
536 if _keyval=='Menu':
537 self.set_all_menu_items_sensitive()
538 _contextmenu = True
539 _button = 3
540 elif _keyval=='Delete' or _keyval=='BackSpace':
541 _delete_row = True
542
543 elif event.type==gtk.gdk.BUTTON_PRESS:
544 _x = int(event.x)
545 _y = int(event.y)
546 _button = event.button
547 _pthinfo = self.view.get_path_at_pos(_x, _y)
548 if _pthinfo is not None:
549 _path, _col, _cellx, _celly = _pthinfo
550 if event.button == 3:
551 self.set_all_menu_items_sensitive()
552 _contextmenu = True
553
554 if not (_contextmenu or _delete_row):
555 #print "NOT DOING ANYTHING ABOUT %s" % gtk.gdk.keyval_name(event.keyval)
556 return
557
558 if len(_rowlist)>1:
559 self.unitsmenuitem.set_sensitive(False)
560 self.studycolumnmenuitem.set_sensitive(False)
561 self.plotmenuitem.set_sensitive(False)
562 self.deletecolumnmenuitem.set_sensitive(False)
563 if _delete_row:
564 self.on_delete_row()
565 return True
566 self.treecontext.popup( None, None, None, _button, event.time)
567 return
568
569 self.view.grab_focus()
570 self.view.set_cursor( _path, _col, 0)
571
572 self.current_path = _path
573 self.current_col = _col
574 self.current_instance = None
575 if _delete_row:
576 self.on_delete_row()
577 elif self.alive is False:
578 self.unitsmenuitem.set_sensitive(False)
579 self.studycolumnmenuitem.set_sensitive(False)
580 self.treecontext.popup( None, None, None, _button, event.time)
581 else:
582 # Since we have the instance data in self.cols and treeview points us to the
583 # ClickableTreeColumn, we need to match the two.
584 for _cols in self.cols:
585 if self.cols[_cols].title == self.current_col.title:
586 self.current_instance = self.cols[_cols].instance
587 self.current_col_key = _cols
588 break
589 if self.current_instance is None:
590 return 0
591 if self.current_instance.isFixed() == False:
592 self.studycolumnmenuitem.set_sensitive(False)
593 self.treecontext.popup( None, None, None, _button, event.time)
594 return 1
595
596 def on_study_column_activate(self, *args):
597 if self.current_instance is not None:
598 _dia = StudyWin(self.browser,self.current_instance)
599 _dia.run()
600
601 def on_delete_row(self, *args):
602 # We need to remove the row from two places,
603 # the treestore, and our own list of ObserverRows
604
605 _sel = self.view.get_selection()
606 _store, _rowlist = _sel.get_selected_rows()
607 i = 0
608 (x,) = _rowlist[0]
609 for _path in _rowlist:
610 if len(self.rows) == x+1:
611 self.browser.reporter.reportWarning("Can't delete the active row")
612 return
613 self.rows.pop(x)
614 _store.remove(_store.get_iter((x,)))
615
616 # now that we have deleted the row, it is
617 # time to move the cursor to the next available element
618
619 self.view.grab_focus()
620 self.view.set_cursor((x,), self.current_col, 0)
621
622 def taint_row(self, msg, _rowobject = None):
623 # to set the solver error message as the row's tooltip
624 _store = self.view.get_model()
625 if _rowobject is None:
626 _rowobject = _store.get_value(self.activeiter,0)
627 _rowobject.error_msg = msg
628 _rowobject.tainted = True
629
630 def on_delete_column(self, *args):
631 # To delete columns
632 for _col in self.cols:
633 if self.cols[_col].title == self.current_col.title:
634 current_col_key = _col
635 self.cols.pop(current_col_key)
636 self.view.remove_column(self.current_col)
637
638 def on_column_plot_events(self, *args):
639 for _col in self.cols:
640 if self.cols[_col].title == self.current_col.title:
641 current_col_key = _col
642 _plotwin = ColPlotEventsDialog(self.browser, self)
643 _plot = _plotwin.run()
644 if _plot:
645 self.plot_event(x=self.cols[current_col_key], t=_plotwin.col, title = self.cols[0].title)
646
647 def plot_event(self, x, t, title):
648 """Plot internal details of event handling for an individual variable"""
649 import platform
650 import matplotlib
651 matplotlib.use('GTKAgg')
652 import pylab
653 pylab.ioff()
654
655 vals = []
656 for x1, x2 in x.eventdata:
657 if x1 == t:
658 vals.append(x2)
659 pylab.xlim(-1,len(vals))
660 vmin = min(vals)
661 vmax = max(vals)
662 pylab.ylim(vmin-1,vmax+1)
663 pylab.plot(vals,'rD')
664 pylab.suptitle("0 - before crossing the boundary,\n1 - after the first call of the logical solver,\n2 - after solving the boundary equations,\n3+ - added if solving the system changes the values of some boolean vars.",bbox={'facecolor':'green', 'alpha':0.5, 'pad':10})
665 pylab.xlabel(title + ' = ' + str(t))
666 pylab.ylabel(x.title)
667 pylab.tight_layout(pad = 7)
668 pylab.ion()
669 pylab.show()
670
671 def on_plotmenuitem_activate(self, *args):
672 # To preselect the column as y axis
673 try:
674 if len(self.cols)<2:
675 raise Exception("Not enough columns to plot (need 2+)")
676 _plotwin = PlotDialog(self.browser, self)
677 _plotwin.select_ycol(self.cols[self.current_col_key], self)
678 _plot = _plotwin.run()
679 if _plot:
680 self.plot(x=_plotwin.xcol, y=_plotwin.ycol)
681 except Exception,e:
682 self.browser.reporter.reportError(str(e))
683
684 def on_close_observer_clicked(self, *args):
685 # First, the dialog box is brought up, and if the user clicks on yes,
686 # the observer tab is closed. Need to make sure that this instance is
687 # removed from the list of observers maintained in the browser
688
689 _alertwin = CloseDialog(self.browser)
690 destroy = _alertwin.run()
691 if destroy:
692 self.view.destroy()
693 if self.browser.currentobservertab == self.browser.currentpage:
694 self.browser.currentobservertab = None
695 self.browser.maintabs.remove_page(self.browser.currentpage)
696 self.rows = []
697 self.browser.observers.remove(self)
698
699 def on_units_activate(self, *args):
700 if self.current_instance is not None:
701 T = self.current_instance.getType()
702 _un = UnitsDialog(self.browser,T)
703 _un.run()
704
705 def units_refresh(self, instance_type):
706 for _col in self.cols.values():
707 _units = None
708 _units = instance_type.getPreferredUnits()
709 if _units is None:
710 _units = instance_type.getDimensions().getDefaultUnits()
711 _uname = str(_units.getName())
712
713 _col_type = _col.instance.getType()
714 _col_units = _col_type.getPreferredUnits()
715 if _col_units is None:
716 _col_units = _col_type.getDimensions().getDefaultUnits()
717 _col_uname = str(_col_units.getName())
718
719 if _col_uname == _uname:
720 if self.browser == None:
721 name = "UNNAMED"
722 else:
723 name = self.browser.sim.getInstanceName(_col.instance)
724
725 _uname = str(_units.getName())
726 if len(_uname) or _uname.find("/")!=-1:
727 _uname = "["+_uname+"]"
728
729 if _uname == "":
730 _title = "%s" % (name)
731 else:
732 _title = "%s / %s" % (name, _uname)
733 for _tvcol in self.view.get_columns():
734 if _tvcol.title == _col.title:
735 _tvcol.label.set_text(str(_title))
736 _tvcol.title = _title
737 _tvcol.set_title(_title)
738 _col.title = _title
739 _col.units = _units
740 _col.uname = _uname
741 _col.name = name
742 def set_dead(self):
743 if self.alive == False and self.reloaded == True:
744 for i in range(self.colindex):
745 col = self.cols[i]
746 renderer = self.renderers[i]
747 tvcol = self.tvcols[i]
748 tvcol.set_cell_data_func(renderer, None)
749 tvcol.set_cell_data_func(renderer, col.cellvalue, True)
750 self.alive = False
751 self.addbutton.set_sensitive(False)
752 _selection = self.view.get_selection()
753 _selection.unselect_all()
754 _store = self.view.get_model()
755 if self.activeiter is not None:
756 _rowobject = _store.get_value(self.activeiter,0)
757 _rowobject.active = False
758 _rowobject.dead = True
759 self.activeiter = None
760
761 class CloseDialog:
762
763 # Just a dialog to confirm that the user REALLY wants to close
764 # the observer
765
766 def __init__(self, browser):
767 browser.builder.add_objects_from_file(browser.glade_file, ["closeobserverdialog"])
768 self.alertwin = browser.builder.get_object("closeobserverdialog")
769 browser.builder.connect_signals(self)
770
771 def on_closeobserverdialog_close(self,*args):
772 self.alertwin.response(gtk.RESPONSE_CLOSE)
773
774 def run(self):
775 _continue = True
776 while _continue:
777 _res = self.alertwin.run()
778 if _res == gtk.RESPONSE_YES:
779 self.alertwin.destroy()
780 return True
781 else:
782 self.alertwin.destroy()
783 return False
784
785 class PlotDialog:
786
787 # a dialog where the user can select which columns to plot
788
789 def __init__(self, browser, tab):
790 self.browser = browser
791 self.browser.builder.add_objects_from_file(browser.glade_file, ["plotdialog"])
792 self.plotwin = self.browser.builder.get_object("plotdialog")
793 self.plotbutton = self.browser.builder.get_object("plotbutton")
794 self.xview = self.browser.builder.get_object("treeview1")
795 self.yview = self.browser.builder.get_object("treeview2")
796 self.yview.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
797 self.ignorepoints = self.browser.builder.get_object("ignorepoints")
798
799 _p = self.browser.prefs
800 _ignore = _p.getBoolPref("PlotDialog", "ignore_error_points", True)
801 self.ignorepoints.set_active(_ignore)
802
803 _xstore = gtk.TreeStore(object)
804 self.xview.set_model(_xstore)
805 _xrenderer = gtk.CellRendererText()
806 _xtvcol = gtk.TreeViewColumn("X axis")
807 _xtvcol.pack_start(_xrenderer,False)
808 _xtvcol.set_cell_data_func(_xrenderer, self.varlist)
809 self.xview.append_column(_xtvcol)
810
811 _ystore = gtk.TreeStore(object)
812 self.yview.set_model(_ystore)
813 _yrenderer = gtk.CellRendererText()
814 _ytvcol = gtk.TreeViewColumn("Y axis")
815 _ytvcol.pack_start(_yrenderer,False)
816 _ytvcol.set_cell_data_func(_yrenderer, self.varlist)
817 self.yview.append_column(_ytvcol)
818
819 self.xcol = None
820 self.ycol = None
821 for _cols in tab.cols:
822 _xtemp = _xstore.append(None, [tab.cols[_cols]])
823 _ytemp = _ystore.append(None, [tab.cols[_cols]])
824 if self.xcol is None:
825 self.xcol = tab.cols[_cols]
826 _xiter = _xtemp
827 continue
828 if self.ycol is None:
829 self.ycol = tab.cols[_cols]
830 _yiter = _ytemp
831 self.plotbutton.set_sensitive(True)
832
833 _selx = self.xview.get_selection()
834 _selx.select_iter(_xiter)
835
836 _sely = self.yview.get_selection()
837 _sely.select_iter(_yiter)
838
839 self.browser.builder.connect_signals(self)
840
841 def on_plotdialog_close(self,*args):
842 self.plotwin.response(gtk.RESPONSE_CANCEL)
843
844 def varlist(self,column,cell,model,iter):
845 _value = model.get_value(iter,0)
846 cell.set_property('text', _value.title)
847
848 def on_treeview_event(self,widget,event):
849
850 _path = None
851 _col = None
852 self.plotbutton.set_sensitive(False)
853 if event.type==gtk.gdk.KEY_RELEASE:
854 _keyval = gtk.gdk.keyval_name(event.keyval)
855 if _keyval == "Escape":
856 self.plotwin.response(gtk.RESPONSE_CANCEL)
857 return
858 _path, _tvcol = widget.get_cursor()
859 if _path is None:
860 return
861
862 elif event.type==gtk.gdk.BUTTON_RELEASE:
863 _x = int(event.x)
864 _y = int(event.y)
865 _button = event.button
866 _pthinfo = widget.get_path_at_pos(_x, _y)
867 if _pthinfo is None:
868 return
869 _path, _tvcol, _cellx, _celly = _pthinfo
870 if _path is None:
871 return
872
873 _sel = widget.get_selection()
874 _view, path_list = _sel.get_selected_rows()
875 if path_list is None:
876 return
877 #_path = _view.get_path(_iter)
878 #_path = _iter[0]
879 #if _path is None:
880 # return
881 widget.grab_focus()
882 _store = widget.get_model()
883 #_selx = self.xview.get_selection()
884 #_sely = self.yview.get_selection()
885
886 #widget.set_cursor( _path, None, 0)
887 flag=True
888 for _path in path_list:
889 if _path is None:
890 return
891 _iter = _store.get_iter(_path)
892 _col = _store.get_value(_iter,0)
893 if widget is self.xview:
894 self.xcol = _col
895 #_selx.select_iter(_iter)
896 break
897 else:
898 if flag==True:
899 self.ycol = []
900 flag=False
901 self.ycol.append(_col)
902 #_sely.select_iter(_iter)
903
904 if self.ycol is not None and type(self.ycol)!=type([]) :
905 self.ycol = [self.ycol]
906
907 flag=True
908 if self.xcol is not None and self.ycol is not None:
909 for yitem in self.ycol:
910 if self.xcol.title == yitem.title:
911 flag=False
912 if widget is self.xview:
913 self.yview.get_selection().unselect_all()
914 self.ycol = None
915 else:
916 self.xview.get_selection().unselect_all()
917 self.xcol = None
918 break
919 if flag==True:
920 self.plotbutton.set_sensitive(True)
921
922 def select_ycol(self, _col, _tab):
923 _ystore = self.yview.get_model()
924 _iter = _ystore.get_iter_first()
925 for i in _tab.cols:
926 _item = _ystore.get_value(_iter, 0)
927 if _item.title == _col.title:
928 self.ycol = _col
929 _sel = self.yview.get_selection()
930 _sel.unselect_all()
931 _sel.select_iter(_iter)
932 self.xcol = None
933 self.xview.get_selection().unselect_all()
934 self.plotbutton.set_sensitive(False)
935 _iter = _ystore.iter_next(_iter)
936
937 def run(self):
938 _continue = True
939 while _continue:
940 _res = self.plotwin.run()
941 if _res == gtk.RESPONSE_YES:
942 _p = self.browser.prefs
943 _p.setBoolPref("PlotDialog", "ignore_error_points", self.ignorepoints.get_active())
944 self.plotwin.destroy()
945 if self.ycol is not None and type(self.ycol)!=type([]) :
946 self.ycol = [self.ycol]
947 return True
948 else:
949 self.plotwin.destroy()
950 return False
951
952 class ColPlotEventsDialog:
953
954 # a dialog where the user can select which events to plot
955 # FIXME: this window should be scrolled
956
957 def __init__(self, browser, tab):
958 self.browser = browser
959 self.browser.builder.add_objects_from_file(browser.glade_file, ["colploteventsdialog"])
960 self.plotwin = self.browser.builder.get_object("colploteventsdialog")
961 self.plotbutton = self.browser.builder.get_object("plotbutton")
962 self.view = self.browser.builder.get_object("treeview1")
963
964 _store = gtk.TreeStore(object)
965 self.view.set_model(_store)
966 _renderer = gtk.CellRendererText()
967 _tvcol = gtk.TreeViewColumn("t")
968 _tvcol.pack_start(_renderer,False)
969 _tvcol.set_cell_data_func(_renderer, self.vallist)
970 self.view.append_column(_tvcol)
971
972 self.col = None
973 tprev = tab.cols[0].eventdata[0]
974 for _vals in tab.cols[0].eventdata:
975 if _vals[0] != tprev:
976 _temp = _store.append(None,[_vals[0]])
977 tprev = _vals[0]
978 if self.col is None:
979 self.col = _vals[0]
980 _iter = _temp
981
982 self.browser.builder.connect_signals(self)
983
984 def on_colploteventsdialog_close(self,*args):
985 self.plotwin.response(gtk.RESPONSE_CANCEL)
986
987 def vallist(self,column,cell,model,iter):
988 _value = model.get_value(iter,0)
989 cell.set_property('text', _value)
990
991 def on_treeview_event(self,widget,event):
992 _path = None
993 _col = None
994 self.plotbutton.set_sensitive(False)
995 if event.type==gtk.gdk.KEY_RELEASE:
996 _keyval = gtk.gdk.keyval_name(event.keyval)
997 if _keyval == "Escape":
998 self.plotwin.response(gtk.RESPONSE_CANCEL)
999 return
1000 _path, _tvcol = widget.get_cursor()
1001 if _path is None:
1002 return
1003 elif event.type==gtk.gdk.BUTTON_RELEASE:
1004 _x = int(event.x)
1005 _y = int(event.y)
1006 _button = event.button
1007 _pthinfo = widget.get_path_at_pos(_x, _y)
1008 if _pthinfo is None:
1009 return
1010 _path, _tvcol, _cellx, _celly = _pthinfo
1011 if _path is None:
1012 return
1013
1014 _sel = widget.get_selection()
1015 _view, path_list = _sel.get_selected_rows()
1016 if path_list is None:
1017 return
1018 widget.grab_focus()
1019 _store = widget.get_model()
1020 flag=True
1021 for _path in path_list:
1022 if _path is None:
1023 return
1024 _iter = _store.get_iter(_path)
1025 _col = _store.get_value(_iter,0)
1026 if widget is self.view:
1027 self.col = _col
1028 break
1029
1030 flag=True
1031 if self.col is not None:
1032 self.plotbutton.set_sensitive(True)
1033
1034 def run(self):
1035 _continue = True
1036 while _continue:
1037 _res = self.plotwin.run()
1038 if _res == gtk.RESPONSE_YES:
1039 self.plotwin.destroy()
1040 return True
1041 else:
1042 self.plotwin.destroy()
1043 return False
1044
1045

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22