1 |
johnpye |
280 |
import gtk |
2 |
|
|
import gtk.glade |
3 |
|
|
import ascend |
4 |
|
|
from itertools import groupby |
5 |
|
|
from operator import itemgetter |
6 |
johnpye |
283 |
import math |
7 |
johnpye |
284 |
import re |
8 |
johnpye |
280 |
|
9 |
johnpye |
284 |
ZOOM_RE = re.compile(r"([0-9]+)\s*%?") |
10 |
|
|
MAX_ZOOM_SIZE = 2000 |
11 |
|
|
MAX_ZOOM_RATIO = 16 |
12 |
johnpye |
287 |
AT_BOUND_TOL = 0.0001; |
13 |
johnpye |
284 |
|
14 |
johnpye |
280 |
class DiagnoseWindow: |
15 |
johnpye |
285 |
def __init__(self,GLADE_FILE,browser,block=0): |
16 |
johnpye |
280 |
self.browser=browser |
17 |
|
|
_xml = gtk.glade.XML(GLADE_FILE,"diagnosewin") |
18 |
|
|
_xml.signal_autoconnect(self) |
19 |
|
|
|
20 |
|
|
self.window = _xml.get_widget("diagnosewin") |
21 |
johnpye |
284 |
self.imagescroll = _xml.get_widget("imagescroll") |
22 |
johnpye |
282 |
self.image = _xml.get_widget("image") |
23 |
johnpye |
280 |
self.blockentry = _xml.get_widget("blockentry") |
24 |
johnpye |
284 |
self.zoomentry = _xml.get_widget("zoomentry") |
25 |
johnpye |
280 |
|
26 |
johnpye |
286 |
self.varname = _xml.get_widget("varname"); |
27 |
|
|
self.varval = _xml.get_widget("varval"); |
28 |
|
|
self.relname = _xml.get_widget("relname"); |
29 |
|
|
self.relresid = _xml.get_widget("relresid"); |
30 |
|
|
|
31 |
johnpye |
280 |
self.varview = _xml.get_widget("varview") |
32 |
|
|
self.varbuf = gtk.TextBuffer() |
33 |
|
|
self.varview.set_buffer(self.varbuf) |
34 |
|
|
self.varcollapsed = _xml.get_widget("varcollapsed") |
35 |
|
|
self.relview = _xml.get_widget("relview") |
36 |
|
|
self.relcollapsed = _xml.get_widget("relcollapsed") |
37 |
|
|
self.relvalues = _xml.get_widget("relvalues") |
38 |
|
|
self.rellabels = _xml.get_widget("rellabels") |
39 |
|
|
self.relrels = _xml.get_widget("relrels") |
40 |
|
|
self.relresids = _xml.get_widget("relresids") |
41 |
|
|
self.relbuf = gtk.TextBuffer() |
42 |
|
|
self.relview.set_buffer(self.relbuf) |
43 |
|
|
|
44 |
johnpye |
294 |
self.im = None |
45 |
johnpye |
285 |
self.block = 0 |
46 |
johnpye |
294 |
self.apply_prefs() |
47 |
|
|
|
48 |
johnpye |
280 |
self.prepare_data() |
49 |
johnpye |
285 |
self.fill_values(block) # block zero |
50 |
johnpye |
280 |
|
51 |
|
|
def run(self): |
52 |
|
|
self.window.run() |
53 |
|
|
self.window.hide() |
54 |
|
|
|
55 |
johnpye |
294 |
def apply_prefs(self): |
56 |
|
|
vc = self.browser.prefs.getBoolPref("Diagnose","varcollapsed") |
57 |
|
|
print "VARCOLLAPSED =",vc |
58 |
|
|
self.varcollapsed.set_active(vc) |
59 |
|
|
self.relcollapsed.set_active(self.browser.prefs.getBoolPref("Diagnose","relcollapsed")) |
60 |
|
|
|
61 |
johnpye |
280 |
def prepare_data(self): |
62 |
|
|
# convert incidence map to pylab numarray type: |
63 |
|
|
print "PREPARING DATA" |
64 |
|
|
self.im = self.browser.sim.getIncidenceMatrix() |
65 |
|
|
self.data = self.im.getIncidenceData() |
66 |
|
|
print "DATA LOADED" |
67 |
|
|
|
68 |
johnpye |
284 |
self.zoom=1; |
69 |
johnpye |
280 |
|
70 |
|
|
def fill_values(self, block): |
71 |
johnpye |
283 |
try: |
72 |
|
|
rl,cl,rh,ch = self.im.getBlockLocation(block) |
73 |
|
|
except IndexError: |
74 |
johnpye |
285 |
self.blockentry.set_text(str(self.block)) |
75 |
johnpye |
283 |
return |
76 |
johnpye |
285 |
except RuntimeError: |
77 |
|
|
self.blockentry.set_text(str(self.block)) |
78 |
|
|
return |
79 |
|
|
|
80 |
johnpye |
280 |
self.block = block |
81 |
|
|
self.blockentry.set_text(str(block)) |
82 |
johnpye |
283 |
|
83 |
johnpye |
286 |
self.rl = rl |
84 |
|
|
self.cl = cl |
85 |
|
|
self.rh = rh |
86 |
|
|
self.ch = ch |
87 |
|
|
|
88 |
johnpye |
283 |
nr = int(rh-rl+1); |
89 |
|
|
nc = int(ch-cl+1); |
90 |
|
|
|
91 |
johnpye |
284 |
#print "STARTING IMAGE CREATION" |
92 |
johnpye |
282 |
# refer http://pygtk.org/pygtk2tutorial/sec-DrawingMethods.html |
93 |
|
|
c = chr(255) |
94 |
johnpye |
283 |
b = nr*nc*3*[c] |
95 |
|
|
rowstride = 3 * nc |
96 |
|
|
|
97 |
|
|
blackdot = [chr(0)]*3; |
98 |
|
|
reddot = [chr(255), chr(0), chr(0)] |
99 |
|
|
pinkdot = [chr(255), chr(127), chr(127)] |
100 |
|
|
skydot = [chr(127), chr(127), chr(255)] |
101 |
|
|
bluedot = [chr(0), chr(0), chr(255)] |
102 |
johnpye |
285 |
hotpinkdot = [chr(255), chr(47), chr(179)] # very big (+/-) |
103 |
|
|
brightbluedot = [chr(71), chr(157), chr(255)] # very small (+/-) |
104 |
|
|
greendot = [chr(87), chr(193), chr(70)] # close to 1 |
105 |
|
|
orangedot = [chr(255), chr(207), chr(61)] # 10-1000 |
106 |
|
|
bluegreendot = [chr(70), chr(221), chr(181)] # 0.001 - 0.1 |
107 |
johnpye |
280 |
for i in self.data: |
108 |
johnpye |
283 |
if i.row < rl or i.row > rh or i.col < cl or i.col > ch: |
109 |
|
|
continue |
110 |
|
|
r = i.row - rl; |
111 |
|
|
c = i.col - cl; |
112 |
|
|
pos = rowstride*r + 3*c |
113 |
|
|
dot = blackdot; |
114 |
|
|
var = self.im.getVariable(i.col); |
115 |
johnpye |
287 |
if abs( (var.getValue()-var.getUpperBound())/ var.getNominal() ) < AT_BOUND_TOL: |
116 |
|
|
dot = reddot |
117 |
|
|
elif abs( var.getValue() - var.getLowerBound() ) / var.getNominal() < AT_BOUND_TOL: |
118 |
|
|
dot = reddot |
119 |
|
|
else: |
120 |
|
|
rat = var.getValue() / var.getNominal() |
121 |
|
|
if rat!=0: |
122 |
|
|
try: |
123 |
|
|
val = abs(rat) |
124 |
|
|
if abs(rat) > 1000: |
125 |
|
|
dot = hotpinkdot |
126 |
|
|
elif abs(rat) > 10: |
127 |
|
|
dot = orangedot |
128 |
|
|
elif abs(rat) < 0.001: |
129 |
|
|
dot = brightbluedot |
130 |
|
|
elif abs(rat) < 10 and abs(rat) > 0.1: |
131 |
|
|
dot = greendot |
132 |
|
|
elif abs(rat) > 0.001 and abs(rat) < 0.1: |
133 |
|
|
dot = bluegreendot |
134 |
|
|
else: |
135 |
|
|
dot = blackdot |
136 |
|
|
except ValueError, e: |
137 |
|
|
pass |
138 |
johnpye |
284 |
#print "DOT: ",dot |
139 |
johnpye |
283 |
b[pos], b[pos+1], b[pos+2] = dot |
140 |
|
|
|
141 |
johnpye |
282 |
d = ''.join(b) |
142 |
johnpye |
283 |
|
143 |
johnpye |
284 |
#print "DONE IMAGE CREATION" |
144 |
johnpye |
282 |
|
145 |
johnpye |
284 |
self.pixbuf = gtk.gdk.pixbuf_new_from_data(d, gtk.gdk.COLORSPACE_RGB, False, 8 \ |
146 |
|
|
, nc, nr, rowstride); |
147 |
johnpye |
283 |
|
148 |
johnpye |
284 |
self.nr = nr |
149 |
|
|
self.nc = nc |
150 |
|
|
self.zoom = -1 # to fit, up to max 16x |
151 |
|
|
self.do_zoom() |
152 |
johnpye |
283 |
|
153 |
johnpye |
284 |
#print "DONE IMAGE TRANSFER TO SERVER" |
154 |
johnpye |
283 |
|
155 |
johnpye |
284 |
self.fill_var_names() |
156 |
|
|
self.fill_rel_names() |
157 |
johnpye |
286 |
|
158 |
|
|
self.varname.set_text(""); |
159 |
|
|
self.varval.set_text(""); |
160 |
|
|
self.relname.set_text(""); |
161 |
|
|
self.relresid.set_text(""); |
162 |
johnpye |
280 |
|
163 |
johnpye |
286 |
|
164 |
johnpye |
284 |
def do_zoom(self): |
165 |
|
|
if self.zoom == -1: |
166 |
|
|
w, h = self.imagescroll.size_request() |
167 |
|
|
#print "SCALE TO FIX, w=%d, h=%d" % (w,h) |
168 |
|
|
if self.nc/self.nr > w/h: |
169 |
|
|
# a 'wide' image |
170 |
|
|
self.zoom = w / self.nc |
171 |
|
|
else: |
172 |
|
|
self.zoom = h / self.nr |
173 |
johnpye |
283 |
|
174 |
johnpye |
284 |
if self.zoom > MAX_ZOOM_RATIO: |
175 |
|
|
self.zoom = MAX_ZOOM_RATIO |
176 |
johnpye |
280 |
|
177 |
johnpye |
284 |
if self.zoom * self.nc > MAX_ZOOM_SIZE or self.zoom * self.nr > MAX_ZOOM_SIZE: |
178 |
|
|
self.zoom = MAX_ZOOM_SIZE / max(self.nc,self.nr) |
179 |
johnpye |
283 |
|
180 |
johnpye |
284 |
w = int(self.zoom * self.nc); |
181 |
|
|
h = int(self.zoom * self.nr); |
182 |
|
|
|
183 |
|
|
self.zoomentry.set_text("%d %%" % (int(self.zoom*100)) ) |
184 |
johnpye |
280 |
|
185 |
johnpye |
284 |
if self.zoom < 2: |
186 |
|
|
pb1 = self.pixbuf.scale_simple(w,h,gtk.gdk.INTERP_BILINEAR) |
187 |
|
|
else: |
188 |
|
|
pb1 = self.pixbuf.scale_simple(w,h,gtk.gdk.INTERP_NEAREST) |
189 |
|
|
|
190 |
|
|
self.image.set_from_pixbuf(pb1) |
191 |
|
|
|
192 |
johnpye |
280 |
def fill_var_names(self): |
193 |
|
|
names = [str(i) for i in self.im.getBlockVars(self.block)] |
194 |
|
|
if self.varcollapsed.get_active(): |
195 |
johnpye |
287 |
res = reduce(names) |
196 |
johnpye |
280 |
rows = [] |
197 |
|
|
for k in res: |
198 |
|
|
if k=="": |
199 |
|
|
for r in res[k]: |
200 |
|
|
rows.append(r) |
201 |
|
|
else: |
202 |
|
|
rows.append( '%s:\n\t%s' % (k, "\n\t".join(res[k])) ) |
203 |
|
|
text = "\n".join(rows) |
204 |
|
|
else: |
205 |
|
|
text = "\n".join(names) |
206 |
|
|
self.varbuf.set_text(text) |
207 |
|
|
|
208 |
|
|
def fill_rel_names(self): |
209 |
|
|
names = [str(i) for i in self.im.getBlockRels(self.block)] |
210 |
|
|
if self.relcollapsed.get_active(): |
211 |
johnpye |
287 |
res = reduce(names) |
212 |
|
|
rows = [] |
213 |
|
|
for k in res: |
214 |
|
|
if k=="": |
215 |
|
|
for r in res[k]: |
216 |
|
|
rows.append(r) |
217 |
|
|
else: |
218 |
|
|
rows.append( '%s:\n\t%s' % (k, "\n\t".join(res[k])) ) |
219 |
|
|
text = "\n".join(rows) |
220 |
johnpye |
280 |
else: |
221 |
|
|
text = "\n".join(names) |
222 |
|
|
self.relbuf.set_text(text) |
223 |
|
|
|
224 |
|
|
def set_block(self, block): |
225 |
|
|
self.fill_values(block) |
226 |
|
|
|
227 |
johnpye |
284 |
def set_zoom(self,zoom): |
228 |
|
|
self.zoom = zoom |
229 |
|
|
self.do_zoom() |
230 |
|
|
|
231 |
johnpye |
286 |
def show_cursor(self,x,y): |
232 |
|
|
c = self.cl + int(x/self.zoom) |
233 |
|
|
r = self.rl + int(y / self.zoom) |
234 |
|
|
if c > self.ch or r > self.rh: |
235 |
|
|
#print "OUT OF RANGE" |
236 |
|
|
return |
237 |
|
|
var = self.im.getVariable(c) |
238 |
|
|
self.varname.set_text(var.getName()) |
239 |
|
|
self.varval.set_text(str(var.getValue())) |
240 |
|
|
rel = self.im.getRelation(r) |
241 |
|
|
self.relname.set_text(rel.getName()) |
242 |
|
|
self.relresid.set_text(str(rel.getResidual())) |
243 |
|
|
|
244 |
|
|
# GUI EVENT HOOKS----------------------------------------------------------- |
245 |
|
|
|
246 |
johnpye |
280 |
def on_varcollapsed_toggled(self,*args): |
247 |
johnpye |
294 |
vc = self.varcollapsed.get_active() |
248 |
|
|
self.browser.prefs.setBoolPref("Diagnose","varcollapsed",vc) |
249 |
|
|
if self.im: |
250 |
|
|
self.fill_var_names() |
251 |
johnpye |
280 |
|
252 |
|
|
def on_relcollapsed_toggled(self,*args): |
253 |
johnpye |
294 |
rc = self.varcollapsed.get_active() |
254 |
|
|
self.browser.prefs.setBoolPref("Diagnose","relcollapsed",rc) |
255 |
|
|
if self.im: |
256 |
|
|
self.fill_rel_names() |
257 |
johnpye |
280 |
|
258 |
|
|
def on_nextbutton_clicked(self,*args): |
259 |
|
|
self.set_block(self.block + 1) |
260 |
|
|
|
261 |
|
|
def on_prevbutton_clicked(self,*args): |
262 |
johnpye |
290 |
self.set_block(self.block - 1) |
263 |
johnpye |
280 |
|
264 |
johnpye |
290 |
def on_prevbigbutton_clicked(self,*args): |
265 |
|
|
b = self.block - 1 |
266 |
johnpye |
291 |
while b >= 0: |
267 |
johnpye |
290 |
rl,cl,rh,ch = self.im.getBlockLocation(b) |
268 |
|
|
if rh-rl > 0 or ch-cl>0: |
269 |
|
|
self.set_block(b) |
270 |
|
|
b = b - 1 |
271 |
|
|
print "NO PRECEDING 'BIG' BLOCKS" |
272 |
|
|
|
273 |
|
|
def on_nextbigbutton_clicked(self,*args): |
274 |
|
|
b = self.block + 1 |
275 |
|
|
n = self.im.getNumBlocks() |
276 |
|
|
while b < n: |
277 |
|
|
rl,cl,rh,ch = self.im.getBlockLocation(b) |
278 |
|
|
if rh-rl > 0 or ch-cl>0: |
279 |
|
|
self.set_block(b) |
280 |
|
|
b = b + 1 |
281 |
|
|
print "NO FOLLOWING 'BIG' BLOCKS" |
282 |
|
|
|
283 |
johnpye |
283 |
def on_blockentry_key_press_event(self,widget,event): |
284 |
|
|
keyname = gtk.gdk.keyval_name(event.keyval) |
285 |
|
|
print "KEY ",keyname |
286 |
|
|
if keyname=="Return": |
287 |
|
|
self.set_block( int(self.blockentry.get_text()) ) |
288 |
johnpye |
280 |
|
289 |
johnpye |
284 |
def on_zoominbutton_clicked(self,*args): |
290 |
|
|
z = int( math.log(self.zoom)/math.log(2) ) |
291 |
|
|
z = pow(2,z + 1); |
292 |
|
|
self.set_zoom(z) |
293 |
|
|
|
294 |
|
|
def on_zoomoutbutton_clicked(self,*args): |
295 |
|
|
z = int( math.log(self.zoom)/math.log(2) + 0.999) |
296 |
|
|
z = pow(2,z - 1); |
297 |
|
|
self.set_zoom(z) |
298 |
|
|
|
299 |
|
|
def on_zoomentry_key_press_event(self,widget,event): |
300 |
|
|
keyname = gtk.gdk.keyval_name(event.keyval) |
301 |
|
|
print "KEY ",keyname |
302 |
|
|
if keyname=="Return": |
303 |
|
|
t = self.zoomentry.get_text() |
304 |
|
|
m = ZOOM_RE.match(t) |
305 |
|
|
if not m: |
306 |
|
|
self.zoomentry.set_text("%d %%" % int(self.zoom*100)) |
307 |
|
|
for mm in m: |
308 |
|
|
print m |
309 |
|
|
self.set_zoom( int(self.zoomentry.get_text()) ) |
310 |
|
|
|
311 |
johnpye |
286 |
def on_imageevent_motion_notify_event(self,widget,event): |
312 |
|
|
self.show_cursor(event.x, event.y) |
313 |
|
|
|
314 |
|
|
def on_imageevent_button_press_event(self,widget,event): |
315 |
|
|
self.show_cursor(event.x, event.y) |
316 |
|
|
|
317 |
|
|
|
318 |
johnpye |
280 |
# The following is from |
319 |
|
|
# http://www.experts-exchange.com/Programming/Programming_Languages/Python/Q_21719649.html |
320 |
johnpye |
284 |
# it's still buggy. |
321 |
johnpye |
280 |
|
322 |
|
|
def fold(data): |
323 |
|
|
""" fold sorted numeric sequence data into ranged representation: |
324 |
|
|
>>> fold([1, 4,5,6, 10, 15,16,17,18, 22, 25,26,27,28]) |
325 |
|
|
'[1,4-6,10,15-18,22,25-28]' |
326 |
|
|
""" |
327 |
|
|
folded = [] |
328 |
johnpye |
287 |
for k, g in groupby(enumerate(sorted(data)), lambda (i,x):i-x): |
329 |
johnpye |
280 |
seq = map(itemgetter(1), g) |
330 |
|
|
if len(seq) > 1: |
331 |
|
|
x = '%s-%s' % (seq[0], seq[-1]) |
332 |
|
|
else: |
333 |
|
|
x = str(seq[0]) |
334 |
|
|
folded.append(x) |
335 |
|
|
return folded and '[%s]' % ','.join(folded) or '' |
336 |
|
|
|
337 |
johnpye |
287 |
def reduce(names): |
338 |
|
|
"""reduce a list of items nto something more readable: |
339 |
johnpye |
280 |
>>> 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() |
340 |
|
|
>>> res = reduce(data) |
341 |
|
|
>>> for k in sorted(res): |
342 |
|
|
... print '%s: %s' % (k, res[k]) |
343 |
|
|
C: T, delta[1-3,5], h, p, x |
344 |
|
|
C.sat: p, x |
345 |
|
|
""" |
346 |
johnpye |
287 |
data = sorted([n.split('.') for n in sorted(names)], key=len) |
347 |
johnpye |
280 |
res = {} |
348 |
|
|
for k, g in groupby(data, lambda x: len(x)): |
349 |
johnpye |
287 |
if k == 1: |
350 |
|
|
indexed = {} |
351 |
|
|
seq = set(get(indexed, item) for item in g) |
352 |
|
|
res['[global]'] = [ i+fold(indexed.get(i, [])) for i in sorted(seq) ] |
353 |
|
|
else: |
354 |
|
|
for key, g1 in groupby(g, lambda x: '.'.join(x[:-1])): |
355 |
|
|
indexed = {} |
356 |
|
|
seq = set(get(indexed, item) for item in g1) |
357 |
|
|
res[key] = [ i+fold(indexed.get(i, [])) for i in sorted(seq) ] |
358 |
johnpye |
280 |
return res |
359 |
|
|
|
360 |
|
|
def get(indexed, item): |
361 |
|
|
item = item[-1] |
362 |
|
|
if item.endswith(']'): |
363 |
|
|
item, idx = item[:-1].split('[') |
364 |
|
|
indexed.setdefault(item, []).append(int(idx)) |
365 |
|
|
return item |