source: trunk/python/asaplot.py@ 117

Last change on this file since 117 was 117, checked in by cal103, 20 years ago

Changed from 1-relative to 0-relative as requested by Malte; retabified and
removed code commented-out in the previous revision.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.5 KB
Line 
1"""
2ASAP plotting class based on matplotlib.
3"""
4
5import sys
6from re import match
7import Tkinter as Tk
8
9print "Importing matplotlib with TkAgg backend."
10import matplotlib
11matplotlib.use("TkAgg")
12
13from matplotlib.backends import new_figure_manager, show
14from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, \
15 FigureManagerTkAgg
16from matplotlib.figure import Figure, Text
17
18# Force use of the newfangled toolbar.
19matplotlib.rcParams['toolbar'] = 'toolbar2'
20
21# Colour dictionary.
22colours = {}
23
24class ASAPlot:
25 """
26 ASAP plotting class based on matplotlib.
27 """
28
29 def __init__(self, rowcol='11', title='', size=(8,6), buffering=False):
30 """
31 Create a new instance of the ASAPlot plotting class.
32 """
33 self.window = Tk.Tk()
34
35 self.frame1 = Tk.Frame(self.window, relief=Tk.RIDGE, borderwidth=4)
36 self.frame1.pack(fill=Tk.BOTH)
37
38 self.figure = Figure(figsize=size, facecolor='#ddddee')
39 self.canvas = FigureCanvasTkAgg(self.figure, master=self.frame1)
40 self.canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
41
42 # Simply instantiating this is enough to get a working toolbar.
43 self.figmgr = FigureManagerTkAgg(self.canvas, 1, self.window)
44 self.window.wm_title('ASAPlot graphics window')
45
46 self.figure.text(0.5, 0.95, title, horizontalalignment='center')
47
48 self.rows = int(rowcol[0])
49 self.cols = int(rowcol[1])
50 self.subplots = []
51 for i in range(0,self.rows*self.cols):
52 self.subplots.append({})
53 self.subplots[i]['axes'] = self.figure.add_subplot(self.rows,
54 self.cols, i+1)
55 self.subplots[i]['lines'] = []
56
57 self.figmgr.toolbar.set_active([0])
58
59 self.axes = self.subplots[0]['axes']
60 self.lines = self.subplots[0]['lines']
61
62
63 # Set matplotlib default colour sequence.
64 self.colours = [1, 'b', 'g', 'r', 'c', 'm', 'y', 'k', 'w']
65 self.attributes = {}
66 self.loc = 1
67
68 matplotlib.interactive = True
69 self.buffering = buffering
70
71 self.canvas.show()
72
73
74 def clear(self):
75 """
76 Delete all lines from the plot. Line numbering will restart from 1.
77 """
78
79 for i in range(1,len(self.lines)+1):
80 self.delete(i)
81
82 self.axes.clear()
83 self.colours[0] = 1
84 self.lines = []
85
86
87 def delete(self, numbers=None):
88 """
89 Delete the 0-relative line number, default is to delete the last.
90 The remaining lines are NOT renumbered.
91 """
92
93 if numbers is None: numbers = [len(self.lines)-1]
94
95 if not hasattr(numbers, '__iter__'):
96 numbers = [numbers]
97
98 for number in numbers:
99 if 0 <= number < len(self.lines):
100 if self.lines[number] is not None:
101 for line in self.lines[number]:
102 line.set_linestyle('None')
103 self.lines[number] = None
104
105 self.show()
106
107
108 def get_line(self):
109 """
110 Get the current default line attributes.
111 """
112 return self.attributes
113
114
115 def hold(self, hold=True):
116 """
117 Buffer graphics until subsequently released.
118 """
119 self.buffering = hold
120
121
122 def legend(self, loc=1):
123 """
124 Add a legend to the plot.
125
126 Any other value for loc else disables the legend:
127 1: upper right
128 2: upper left
129 3: lower left
130 4: lower right
131 5: right
132 6: center left
133 7: center right
134 8: lower center
135 9: upper center
136 10: center
137
138 """
139 if 1 > loc > 10: loc = 0
140 self.loc = loc
141 self.show()
142
143
144 def map(self):
145 """
146 Reveal the ASAPlot graphics window and bring it to the top of the
147 window stack.
148 """
149 self.window.wm_deiconify()
150 self.window.lift()
151
152
153 def palette(self, pen=None, colours=None):
154 """
155 Redefine the colour sequence.
156
157 pen is the pen number to use for the next plot; this will be auto-
158 incremented.
159
160 colours is the list of pen colours. Colour may be specified via
161 the single letter values understood by matplotlib:
162
163 b: blue
164 g: green
165 r: red
166 c: cyan
167 m: magenta
168 y: yellow
169 k: black
170 w: white
171
172 or via the full name as listed in the colour dictionary which is
173 loaded by default by load_colours() from rgb.txt and listed by
174 list_colours().
175 """
176
177 if pen is None and colours is None:
178 self.colours = []
179 return
180
181 if pen is None:
182 if not len(self.colours):
183 self.colours = [1]
184 else:
185 self.colours[0] = pen
186
187 if colours is None:
188 return
189
190 cols = []
191 for col in colours:
192 cols.append(get_colour(col))
193
194 self.colours[1:] = cols
195
196 if 0 > self.colours[0] > len(self.colours):
197 self.colours[0] = 1
198
199
200 def plot(self, x=None, y=None, mask=None, fmt=None, add=None):
201 """
202 Plot the next line in the current frame using the current line
203 attributes. The ASAPlot graphics window will be mapped and raised.
204
205 The argument list works a bit like the matlab plot() function.
206 """
207
208 if x is None:
209 if y is None: return
210 x = range(len(y))
211
212 elif y is None:
213 y = x
214 x = range(len(y))
215
216 if mask is None:
217 if fmt is None:
218 line = self.axes.plot(x, y)
219 else:
220 line = self.axes.plot(x, y, fmt)
221 else:
222 segments = []
223
224 mask = list(mask)
225 i = 0
226 while mask[i:].count(1):
227 i += mask[i:].index(1)
228 if mask[i:].count(0):
229 j = i + mask[i:].index(0)
230 else:
231 j = len(mask)
232
233 segments.append(x[i:j])
234 segments.append(y[i:j])
235
236 i = j
237
238 line = self.axes.plot(*segments)
239
240 # Add to an existing line?
241 if add is None or len(self.lines) < add < 0:
242 self.lines.append(line)
243 i = len(self.lines) - 1
244 else:
245 if add == 0: add = len(self.lines)
246 i = add - 1
247 self.lines[i].extend(line)
248
249 # Set/reset attributes for the line.
250 gotcolour = False
251 for k, v in self.attributes.iteritems():
252 if k == 'color': gotcolour = True
253 for segment in self.lines[i]:
254 getattr(segment, "set_%s"%k)(v)
255
256 if not gotcolour and len(self.colours):
257 for segment in self.lines[i]:
258 getattr(segment, "set_color")(self.colours[self.colours[0]])
259
260 self.colours[0] += 1
261 if self.colours[0] >= len(self.colours):
262 self.colours[0] = 1
263
264 self.show()
265
266
267 def quit(self):
268 """
269 Destroy the ASAPlot graphics window.
270 """
271 self.window.destroy()
272
273
274 def release(self):
275 """
276 Release buffered graphics.
277 """
278 self.buffering = False
279 self.show()
280
281
282 def set_axes(self, what=None, *args, **kwargs):
283 """
284 Set attributes for the axes by calling the relevant Axes.set_*()
285 method. Colour translation is done as described in the doctext
286 for palette().
287 """
288
289 if what is None: return
290 if what[-6:] == 'colour': what = what[:-6] + 'color'
291
292 newargs = {}
293 for k, v in kwargs.iteritems():
294 k = k.lower()
295 if k == 'colour': k = 'color'
296
297 if k == 'color':
298 v = get_colour(v)
299
300 newargs[k] = v
301
302 getattr(self.axes, "set_%s"%what)(*args, **newargs)
303 self.show()
304
305
306 def set_figure(self, what=None, *args, **kwargs):
307 """
308 Set attributes for the figure by calling the relevant Figure.set_*()
309 method. Colour translation is done as described in the doctext
310 for palette().
311 """
312
313 if what is None: return
314 if what[-6:] == 'colour': what = what[:-6] + 'color'
315 if what[-5:] == 'color' and len(args):
316 args = (get_colour(args[0]),)
317
318 newargs = {}
319 for k, v in kwargs.iteritems():
320 k = k.lower()
321 if k == 'colour': k = 'color'
322
323 if k == 'color':
324 v = get_colour(v)
325
326 newargs[k] = v
327
328 getattr(self.figure, "set_%s"%what)(*args, **newargs)
329 self.show()
330
331
332 def set_line(self, number=None, **kwargs):
333 """
334 Set attributes for the specified line, or else the next line(s)
335 to be plotted.
336
337 number is the 0-relative number of a line that has already been
338 plotted. If no such line exists, attributes are recorded and used
339 for the next line(s) to be plotted.
340
341 Keyword arguments specify Line2D attributes, e.g. color='r'. Do
342
343 import matplotlib
344 help(matplotlib.lines)
345
346 The set_* methods of class Line2D define the attribute names and
347 values. For non-US usage, "colour" is recognized as synonymous with
348 "color".
349
350 Set the value to None to delete an attribute.
351
352 Colour translation is done as described in the doctext for palette().
353 """
354
355 redraw = False
356 for k, v in kwargs.iteritems():
357 k = k.lower()
358 if k == 'colour': k = 'color'
359
360 if k == 'color':
361 v = get_colour(v)
362
363 if 0 <= number < len(self.lines):
364 if self.lines[number] is not None:
365 for line in self.lines[number]:
366 getattr(line, "set_%s"%k)(v)
367 redraw = True
368 else:
369 if v is None:
370 del self.attributes[k]
371 else:
372 self.attributes[k] = v
373
374 if redraw: self.show()
375
376
377 def show(self):
378 """
379 Show graphics dependent on the current buffering state.
380 """
381 if not self.buffering:
382 if self.loc:
383 lines = []
384 labels = []
385 i = 0
386 for line in self.lines:
387 i += 1
388 if line is not None:
389 lines.append(line[0])
390 lbl = line[0].get_label()
391 if lbl == '':
392 lbl = str(i)
393 labels.append(lbl)
394
395 if len(lines):
396 self.axes.legend(tuple(lines), tuple(labels), self.loc)
397 else:
398 self.axes.legend((' '))
399
400 self.window.wm_deiconify()
401 self.canvas.show()
402
403
404 def subplot(self, col=0, row=0):
405 """
406 Set the subplot; 0-relative column and row numbers. Overrange column
407 numbers map onto successive rows.
408 """
409 i = (self.cols*row + col)%(self.rows*self.cols)
410 self.axes = self.subplots[i]['axes']
411 self.lines = self.subplots[i]['lines']
412
413
414 def terminate(self):
415 """
416 Clear the figure.
417 """
418 self.window.destroy()
419
420
421 def text(self, *args, **kwargs):
422 """
423 Add text to the figure.
424 """
425 self.figure.text(*args, **kwargs)
426 self.show()
427
428
429 def unmap(self):
430 """
431 Hide the ASAPlot graphics window.
432 """
433 self.window.wm_withdraw()
434
435
436def get_colour(colour='black'):
437 """
438 Look up a colour by name in the colour dictionary. Matches are
439 case-insensitive, insensitive to blanks, and 'gray' matches 'grey'.
440 """
441
442 if colour is None: return None
443
444 if match('[rgbcmykw]$', colour): return colour
445 if match('#[\da-fA-F]{6}$', colour): return colour
446
447 if len(colours) == 0: load_colours()
448
449 # Try a quick match.
450 if colours.has_key(colour): return colours[colour]
451
452 colour = colour.replace(' ','').lower()
453 colour = colour.replace('gray','grey')
454 for name in colours.keys():
455 if name.lower() == colour:
456 return colours[name]
457
458 return '#000000'
459
460
461def list_colours():
462 """
463 List the contents of the colour dictionary sorted by name.
464 """
465
466 if len(colours) == 0: load_colours()
467
468 names = colours.keys()
469 names.sort()
470 for name in names:
471 print colours[name], name
472
473
474def load_colours(file='/usr/local/lib/rgb.txt'):
475 """
476 Load the colour dictionary from the specified file.
477 """
478 print 'Loading colour dictionary from', file
479 rgb = open(file, 'r')
480
481 while True:
482 line = rgb.readline()
483 if line == '': break
484 tmp = line.split()
485
486 if len(tmp) == 4:
487 if tmp[3][:4] == 'gray': continue
488 if tmp[3].lower().find('gray') != -1: continue
489
490 name = tmp[3][0].upper() + tmp[3][1:]
491 r, g, b = int(tmp[0]), int(tmp[1]), int(tmp[2])
492 colours[name] = '#%2.2x%2.2x%2.2x' % (r, g, b)
Note: See TracBrowser for help on using the repository browser.