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