/[ascend]/trunk/pygtk/diagnose.py
ViewVC logotype

Diff of /trunk/pygtk/diagnose.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

trunk/pygtk/interface/diagnose.py revision 282 by johnpye, Wed Feb 8 13:51:04 2006 UTC trunk/pygtk/diagnose.py revision 2071 by jose, Fri Aug 28 02:42:47 2009 UTC
# Line 1  Line 1 
1  import gtk  import gtk
2  import gtk.glade  import gtk.glade
3  import ascend  import ascpy
 import pylab;  
 import matplotlib  
 matplotlib.use('GTK')  
 from matplotlib.figure import Figure  
 from matplotlib.axes import Subplot  
 from matplotlib.colors import LinearSegmentedColormap  
 from matplotlib.backends.backend_gtk import FigureCanvasGTK, NavigationToolbar  
4  from itertools import groupby  from itertools import groupby
5  from operator import itemgetter  from operator import itemgetter
6    import math
7    import re
8    
9    import config
10    from infodialog import *
11    
12    ZOOM_RE = re.compile(r"([0-9]+)\s*%?")
13    MAX_ZOOM_SIZE = float(2000) # float
14    MAX_ZOOM_RATIO = float(16) # float
15    AT_BOUND_TOL = 0.0001;
16    
17  class DiagnoseWindow:  class DiagnoseWindow:
18      def __init__(self,GLADE_FILE,browser):      def __init__(self,browser,block=0):
19          self.browser=browser          self.browser=browser
20          _xml = gtk.glade.XML(GLADE_FILE,"diagnosewin")          _xml = gtk.glade.XML(browser.glade_file,"diagnosewin")
21          _xml.signal_autoconnect(self)            _xml.signal_autoconnect(self)  
22    
23          self.window = _xml.get_widget("diagnosewin")          self.window = _xml.get_widget("diagnosewin")
24            self.window.set_transient_for(self.browser.window)
25    
26            try:
27                _icon = gtk.Image()
28                _iconpath = browser.assets_dir+'diagnose'+config.ICON_EXTENSION
29                print "ICON PATH =",_iconpath
30                _icon.set_from_file(_iconpath)
31                print "ICON = ",_icon
32                self.window.set_icon(_icon)
33            except:
34                pass
35            
36            self.imagescroll = _xml.get_widget("imagescroll")
37          self.image = _xml.get_widget("image")          self.image = _xml.get_widget("image")
38          self.blockentry = _xml.get_widget("blockentry")          self.blockentry = _xml.get_widget("blockentry")
39            self.zoomentry = _xml.get_widget("zoomentry")
40    
41            self.var = None; self.rel = None
42            self.varname = _xml.get_widget("varname1")
43            self.varval = _xml.get_widget("varval")
44            self.varinfobutton = _xml.get_widget("varinfobutton")
45            self.relname = _xml.get_widget("relname1")
46            self.relresid = _xml.get_widget("relresid")
47            self.relinfobutton = _xml.get_widget("relinfobutton")
48    
49          self.varview = _xml.get_widget("varview")          self.varview = _xml.get_widget("varview")
50          self.varbuf = gtk.TextBuffer()          self.varbuf = gtk.TextBuffer()
# Line 34  class DiagnoseWindow: Line 59  class DiagnoseWindow:
59          self.relbuf = gtk.TextBuffer()          self.relbuf = gtk.TextBuffer()
60          self.relview.set_buffer(self.relbuf)          self.relview.set_buffer(self.relbuf)
61    
62            self.im = None
63            self.block = 0
64            self.apply_prefs()
65    
66          self.prepare_data()          self.prepare_data()
67          self.fill_values(0) # block zero          self.fill_values(block) # block zero
68    
69      def run(self):      def run(self):
70          self.window.run()          self.window.run()
71          self.window.hide()          self.window.hide()
72    
73        def apply_prefs(self):
74            vc = self.browser.prefs.getBoolPref("Diagnose","varcollapsed",True)
75    
76            print "VARCOLLAPSED =",vc
77            self.varcollapsed.set_active(vc)
78            self.relcollapsed.set_active(self.browser.prefs.getBoolPref("Diagnose","relcollapsed",True))
79    
80      def prepare_data(self):      def prepare_data(self):
81          # convert incidence map to pylab numarray type:          # convert incidence map to pylab numarray type:
82          print "PREPARING DATA"          print "PREPARING DATA"
# Line 48  class DiagnoseWindow: Line 84  class DiagnoseWindow:
84          self.data = self.im.getIncidenceData()          self.data = self.im.getIncidenceData()
85          print "DATA LOADED"          print "DATA LOADED"
86    
87          self.canvas = None          self.zoom=1;
88            
89      def fill_values(self, block):      def fill_values(self, block):
90          print "FILL VALUES %d" % block          
91            try:
92                if self.im.getNumBlocks()==0:
93                    print "NO BLOCKS!"
94                    self.image.set_from_stock(gtk.STOCK_DIALOG_ERROR
95                        ,gtk.ICON_SIZE_DIALOG
96                    )
97                    self.browser.reporter.reportError(
98                        "Can't 'Diagnose blocks' until solver has been used."
99                    )
100                    return;
101                rl,cl,rh,ch = self.im.getBlockLocation(block)
102            except IndexError:
103                if block >= self.im.getNumBlocks():
104                    block = self.im.getNumBlocks() - 1
105                    rl,cl,rh,ch = self.im.getBlockLocation(block)
106                else:              
107                    print "BLOCK INDEX ERROR: block =",block
108                    self.blockentry.set_text(str(self.block))
109                    return
110            except RuntimeError,e:
111                print "ERROR GETTING BLOCK LOCATION:",str(e)
112                self.blockentry.set_text(str(self.block))
113                return
114    
115          self.block = block          self.block = block
116          self.blockentry.set_text(str(block))          self.blockentry.set_text(str(block))
117            
118            self.rl = rl
119            self.cl = cl
120            self.rh = rh
121            self.ch = ch
122    
123            nr = int(rh-rl+1);
124            nc = int(ch-cl+1);
125    
126            print "STARTING IMAGE CREATION"
127          # refer http://pygtk.org/pygtk2tutorial/sec-DrawingMethods.html          # refer http://pygtk.org/pygtk2tutorial/sec-DrawingMethods.html
128          c = chr(255)          c = chr(255)
129          b = self.im.getNumRows()*self.im.getNumCols()*3*[c]          b = nr*nc*3*[c]
130          rowstride = 3 * self.im.getNumCols()          rowstride = 3 * nc
         for i in self.data:  
             pos = rowstride*i.row + 3*i.col  
             b[pos], b[pos+1], b[pos+2] = [chr(0)]*3  
131                    
132            blackdot = [chr(0)]*3;
133            reddot = [chr(255), chr(0), chr(0)]
134            pinkdot = [chr(255), chr(127), chr(127)]
135            skydot = [chr(127), chr(127), chr(255)]
136            bluedot = [chr(0), chr(0), chr(255)]
137            hotpinkdot = [chr(255), chr(47), chr(179)] # very big (+/-)
138            brightbluedot = [chr(71), chr(157), chr(255)] # very small (+/-)
139            greendot = [chr(87), chr(193), chr(70)] # close to 1
140            orangedot = [chr(255), chr(207), chr(61)] # 10-1000
141            bluegreendot = [chr(70), chr(221), chr(181)] # 0.001 - 0.1
142            for i in self.data:
143                if i.row < rl or i.row > rh or i.col < cl or i.col > ch:
144                    continue
145                r = i.row - rl;
146                c = i.col - cl;
147                pos = rowstride*r + 3*c
148                dot = blackdot;
149                var = self.im.getVariable(i.col);
150                if abs( (var.getValue()-var.getUpperBound())/ var.getNominal() )  < AT_BOUND_TOL:
151                    dot = reddot
152                elif abs( var.getValue() - var.getLowerBound() ) / var.getNominal() < AT_BOUND_TOL:
153                    dot = reddot
154                else:
155                    rat = var.getValue() / var.getNominal()
156                    if rat!=0:
157                        try:
158                            val = abs(rat)
159                            if abs(rat) > 1000:
160                                dot = hotpinkdot
161                            elif abs(rat) > 10:
162                                dot = orangedot
163                            elif abs(rat) < 0.001:
164                                dot = brightbluedot
165                            elif abs(rat) < 10 and abs(rat) > 0.1:
166                                dot = greendot
167                            elif abs(rat) > 0.001 and abs(rat) < 0.1:
168                                dot = bluegreendot
169                            else:
170                                dot = blackdot
171                        except ValueError, e:
172                            pass
173                #print "DOT: ",dot
174                b[pos], b[pos+1], b[pos+2] = dot
175    
176          d = ''.join(b)          d = ''.join(b)
177          pb = gtk.gdk.pixbuf_new_from_data(d, gtk.gdk.COLORSPACE_RGB, False, 8 \  
178                  , self.im.getNumCols(), self.im.getNumRows(), rowstride)          print "DONE IMAGE CREATION"
179            
180          pb1 = pb.scale_simple(400,400,gtk.gdk.INTERP_BILINEAR)          self.pixbuf = gtk.gdk.pixbuf_new_from_data(d, gtk.gdk.COLORSPACE_RGB, False, 8 \
181          del pb;                  , nc, nr, rowstride);
182    
183          self.image.set_from_pixbuf(pb1)          self.nr = nr
184            self.nc = nc
185            self.zoom = -1 # to fit, up to max 16x
186            self.do_zoom()
187    
188            print "DONE IMAGE TRANSFER TO SERVER"
189    
190          self.fill_var_names()          self.fill_var_names()
191          self.fill_rel_names()          self.fill_rel_names()
192        
193            self.fill_selection_info()
194    
195            print "DONE FILL VALUES"
196    
197        def fill_selection_info(self):
198            if self.var:
199                #self.varname.set_text(self.var.getName())
200                self.varval.set_text(str(self.var.getValue()))
201                self.varinfobutton.set_sensitive(True)
202            else:
203                self.varname.set_text("")
204                self.varval.set_text("")
205                self.varinfobutton.set_sensitive(False)
206    
207            if self.rel:
208                self.relname.set_text(self.rel.getName())
209                self.relresid.set_text(str(self.rel.getResidual()))
210                self.relinfobutton.set_sensitive(True)
211            else:
212                self.relname.set_text("")
213                self.relresid.set_text("")
214                self.relinfobutton.set_sensitive(False)
215    
216        def do_zoom(self):
217            if self.zoom == -1:
218                w, h = self.imagescroll.size_request()
219                #print "SCALE TO FIX, w=%d, h=%d" % (w,h)
220                if self.nc/self.nr > w/h:
221                    # a 'wide' image    
222                    self.zoom = float(w) / self.nc
223                else:
224                    self.zoom = float(h) / self.nr
225    
226            #self.browser.reporter.reportNote("Diagnose window: preliminary calculated zoom = %f (nr = %d, nc = %d)" % (self.zoom, self.nr, self.nc))
227            
228    
229            if self.zoom > MAX_ZOOM_RATIO:
230                self.zoom = MAX_ZOOM_RATIO
231    
232            if self.zoom * self.nc > MAX_ZOOM_SIZE or self.zoom * self.nr > MAX_ZOOM_SIZE:
233                self.browser.reporter.reportNote("image is too big, reducing to MAX_ZOOM_SIZE = %f" % MAX_ZOOM_SIZE);
234                self.zoom = MAX_ZOOM_SIZE / max(self.nc,self.nr)
235    
236            #self.browser.reporter.reportNote("Diagnose window: matrix zoom = %f" % self.zoom)
237            w = int(self.zoom * self.nc);
238            h = int(self.zoom * self.nr);
239                
240            self.zoomentry.set_text("%d %%" % (int(self.zoom*100)) )
241    
242            if self.zoom < 2:
243                pb1 = self.pixbuf.scale_simple(w,h,gtk.gdk.INTERP_BILINEAR)
244            else:
245                pb1 = self.pixbuf.scale_simple(w,h,gtk.gdk.INTERP_NEAREST)
246            
247            self.image.set_from_pixbuf(pb1)
248    
249      def fill_var_names(self):      def fill_var_names(self):
250            print "FILL VAR NAMES"
251    
252          names = [str(i) for i in self.im.getBlockVars(self.block)]          names = [str(i) for i in self.im.getBlockVars(self.block)]
253    
254            #print "NAMES:",names
255    
256          if self.varcollapsed.get_active():          if self.varcollapsed.get_active():
257              res = collapse(names)              res = reduce(names)
258              rows = []              rows = []
259              for k in res:              for k in res:
260                  if k=="":                  if k=="":
# Line 91  class DiagnoseWindow: Line 267  class DiagnoseWindow:
267              text = "\n".join(names)              text = "\n".join(names)
268          self.varbuf.set_text(text)          self.varbuf.set_text(text)
269    
270            print "DONE VAR NAMES"
271    
272      def fill_rel_names(self):      def fill_rel_names(self):
273          names = [str(i) for i in self.im.getBlockRels(self.block)]          print "REL NAMES"
274    
275            rels = self.im.getBlockRels(self.block)
276    
277            print "GOT RELS, NOW GETTING NAMES"
278    
279            names = [str(i) for i in rels]
280    
281            #print "NAMES =",names
282    
283          if self.relcollapsed.get_active():          if self.relcollapsed.get_active():
284              text = "\n".join(collapse(names))              res = reduce(names)
285                rows = []
286                for k in res:
287                    if k=="":
288                        for r in res[k]:
289                            rows.append(r)
290                    else:
291                        rows.append( '%s:\n\t%s' % (k, "\n\t".join(res[k])) )
292                text = "\n".join(rows)
293          else:          else:
294              text = "\n".join(names)              text = "\n".join(names)
295          self.relbuf.set_text(text)          self.relbuf.set_text(text)
296    
297            print "DONE REL NAMES"
298    
299      def set_block(self, block):      def set_block(self, block):
         self.block = block;  
300          self.fill_values(block)          self.fill_values(block)
301    
302        def set_zoom(self,zoom):
303            self.zoom = zoom
304            self.do_zoom()
305    
306        def show_cursor(self,x,y):
307            c = self.cl + int(x/self.zoom)
308            r = self.rl + int(y / self.zoom)
309            if c > self.ch or r > self.rh:
310                #print "OUT OF RANGE"
311                return
312            self.var = self.im.getVariable(c)
313            self.rel = self.im.getRelation(r)
314            self.fill_selection_info()
315    
316        # GUI EVENT HOOKS-----------------------------------------------------------
317    
318        def on_diagnosewin_close(self,*args):
319            self.window.response(gtk.RESPONSE_CLOSE);
320    
321        # incidence data view
322    
323      def on_varcollapsed_toggled(self,*args):      def on_varcollapsed_toggled(self,*args):
324          print "COLLAPSED-TOGGLED"          vc = self.varcollapsed.get_active()
325          self.fill_var_names()          self.browser.prefs.setBoolPref("Diagnose","varcollapsed",vc)    
326            if self.im:
327                self.fill_var_names()
328    
329      def on_relcollapsed_toggled(self,*args):      def on_relcollapsed_toggled(self,*args):
330          print "COLLAPSED-TOGGLED"          rc = self.varcollapsed.get_active()
331          self.fill_rel_names()          self.browser.prefs.setBoolPref("Diagnose","relcollapsed",rc)    
332            if self.im:
333                self.fill_rel_names()
334    
335        # detailed information about vars and rels (solver-side information!)
336    
337        def on_varinfobutton_clicked(self,*args):
338            title = "Variable '%s'" % self.var
339            text = "%s\n%s\n" % (title,"(from the solver's view)")
340    
341            _rows = {
342                "Value": self.var.getValue()
343                ,"Nominal": self.var.getNominal()
344                ,"Lower bound": self.var.getLowerBound()
345                ,"Upper bound": self.var.getUpperBound()
346            }
347            for k,v in _rows.iteritems():
348                text += "\n  %s\t%s" % (k,value_human(v))
349            
350            text += "\n\nIncident with %d relations:" % self.var.getNumIncidentRelations()
351            for r in self.var.getIncidentRelations():
352                text += "\n  %s" % r.getName()
353    
354            _dialog = InfoDialog(self.browser,self.window,text,title,tabs=(150,300))
355            _dialog.run()
356    
357        def on_relinfobutton_clicked(self,*args):
358            title = "Relation '%s'" % self.rel
359            text = "%s\n%s\n" % (title,"(from the solver's view)")
360            text += "\n  %s\t%15f" % ("Residual", self.rel.getResidual())
361    
362            text += "\n\nRelation expression:\n"
363            text += self.rel.getRelationAsString()
364    
365            text += "\n\nIncident with %d variables:" % self.rel.getNumIncidentVariables()
366            for v in self.rel.getIncidentVariables():
367                text += "\n  %s\t= %s" % ( v.getName(),value_human(v.getValue()) )
368    
369            _dialog = InfoDialog(self.browser,self.window,text,title,tabs=(150,300))
370            _dialog.run()
371            
372    
373        # block navigation
374    
375      def on_nextbutton_clicked(self,*args):      def on_nextbutton_clicked(self,*args):
376          self.set_block(self.block + 1)          self.set_block(self.block + 1)
377    
378      def on_prevbutton_clicked(self,*args):      def on_prevbutton_clicked(self,*args):
379          self.set_block(self.block - 1)                self.set_block(self.block - 1)  
380    
381      def on_blockentry_changed(self,*args):      def on_prevbigbutton_clicked(self,*args):
382          self.set_block( int(self.blockentry.get_text()) )          b = self.block - 1
383            while b >= 0:
384                rl,cl,rh,ch = self.im.getBlockLocation(b)
385                if rh-rl > 0 or ch-cl>0:
386                    self.set_block(b)
387                b = b - 1
388            print "NO PRECEDING 'BIG' BLOCKS"
389            
390        def on_nextbigbutton_clicked(self,*args):
391            b = self.block + 1
392            n = self.im.getNumBlocks()
393            while b < n:
394                rl,cl,rh,ch = self.im.getBlockLocation(b)
395                if rh-rl > 0 or ch-cl>0:
396                    self.set_block(b)
397                b = b + 1
398            print "NO FOLLOWING 'BIG' BLOCKS"
399        
400        def on_blockentry_key_press_event(self,widget,event):
401            keyname = gtk.gdk.keyval_name(event.keyval)
402            print "KEY ",keyname
403            if keyname=="Return":
404                self.set_block( int(self.blockentry.get_text()) )
405    
406        # zoom in and out
407    
408        def on_zoominbutton_clicked(self,*args):
409            z = int( math.log(self.zoom)/math.log(2) )
410            z = pow(2,z + 1);
411            self.set_zoom(z)
412    
413        def on_zoomoutbutton_clicked(self,*args):
414            z = int( math.log(self.zoom)/math.log(2) + 0.999)
415            z = pow(2,z - 1);
416            self.set_zoom(z)        
417    
418        def on_zoomentry_key_press_event(self,widget,event):
419            keyname = gtk.gdk.keyval_name(event.keyval)
420            print "KEY ",keyname
421            if keyname=="Return":
422                t = self.zoomentry.get_text()
423                m = ZOOM_RE.match(t)
424                if not m:
425                    self.zoomentry.set_text("%d %%" % int(self.zoom*100))
426                for mm in m:
427                    print m
428                self.set_zoom( int(self.zoomentry.get_text()) )
429    
430        # clicking in incidence matrix to get updated information at RHS
431    
432        def on_imageevent_motion_notify_event(self,widget,event):
433            self.show_cursor(event.x, event.y)
434    
435        def on_imageevent_button_press_event(self,widget,event):
436            self.show_cursor(event.x, event.y)
437    
438    
439    def value_human(v):
440        if v==0 or abs( math.log10(abs(v)) )<8:
441            return "%f" % v
442        return "%e" % v
443    
444  # The following is from  #---------------------------------------
445    # Procedures to 'fold' a list of items from a hierarchy
446  # http://www.experts-exchange.com/Programming/Programming_Languages/Python/Q_21719649.html  # http://www.experts-exchange.com/Programming/Programming_Languages/Python/Q_21719649.html
447    # It's still buggy, I think
448    
449  def fold(data):  def fold(data):
450      """ fold sorted numeric sequence data into ranged representation:      """ fold sorted numeric sequence data into ranged representation:
# Line 129  def fold(data): Line 452  def fold(data):
452      '[1,4-6,10,15-18,22,25-28]'      '[1,4-6,10,15-18,22,25-28]'
453      """      """
454      folded = []      folded = []
455      for k, g in groupby(enumerate(data), lambda (i,x):i-x):      for k, g in groupby(enumerate(sorted(data)), lambda (i,x):i-x):
456          seq = map(itemgetter(1), g)          seq = map(itemgetter(1), g)
457          if len(seq) > 1:          if len(seq) > 1:
458              x = '%s-%s' % (seq[0], seq[-1])              x = '%s-%s' % (seq[0], seq[-1])
# Line 138  def fold(data): Line 461  def fold(data):
461          folded.append(x)          folded.append(x)
462      return folded and '[%s]' % ','.join(folded) or ''      return folded and '[%s]' % ','.join(folded) or ''
463    
464  def collapse(names):  def reduce(names):
465      """reduce a list of items into something more readable:      """reduce a list of items nto something more readable:
466      >>> data = 'C.x C.p C.T C.delta[1] C.delta[2] C.delta[3] C.sat.x C.sat.p C.h C.delta[5]'.split()      >>> data = 'C.x C.p C.T C.delta[1] C.delta[2] C.delta[3] C.sat.x C.sat.p C.h C.delta[5]'.split()
467      >>> res = reduce(data)      >>> res = reduce(data)
468      >>> for k in sorted(res):      >>> for k in sorted(res):
# Line 147  def collapse(names): Line 470  def collapse(names):
470      C: T, delta[1-3,5], h, p, x      C: T, delta[1-3,5], h, p, x
471      C.sat: p, x      C.sat: p, x
472      """      """
473      data = sorted([n.split('.') for n in names], key=len)      data = sorted([n.split('.') for n in sorted(names)], key=len)
474      res = {}      res = {}
475      for k, g in groupby(data, lambda x: len(x)):      for k, g in groupby(data, lambda x: len(x)):
476          item = g.next()          if k == 1:
477          assert len(item) == k              indexed = {}
478          key = '.'.join(item[:-1])              seq = set([get(indexed, item) for item in g])
479          indexed = {}              res['[global]'] = [ i+fold(indexed.get(i, [])) for i in sorted(seq) ]
480          seq = set(get(indexed, item))          else:
481          for item in g:              for key, g1 in groupby(g, lambda x: '.'.join(x[:-1])):
482              seq.add(get(indexed, item))                  indexed = {}
483          res[key] = [i+fold(indexed.get(i, [])) for i in sorted(seq)]                  seq = set(get(indexed, item) for item in g1)
484                    res[key] = [ i+fold(indexed.get(i, [])) for i in sorted(seq) ]
485      return res      return res
486    
487  def get(indexed, item):  def get(indexed, item):
# Line 166  def get(indexed, item): Line 490  def get(indexed, item):
490          item, idx = item[:-1].split('[')          item, idx = item[:-1].split('[')
491          indexed.setdefault(item, []).append(int(idx))          indexed.setdefault(item, []).append(int(idx))
492      return item      return item
493    

Legend:
Removed from v.282  
changed lines
  Added in v.2071

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