Package SimPy :: Module SimPlot
[hide private]
[frames] | no frames]

Source Code for Module SimPy.SimPlot

  1  #!/usr / bin / env python 
  2  # coding=utf-8 
  3  # $Revision: 485 $ $Date: 2010-05-10 09:23:24 +0200 (Mon, 10 May 2010) $ kgm 
  4  """ SimPlot 2.1  Provides basic plotting services based on Tk / Tkinter. 
  5   
  6  LICENSE: 
  7  Copyright (C) 2002, 2005, 2006, 2007, 2008, 2009, 2010  Klaus G. Muller, Tony Vignaux 
  8  mailto: kgmuller at xs4all.nl and Tony.Vignaux at vuw.ac.nz 
  9   
 10      This library is free software; you can redistribute it and / or 
 11      modify it under the terms of the GNU Lesser General Public 
 12      License as published by the Free Software Foundation; either 
 13      version 2.1 of the License, or (at your option) any later version. 
 14   
 15      This library is distributed in the hope that it will be useful, 
 16      but WITHOUT ANY WARRANTY; without even the implied warranty of 
 17      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
 18      Lesser General Public License for more details. 
 19   
 20      You should have received a copy of the GNU Lesser General Public 
 21      License along with this library; if not, write to the Free Software 
 22      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111 - 1307  USA 
 23  END OF LICENSE 
 24   
 25  Derived from plotting package in Grayson's Tkinter book. 
 26  The idea to use this package came from Prof. Simon Frost 
 27  of U of California, San Diego who also strongly contributed 
 28  to the design and implementation of SimPlot. 
 29   
 30  """ 
 31  __version__ = '2.1 $Revision: 485 $ $Date: 2010-05-10 09:23:24 +0200 (Mon, 10 May 2010) $' 
 32  from Tkinter import * 
 33  from Canvas import Line, CanvasText, Rectangle 
 34  from tkMessageBox import * 
 35  from tkSimpleDialog import askinteger, askstring, askfloat 
 36  from tkFileDialog import * 
 37  import string, math 
 38  from math import pi 
 39  from SimPy.Simulation import Monitor 
 40   
41 -def minCoordinate(clist):
42 if len(clist) < 2: return clist[0] 43 try: 44 x, y = clist[0] 45 for x1, y1 in clist[1:]: 46 if x1 <= x or y1 <= y: 47 x, y = x1, y1 48 except: 49 x, y = 0, 0 50 51 return x, y
52
53 -def maxCoordinate(clist):
54 if len(clist) < 2: return clist[0] 55 try: 56 x, y = clist[0] 57 for x1, y1 in clist[1:]: 58 if x1 >= x or y1 >= y: 59 x, y = x1, y1 60 except: 61 x, y = 0, 0 62 63 return x, y
64
65 -def minBound(clist):
66 x = 10000000 67 y = 10000000 68 for x1, y1 in clist: 69 if x1 < x: x = x1 70 if y1 < y: y = y1 71 return x, y
72
73 -def maxBound(clist):
74 x = -10000000 75 y = -10000000 76 for x1, y1 in clist: 77 if x1 > x: x = x1 78 if y1 > y: y = y1 79 return x, y
80
81 -class SimPlot(object):
82 - def __init__(self, root = Tk()):
83 self.root = root 84 pass
85
86 - def mainloop(self):
87 self.root.mainloop()
88
89 - def makeLine(self, points,**attr):
90 return GraphLine(points, **attr)
91 - def makeStep(self, points, **attr):
92 #convert data list to steps 93 step0 = points[:] 94 step1 = [[0, 0]] * 2*len(step0) 95 prev = [step0[0][0],0] 96 for x in range(len(step0)): 97 step1[2 * x] = [step0[x][0],prev[1]] 98 step1[2 * x + 1] = step0[x] 99 prev = step0[x] 100 #draw the line 101 return self.makeLine(step1, smooth = False, **attr)
102
103 - def makeHistogram(self, points,**attr):
104 """Makes a histogram graph. 'points' must be a Histogram - like 105 object. 106 """ 107 #convert data list to bars 108 step0 = points[:] 109 step1 = [[0, 0]] * 3*len(step0) 110 prev = [step0[0][0],0] 111 for x in range(len(step0)): 112 step1[3 * x] = [step0[x][0],prev[1]] 113 step1[3 * x + 1] = [step0[x][0],0.0] 114 step1[3 * x + 2] = step0[x] 115 prev = step0[x] 116 deltax = step0[1][0] - step0[0][0] 117 step1.append([prev[0] + deltax, prev[1]]) 118 step1.append([prev[0] + deltax, 0]) 119 #make the line 120 return self.makeLine(step1, smooth = False, 121 xaxis = (step1[0][0],step1[-1][0]), 122 **attr)
123
124 - def makeSymbols(self, points,**attr):
125 return GraphSymbols(points,**attr)
126 - def makeBars(self, points,**attr):
127 return GraphBars(points,**attr)
128 - def makeGraphObjects(self, objects):
129 return GraphObjects(objects)
130 - def makeGraphBase(self, master, width, height, 131 background = 'white', title = '', xtitle = '', ytitle = '', **kw):
132 return GraphBase(master, width, height, 133 background, title, xtitle, ytitle,**kw)
134
135 - def graphMenu(self, root, graph):
136 """To provide a File menu (postscript output, more to come) 137 to the plotxxxx plots""" 138 mainMenu = Menu(root) 139 root.config(menu = mainMenu) 140 def postscriptout(): 141 graph.postscr()
142 file = Menu(mainMenu) 143 file.add_command(label = 'Postscript', command = postscriptout) 144 mainMenu.add_cascade(label = 'File', menu = file, underline = 0)
145
146 - def plotLine(self, points, windowsize = (500, 300),title = '', width = 1, color = 'black', 147 smooth = 0, background = 'white', xlab = 'x', ylab = 'y', 148 xaxis = 'automatic', yaxis = 'automatic'):
149 """Generates a line chart, with menu to save as Postscript file. 150 'points' can be a Monitor instance. 151 """ 152 if points != []: 153 root = Toplevel() 154 f = Frame(root) 155 try: #if it is like a Monitor, take xlab, ylab from it 156 ylab = points.ylab 157 xlab = points.tlab 158 if not title: title = points.name 159 except: 160 pass 161 line = self.makeLine(points, width = width, color = color, smooth = smooth) 162 gr = self.makeGraphObjects([line]) 163 graph = self.makeGraphBase(f, windowsize[0], windowsize[1], 164 title = title, xtitle = xlab, 165 ytitle = ylab, background = background) 166 graph.pack(side = LEFT, fill = BOTH, expand = YES) 167 graph.draw(gr, xaxis = xaxis, yaxis = yaxis) 168 #File menu 169 self.graphMenu(root, graph) 170 f.pack() 171 return graph 172 else: 173 print 'SimPlot.plotline: dataset empty, no plot.' 174 return None
175
176 - def plotStep(self, points, windowsize = (500, 300),title = '', width = 1, color = 'black', 177 background = 'white', xlab = 'x', ylab = 'y', 178 xaxis = 'automatic', yaxis = 'automatic'):
179 """Generates a step chart, with menu to save as Postscript file. 180 'points' can be a Monitor instance. 181 """ 182 if points != []: 183 #convert data list to steps 184 step0 = points[:] 185 step1 = [[0, 0]] * 2*len(step0) 186 prev = [step0[0][0],0] 187 for x in range(len(step0)): 188 step1[2 * x] = [step0[x][0],prev[1]] 189 step1[2 * x + 1] = step0[x] 190 prev = step0[x] 191 #treat monitor case 192 try: #if it is like a Monitor, take xlab, ylab from it 193 ylab = points.ylab 194 xlab = points.tlab 195 if not title: title = points.name 196 except: 197 pass 198 #draw the line 199 smooth = False 200 return self.plotLine(step1, windowsize, title, width, color, 201 smooth, background, xlab, ylab, 202 xaxis, yaxis) 203 else: 204 print 'SimPlot.plotStep: dataset empty, no plot.' 205 return None
206
207 - def plotHistogram(self, points, windowsize = (500, 300),title = '', width = 1, color = 'black', 208 background = 'white', xlab = 'x', ylab = 'y', 209 xaxis = 'automatic', yaxis = 'automatic'):
210 """Makes a histogram plot. 'points' can be a Monitor instance. 211 """ 212 if points != []: 213 #convert data list to bars 214 step0 = points[:] 215 step1 = [[0, 0]] * 3*len(step0) 216 prev = [step0[0][0],0] 217 for x in range(len(step0)): 218 step1[3 * x] = [step0[x][0],prev[1]] 219 step1[3 * x + 1] = [step0[x][0],0.0] 220 step1[3 * x + 2] = step0[x] 221 prev = step0[x] 222 deltax = step0[1][0] - step0[0][0] 223 step1.append([prev[0] + deltax, prev[1]]) 224 step1.append([prev[0] + deltax, 0]) 225 #treat monitor case 226 try: #if it is like a Monitor, take xlab, ylab from it 227 ylab = points.ylab 228 xlab = points.tlab 229 if not title: title = points.name 230 except: 231 pass 232 #draw the line 233 smooth = False 234 return self.plotLine(step1, windowsize = windowsize, title = title, width = width, 235 color = color, smooth = smooth, background = background, 236 xlab = xlab, ylab = ylab, xaxis = (step1[0][0],step1[-1][0]), 237 yaxis = yaxis) 238 else: 239 print 'SimPlot.plotHistogram: dataset empty, no plot.' 240 return None
241
242 - def plotBars(self, points, windowsize = (500, 300),title = '', color = 'black', 243 width = 1, size = 3, fillcolor = 'black', fillstyle = '', 244 outline = 'black', background = 'white', xlab = 'x', ylab = 'y', 245 xaxis = 'automatic', yaxis = 'automatic', anchor = 0.0):
246 """Generates a bar chart, with menu to save as Postscript file. 247 'points' can be a Monitor instance. 248 """ 249 if points != []: 250 root = Toplevel() 251 f = Frame(root) 252 try: #if it is like a Monitor, take xlab, ylab from it 253 ylab = points.ylab 254 xlab = points.tlab 255 if not title: title = points.name 256 except: 257 pass 258 bars = self.makeBars(points, width = width, size = size, color = color, 259 fillcolor = fillcolor, fillstyle = fillstyle, 260 outline = outline, anchor = anchor) 261 gr = self.makeGraphObjects([bars]) 262 graph = self.makeGraphBase(f, windowsize[0],windowsize[1], 263 title = title, xtitle = xlab, 264 ytitle = ylab, background = background) 265 graph.pack(side = LEFT, fill = BOTH, expand = YES) 266 graph.draw(gr, xaxis = xaxis, yaxis = yaxis) 267 #File menu 268 self.graphMenu(root, graph) 269 f.pack() 270 return graph 271 else: 272 print 'SimPlot.plotBars dataset empty, no plot.' 273 return None
274
275 - def plotScatter(self, points, windowsize = (500, 300),title = '', width = 1, color = 'black', 276 fillcolor = 'black', size = 2, fillstyle = '', 277 outline = 'black', marker = 'circle', 278 background = 'white', xlab = 'x', ylab = 'y', 279 xaxis = 'automatic', yaxis = 'automatic'):
280 if points != []: 281 root = Toplevel() 282 f = Frame(root) 283 try: #if it is like a Monitor, take xlab, ylab from it 284 ylab = points.ylab 285 xlab = points.tlab 286 if not title: title = points.name 287 except: 288 pass 289 scat = self.makeSymbols(points, width = width, color = color, size = size, 290 marker = marker, fillcolor = fillcolor, 291 fillstyle = fillstyle, outline = outline) 292 gr = self.makeGraphObjects([scat]) 293 graph = self.makeGraphBase(f, windowsize[0],windowsize[1], 294 title = title, xtitle = xlab, 295 ytitle = ylab, background = background) 296 graph.pack(side = LEFT, fill = BOTH, expand = YES) 297 graph.draw(gr, xaxis = xaxis, yaxis = yaxis) 298 #File menu 299 self.graphMenu(root, graph) 300 f.pack() 301 return graph 302 else: 303 print 'SimPlot.plotScatter: dataset empty, no plot.' 304 return None
305
306 - def mainloop(self):
307 self.root.mainloop()
308
309 -class GraphPoints:
310 - def __init__(self, points, attr):
311 self.points = points 312 self.scaled = self.points 313 self.attributes = {} 314 for name, value in self._attributes.items(): 315 try: 316 value = attr[name] 317 except KeyError: pass 318 self.attributes[name] = value
319
320 - def boundingBox(self):
321 return minBound(self.points), maxBound(self.points)
322
323 - def fitToScale(self, scale = (1, 1), shift = (0, 0)):
324 self.scaled = [] 325 for x, y in self.points: 326 self.scaled.append(((scale[0] * x) + shift[0],\ 327 (scale[1] * y) + shift[1])) 328 self.attributes.get('anchor', 0.0) 329 self.anchor = scale[1] * self.attributes.get('anchor', 0.0)+\ 330 shift[1]
331
332 -class GraphLine(GraphPoints):
333 - def __init__(self, points, **attr):
334 GraphPoints.__init__(self, points, attr)
335 336 _attributes = {'color': 'black', 337 'width': 1, 338 'smooth': 0, 339 'splinesteps': 12} 340
341 - def draw(self, canvas):
342 color = self.attributes['color'] 343 width = self.attributes['width'] 344 smooth = self.attributes['smooth'] 345 steps = self.attributes['splinesteps'] 346 arguments = (canvas,) 347 if smooth: 348 for i in range(len(self.points)): 349 x1, y1 = self.scaled[i] 350 arguments = arguments + (x1, y1) 351 else: 352 for i in range(len(self.points) - 1): 353 x1, y1 = self.scaled[i] 354 x2, y2 = self.scaled[i + 1] 355 arguments = arguments + (x1, y1, x2, y2) 356 apply(Line, arguments, {'fill': color, 'width': width, 357 'smooth': smooth, 'splinesteps':steps})
358
359 -class GraphSymbols(GraphPoints):
360 - def __init__(self, points, **attr):
361 GraphPoints.__init__(self, points, attr)
362 363 _attributes = {'color': 'black', 364 'width': 1, 365 'fillcolor': 'black', 366 'size': 2, 367 'fillstyle': '', 368 'outline': 'black', 369 'marker': 'circle'} 370
371 - def draw(self, canvas):
372 color = self.attributes['color'] 373 size = self.attributes['size'] 374 fillcolor = self.attributes['fillcolor'] 375 marker = self.attributes['marker'] 376 fillstyle = self.attributes['fillstyle'] 377 378 self._drawmarkers(canvas, self.scaled, marker, color, 379 fillstyle, fillcolor, size)
380
381 - def _drawmarkers(self, c, coords, marker = 'circle', color = 'black', 382 fillstyle = '', fillcolor = '', size = 2):
383 l = [] 384 f = eval('self._' + marker) 385 for xc, yc in coords: 386 id = f(c, xc, yc, outline = color, size = size, 387 fill = fillcolor, fillstyle = fillstyle) 388 if type(id) is type(()): 389 for item in id: l.append(item) 390 else: 391 l.append(id) 392 return l
393
394 - def _circle(self, c, xc, yc, size = 1, fill = '', outline = 'black', 395 fillstyle = ''):
396 id = c.create_oval(xc - 0.5, yc - 0.5, xc + 0.5, yc + 0.5, 397 fill = fill, outline = outline, 398 stipple = fillstyle) 399 c.scale(id, xc, yc, size * 5, size * 5) 400 return id
401
402 - def _dot(self, c, xc, yc, size = 1, fill = '', outline = 'black', 403 fillstyle = ''):
404 id = c.create_oval(xc - 0.5, yc - 0.5, xc + 0.5, yc + 0.5, 405 fill = fill, outline = outline, 406 stipple = fillstyle) 407 c.scale(id, xc, yc, size * 2.5, size * 2.5) 408 return id
409
410 - def _square(self, c, xc, yc, size = 1, fill = '', outline = 'black', 411 fillstyle = ''):
412 id = c.create_rectangle(xc - 0.5, yc - 0.5, xc + 0.5, yc + 0.5, 413 fill = fill, outline = outline, 414 stipple = fillstyle) 415 c.scale(id, xc, yc, size * 5, size * 5) 416 return id
417
418 - def _triangle(self, c, xc, yc, size = 1, fill = '', outline = 'black', 419 fillstyle = ''):
420 id = c.create_polygon(-0.5, 0.288675134595, 421 0.5, 0.288675134595, 422 0.0, -0.577350269189, fill = fill, 423 outline = outline, stipple = fillstyle) 424 c.move(id, xc, yc) 425 c.scale(id, xc, yc, size * 5, size * 5) 426 return id
427
428 - def _triangle_down(self, c, xc, yc, size = 1, fill = '', 429 outline = 'black', fillstyle = ''):
430 id = c.create_polygon(-0.5, -0.288675134595, 431 0.5, -0.288675134595, 432 0.0, 0.577350269189, fill = fill, 433 outline = outline, stipple = fillstyle) 434 c.move(id, xc, yc) 435 c.scale(id, xc, yc, size * 5, size * 5) 436 return id
437
438 - def _cross(self, c, xc, yc, size = 1, fill = 'black', outline = None, 439 fillstyle = ''):
440 if outline: fill = outline 441 id1 = c.create_line(xc - 0.5, yc - 0.5, xc + 0.5, yc + 0.5, 442 fill = fill) 443 id2 = c.create_line(xc - 0.5, yc + 0.5, xc + 0.5, yc - 0.5, 444 fill = fill) 445 c.scale(id1, xc, yc, size * 5, size * 5) 446 c.scale(id2, xc, yc, size * 5, size * 5) 447 return id1, id2
448
449 - def _plus(self, c, xc, yc, size = 1, fill = 'black', outline = None, 450 fillstyle = ''):
451 if outline: fill = outline 452 id1 = c.create_line(xc - 0.5, yc, xc + 0.5, yc, fill = fill) 453 id2 = c.create_line(xc, yc + 0.5, xc, yc - 0.5, fill = fill) 454 c.scale(id1, xc, yc, size * 5, size * 5) 455 c.scale(id2, xc, yc, size * 5, size * 5) 456 return id1, id2
457
458 -class GraphBars(GraphPoints):
459 - def __init__(self, points, **attr):
460 GraphPoints.__init__(self, points, attr)
461 462 _attributes = {'color': 'black', 463 'width': 1, 464 'fillcolor': 'black', 465 'size': 3, 466 'fillstyle': '', 467 'outline': 'black'} 468
469 - def draw(self, canvas):
470 color = self.attributes['color'] 471 width = self.attributes['width'] 472 fillstyle = self.attributes['fillstyle'] 473 outline = self.attributes['outline'] 474 spread = self.attributes['size'] 475 arguments = (canvas,) 476 p1, p2 = self.boundingBox() 477 for i in range(len(self.points)): 478 x1, y1 = self.scaled[i] 479 canvas.create_rectangle(x1 - spread, y1, x1 + spread, 480 self.anchor, fill = color, 481 width = width, outline = outline, 482 stipple = fillstyle)
483
484 -class GraphObjects:
485 - def __init__(self, objects):
486 self.objects = objects
487
488 - def boundingBox(self):
489 c1, c2 = self.objects[0].boundingBox() 490 for object in self.objects[1:]: 491 c1o, c2o = object.boundingBox() 492 c1 = minBound([c1, c1o]) 493 494 c2 = maxBound([c2, c2o]) 495 return c1, c2
496
497 - def fitToScale(self, scale = (1, 1), shift = (0, 0)):
498 for object in self.objects: 499 object.fitToScale(scale, shift)
500
501 - def draw(self, canvas):
502 for object in self.objects: 503 object.draw(canvas)
504
505 -class GraphBase(Frame):
506 - def __init__(self, master, width, height, 507 background = 'white', title = '', xtitle = '', ytitle = '', **kw):
508 apply(Frame.__init__, (self, master), kw) 509 self.title = title 510 self.xtitle = xtitle 511 self.ytitle = ytitle 512 self.canvas = Canvas(self, width = width, height = height, 513 background = background) 514 self.canvas.pack(fill = BOTH, expand = YES) 515 border_w = self.canvas.winfo_reqwidth() - \ 516 string.atoi(self.canvas.cget('width')) 517 border_h = self.canvas.winfo_reqheight() - \ 518 string.atoi(self.canvas.cget('height')) 519 self.border = (border_w, border_h) 520 self.canvas.bind('<Configure>', self.configure) 521 self.plotarea_size = [None, None] 522 self._setsize() 523 self.last_drawn = None 524 self.font = ('Verdana', 10)
525
526 - def configure(self, event):
527 new_width = event.width - self.border[0] 528 new_height = event.height - self.border[1] 529 width = string.atoi(self.canvas.cget('width')) 530 height = string.atoi(self.canvas.cget('height')) 531 if new_width == width and new_height == height: 532 return 533 self.canvas.configure(width = new_width, height = new_height) 534 self._setsize() 535 self.clear() 536 self.replot()
537
538 - def bind(self, *args):
539 apply(self.canvas.bind, args)
540
541 - def _setsize(self):
542 self.width = string.atoi(self.canvas.cget('width')) 543 self.height = string.atoi(self.canvas.cget('height')) 544 #self.plotarea_size[0] = 0.90 * self.width 545 #self.plotarea_size[1] = 0.90 * -self.height 546 self.plotarea_size[0] = 0.90 * self.width 547 self.plotarea_size[1] = 0.90 * -self.height 548 xo = 0.5 * (self.width - self.plotarea_size[0]) 549 yo = self.height - 0.5 * (self.height + self.plotarea_size[1]) 550 self.plotarea_origin = (xo, yo)
551
552 - def draw(self, graphics, xaxis = 'automatic', yaxis = 'automatic'):
553 554 self.last_drawn = (graphics, xaxis, yaxis) 555 p1, p2 = graphics.boundingBox() 556 xaxis = self._axisInterval(xaxis, p1[0], p2[0]) 557 yaxis = self._axisInterval(yaxis, p1[1], p2[1]) 558 text_width = [0., 0.] 559 text_height = [0., 0.] 560 if xaxis is not None: 561 p1 = xaxis[0], p1[1] 562 p2 = xaxis[1], p2[1] 563 xticks = self._ticks(xaxis[0], xaxis[1]) 564 bb = self._textBoundingBox(xticks[0][1]) 565 text_height[1] = bb[3] - bb[1] 566 text_width[0] = 0.5 * (bb[2] - bb[0]) 567 bb = self._textBoundingBox(xticks[-1][1]) 568 text_width[1] = 0.5 * (bb[2] - bb[0]) 569 else: 570 xticks = None 571 if yaxis is not None: 572 p1 = p1[0], yaxis[0] 573 p2 = p2[0], yaxis[1] 574 yticks = self._ticks(yaxis[0], yaxis[1]) 575 for y in yticks: 576 bb = self._textBoundingBox(y[1]) 577 w = bb[2] - bb[0] 578 text_width[0] = max(text_width[0], w) 579 h = 0.5 * (bb[3] - bb[1]) 580 text_height[0] = h 581 text_height[1] = max(text_height[1], h) 582 else: 583 yticks = None 584 text1 = [text_width[0], -text_height[1]] 585 text2 = [text_width[1], -text_height[0]] 586 scale = ((self.plotarea_size[0] - text1[0] - text2[0]) / \ 587 (p2[0] - p1[0]), 588 (self.plotarea_size[1] - text1[1] - text2[1]) / \ 589 (p2[1] - p1[1])) 590 shift = ((-p1[0] * scale[0]) + self.plotarea_origin[0] + \ 591 text1[0], 592 (-p1[1] * scale[1]) + self.plotarea_origin[1] + \ 593 text1[1]) 594 self._drawAxes(self.canvas, xaxis, yaxis, p1, p2, 595 scale, shift, xticks, yticks) 596 graphics.fitToScale(scale, shift) 597 graphics.draw(self.canvas)
598
599 - def _axisInterval(self, spec, lower, upper):
600 if spec is None: 601 return None 602 if spec == 'minimal': 603 if lower == upper: 604 return lower - 0.5, upper + 0.5 605 else: 606 return lower, upper 607 if spec == 'automatic': 608 range = upper - lower 609 if range == 0.: 610 return lower - 0.5, upper + 0.5 611 log = math.log10(range) 612 power = math.floor(log) 613 fraction = log - power 614 if fraction <= 0.05: 615 power = power - 1 616 grid = 10.**power 617 lower = lower - lower % grid 618 mod = upper % grid 619 if mod != 0: 620 upper = upper - mod + grid 621 return lower, upper 622 if type(spec) == type(()): 623 lower, upper = spec 624 if lower <= upper: 625 return lower, upper 626 else: 627 return upper, lower 628 raise ValueError, str(spec) + ': illegal axis specification'
629
630 - def _drawAxes(self, canvas, xaxis, yaxis, 631 bb1, bb2, scale, shift, xticks, yticks):
632 dict = {'anchor': N, 'fill': 'black'} 633 if self.font is not None: 634 dict['font'] = self.font 635 if xaxis is not None: 636 #draw x - axis 637 lower, upper = xaxis 638 text = 1 639 once = 1 640 for y, d in [(bb1[1], -3), (bb2[1], 3)]: 641 #d=.5 of tick - length 642 p1 = (scale[0] * lower) + shift[0], (scale[1] * y) + shift[1] 643 if once: pp1 = p1 644 p2 = (scale[0] * upper) + shift[0], (scale[1] * y) + shift[1] 645 if once: pp2 = p2 646 once = 0 647 Line(self.canvas, p1[0], p1[1], p2[0], p2[1], 648 fill = 'black', width = 1) 649 if xticks: 650 for x, label in xticks: 651 p = (scale[0] * x) + shift[0], \ 652 (scale[1] * y) + shift[1] 653 Line(self.canvas, p[0], p[1], p[0], p[1] + d, 654 fill = 'black', width = 1) 655 if text: 656 dict['text'] = label 657 apply(CanvasText, (self.canvas, p[0], 658 p[1] + 2), dict) ##KGM 14 Aug 03 659 text = 0 660 #write x - axis title 661 CanvasText(self.canvas,(pp2[0] - pp1[0]) / 2.+pp1[0],pp1[1] + 22, text = self.xtitle) 662 #write graph title 663 CanvasText(self.canvas,(pp2[0] - pp1[0]) / 2.+pp1[0],7, text = self.title) 664 dict['anchor'] = E 665 if yaxis is not None: 666 #draw y - axis 667 lower, upper = yaxis 668 text = 1 669 once = 1 670 for x, d in [(bb1[0], -3), (bb2[0], 3)]: 671 p1 = (scale[0] * x) + shift[0], (scale[1] * lower) + shift[1] 672 p2 = (scale[0] * x) + shift[0], (scale[1] * upper) + shift[1] 673 if once: pp1 = p1 ;pp2 = p2 674 once = 0 675 Line(self.canvas, p1[0], p1[1], p2[0], p2[1], 676 fill = 'black', width = 1) 677 if yticks: 678 for y, label in yticks: 679 p = (scale[0] * x) + shift[0], \ 680 (scale[1] * y) + shift[1] 681 Line(self.canvas, p[0], p[1], p[0] - d, p[1], 682 fill = 'black', width = 1) 683 if text: 684 dict['text'] = label 685 apply(CanvasText,(self.canvas, 686 p[0] - 4, p[1] + 2), dict) 687 text = 0 688 #write y - axis title 689 CanvasText(self.canvas, pp2[0],pp2[1] - 10, text = self.ytitle)
690
691 - def _ticks(self, lower, upper):
692 ideal = (upper - lower) / 7. 693 log = math.log10(ideal) 694 power = math.floor(log) 695 fraction = log - power 696 factor = 1. 697 error = fraction 698 for f, lf in self._multiples: 699 e = math.fabs(fraction - lf) 700 if e < error: 701 error = e 702 factor = f 703 grid = factor * 10.**power 704 if power > 3 or power < -3: 705 format = '%+7.0e' 706 elif power >= 0: 707 digits = max(1, int(power)) 708 format = '%' + `digits`+'.0f' 709 else: 710 digits = -int(power) 711 format = '%'+`digits + 2`+'.'+`digits`+'f' 712 ticks = [] 713 t = -grid * math.floor(-lower / grid) 714 while t <= upper and len(ticks) < 200: 715 ticks.append((t, format % (t,))) 716 t = t + grid 717 return ticks
718 719 _multiples = [(2., math.log10(2.)), (5., math.log10(5.))] 720
721 - def _textBoundingBox(self, text):
722 bg = self.canvas.cget('background') 723 dict = {'anchor': NW, 'text': text, 'fill': bg} 724 if self.font is not None: 725 dict['font'] = self.font 726 item = apply(CanvasText, (self.canvas, 0., 0.), dict) 727 bb = self.canvas.bbox(item) 728 self.canvas.delete(item) 729 return bb
730
731 - def replot(self):
732 if self.last_drawn is not None: 733 apply(self.draw, self.last_drawn)
734
735 - def clear(self):
736 self.canvas.delete('all')
737
738 - def postscr(self, filename = None):
739 """Write to Postscript file given by 'filename'. If none provided, 740 ask user. 741 """ 742 from tkFileDialog import asksaveasfilename 743 if not filename: 744 filename = asksaveasfilename() 745 if filename: 746 if not filename[-3:] == '.ps': 747 filename += '.ps' 748 self.canvas.postscript(width = self.width, height = self.height, file = filename)
749
750 -class TextBox(Frame):
751 - def __init__(self, master, width, height, 752 background = 'white', boxtext = '', **kw):
753 apply(Frame.__init__, (self, master), kw) 754 self.width = width 755 self.height = height 756 self.canvas = Canvas(self, width = width, height = height, 757 background = background) 758 self.canvas.pack(fill = BOTH, expand = YES)
759 #CanvasText(self.canvas, text = boxtext) 760
761 - def postscr(self):
762 #select output file 763 #from tkFileDialog import asksaveasfilename 764 filename = asksaveasfilename() 765 if filename: 766 if not filename[-3:] == '.ps': 767 filename += '.ps' 768 self.canvas.postscript(width = self.width, height = self.height, file = filename)
769 770 if __name__ == '__main__': 771 print 'SimPlot.py %s'%__version__ 772 root = Tk() 773 plt = SimPlot() 774 root.title('SimPlot example - First frame') 775 776 root1 = Tk() 777 root1.title('SimPlot example - Second frame') 778 779 """PARAMETER DEFAULTS: 780 GraphBase 781 --------- 782 background = 'white', 783 title = '', 784 xtitle = '', 785 ytitle = '' 786 787 GraphBase.draw 788 -------------- 789 xaxis = 'automatic', 790 yaxis = 'automatic') 791 792 GraphLine 793 --------- 794 color: 'black', 795 width: 1, 796 smooth: 0, 797 splinesteps: 12 798 799 GraphSymbols: 800 ------------- 801 color: 'black', 802 width: 1, 803 fillcolor: 'black', 804 size: 2, 805 fillstyle: '', 806 outline: 'black', 807 marker: 'circle'} 808 809 GraphBars 810 --------- 811 color: 'black', 812 width: 1, 813 fillcolor: 'black', 814 size: 3, 815 fillstyle: '', 816 outline: 'black' 817 """ 818 # Plot 1 -- smooth line + filled bars 819 di = 5.0 * pi / 40. 820 data = [] 821 for i in range(40): 822 data.append((float(i) * di, 823 (math.sin(float(i) * di) - math.cos(float(i) * di)))) 824 line1 = plt.makeLine(data, color = 'black', width = 1, 825 smooth = 1) 826 line1a = plt.makeBars(data[1:], color = 'blue', fillstyle = 'gray25', 827 anchor = 0.0) 828 829 830 graphObject = plt.makeGraphObjects([line1a, line1]) 831 #Second panel -- Narrow bars 832 line2 = plt.makeBars([(0, 0),(1, 145),(2,-90),(3, 147),(4, 22),(5, 31), 833 (6, 77),(7, 125),(8, 220),(9, 550),(10, 560),(11, 0)], 834 outline = 'green', color = 'red', size = 7) 835 836 837 graphObject2 = plt.makeGraphObjects([line2]) 838 839 # Third plot -- Smooth line and unsmoothed line 840 line3 = plt.makeLine([(1, 145 + 100),(2, 151 + 100),(3, 147 + 100),(4, 22 + 100),(5, 31 + 100), 841 (6, 77 + 100),(7, 125 + 100),(8, 220 + 100),(9, 550 + 100),(10, 560 + 100)], 842 color = 'blue', width = 2, smooth = 1) 843 line3a = plt.makeLine([(1, 145),(2, 151),(3, 147),(4, 22),(5, 31), 844 (6, 77),(7, 125),(8, 220),(9, 550),(10, 560)], 845 color = 'green', width = 2, smooth = 0) 846 line3b = plt.makeStep([(1, 145 + 100),(2, 151 + 100),(3, 147 + 100),(4, 22 + 100),(5, 31 + 100), 847 (6, 77 + 100),(7, 125 + 100),(8, 220 + 100),(9, 550 + 100),(10, 560 + 100)], 848 color = 'red', width = 2) 849 850 graphObject3 = plt.makeGraphObjects([line3, line3a, line3b]) 851 852 # Fourth plot -- lines with all available symbols with different 853 # outline colors / fill colors / sizes 854 855 line4 = plt.makeSymbols([(1, 100),(2, 100),(3, 100),(4, 100),(5, 100), 856 (6, 100),(7, 100),(8, 100),(9, 100),(10, 100)], 857 color = 'black', fillcolor = 'red', width = 2, marker = 'triangle') 858 line5 = plt.makeSymbols([(1, 200),(2, 200),(3, 200),(4, 200),(5, 200), 859 (6, 200),(7, 200),(8, 200),(9, 200),(10, 200)], 860 color = 'red', width = 2, marker = 'circle') 861 line6 = plt.makeSymbols([(1, 300),(2, 300),(3, 300),(4, 300),(5, 300), 862 (6, 300),(7, 300),(8, 300),(9, 300),(10, 300)], 863 color = 'green', width = 2, marker = 'dot') 864 line7 = plt.makeSymbols([(1, 400),(2, 400),(3, 400),(4, 400),(5, 400), 865 (6, 400),(7, 400),(8, 400),(9, 400),(10, 400)], 866 color = 'blue', fillcolor = 'white', 867 size = 2, width = 2, marker = 'square') 868 line8 = plt.makeSymbols([(1, 500),(2, 500),(3, 500),(4, 500),(5, 500), 869 (6, 500),(7, 500),(8, 500),(9, 500),(10, 500)], 870 color = 'yellow', width = 2, marker = 'triangle') 871 line9 = plt.makeSymbols([(1, 600),(2, 600),(3, 600),(4, 600),(5, 600), 872 (6, 600),(7, 600),(8, 600),(9, 600),(10, 600)], 873 color = 'magenta', width = 2, marker = 'cross') 874 line10 = plt.makeSymbols([(1, 700),(2, 700),(3, 700),(4, 700),(5, 700), 875 (6, 700),(7, 700),(8, 700),(9, 700),(10, 700)], 876 color = 'brown', width = 2, marker = 'plus') 877 line11 = plt.makeSymbols([(1, 800),(2, 800),(3, 800),(4, 800),(5, 800), 878 (6, 800),(7, 800),(8, 800),(9, 800),(10, 800)], 879 color = 'black', fillcolor = 'orange', 880 width = 2, marker = 'triangle_down') 881 882 883 graphObject4 = GraphObjects([line4, line5, line6, line7, line8, 884 line9, line10, line11]) 885 886 # Two panels 887 f1 = Frame(root) 888 f2 = Frame(root1) 889 890 graph={} 891 # Plots 1 and 2 in panel f1, side by side 892 graph[1] = plt.makeGraphBase(f1, 500, 300, title = 'Plot 1: 1 makeLine call, 1 makeBars call', 893 xtitle = 'the x-axis', ytitle = 'the y-axis') 894 graph[1].pack(side = LEFT, fill = BOTH, expand = YES) 895 graph[1].draw(graphObject, xaxis = 'minimal', yaxis = 'minimal') 896 897 graph[2] = plt.makeGraphBase(f1, 500, 300, title = 'Plot 2: 1 makeBars call', 898 xtitle = 'time', ytitle = 'pulse [volt]') 899 # Set side - by - side plots 900 graph[2].pack(side = LEFT, fill = BOTH, expand = YES) 901 graph[2].draw(graphObject2, 'minimal', 'automatic') 902 903 # Pack panel 1 to make it visible 904 f1.pack() 905 906 # Plots 2 and 3 in panel f2, one under the other 907 graph[3] = plt.makeGraphBase(f2, 500, 300, 908 title = 'Plot 3: 2 makeLine call (smooth, not smooth); 1 makeStep call') 909 graph[3].pack(side = TOP, fill = BOTH, expand = YES) 910 graph[3].draw(graphObject3) 911 912 graph[4] = plt.makeGraphBase(f2, 500, 300, border = 3, title = 'Plot 4: 8 makeSymbols calls') 913 # Set one - over - other configuration of plots 914 graph[4].pack(side = TOP, fill = BOTH, expand = YES) 915 graph[4].draw(graphObject4) 916 917 # Pack panel 2 to make it visible 918 f2.pack() 919 920 # Save graph[1] to Postscript file (user selects filename) 921 graph[1].postscr() 922 923 # end plotting stuff 924 925 #### Very Important -- get Tk going by starting event loop 926 plt.mainloop() 927