source: trunk/python/asaplotbase.py@ 1559

Last change on this file since 1559 was 1553, checked in by Malte Marquarding, 16 years ago

Fix for Ticket #157; numpy api changed for mask/data access in MaskedArray

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.9 KB
Line 
1"""
2ASAP plotting class based on matplotlib.
3"""
4
5import sys
6from re import match
7
8import matplotlib
9
10from matplotlib.figure import Figure, Text
11from matplotlib.font_manager import FontProperties as FP
12from matplotlib.numerix import sqrt
13from matplotlib import rc, rcParams
14from asap import rcParams as asaprcParams
15from matplotlib.ticker import OldScalarFormatter
16from matplotlib.ticker import NullLocator
17
18# API change in mpl >= 0.98
19try:
20 from matplotlib.transforms import blended_transform_factory
21except ImportError:
22 from matplotlib.transforms import blend_xy_sep_transform as blended_transform_factory
23
24if int(matplotlib.__version__.split(".")[1]) < 87:
25 print "Warning: matplotlib version < 0.87. This might cause errors. Please upgrade."
26
27#class MyFormatter(OldScalarFormatter):
28# def __call__(self, x, pos=None):
29# last = len(self.locs)-2
30# if pos==0:
31# return ''
32# else: return OldScalarFormatter.__call__(self, x, pos)
33
34class asaplotbase:
35 """
36 ASAP plotting base class based on matplotlib.
37 """
38
39 def __init__(self, rows=1, cols=0, title='', size=(8,6), buffering=False):
40 """
41 Create a new instance of the ASAPlot plotting class.
42
43 If rows < 1 then a separate call to set_panels() is required to define
44 the panel layout; refer to the doctext for set_panels().
45 """
46 self.is_dead = False
47 self.figure = Figure(figsize=size, facecolor='#ddddee')
48 self.canvas = None
49
50 self.set_title(title)
51 self.subplots = []
52 if rows > 0:
53 self.set_panels(rows, cols)
54
55 # Set matplotlib default colour sequence.
56 self.colormap = "green red black cyan magenta orange blue purple yellow pink".split()
57
58 c = asaprcParams['plotter.colours']
59 if isinstance(c,str) and len(c) > 0:
60 self.colormap = c.split()
61
62 self.lsalias = {"line": [1,0],
63 "dashdot": [4,2,1,2],
64 "dashed" : [4,2,4,2],
65 "dotted" : [1,2],
66 "dashdotdot": [4,2,1,2,1,2],
67 "dashdashdot": [4,2,4,2,1,2]
68 }
69
70 styles = "line dashed dotted dashdot".split()
71 c = asaprcParams['plotter.linestyles']
72 if isinstance(c,str) and len(c) > 0:
73 styles = c.split()
74 s = []
75 for ls in styles:
76 if self.lsalias.has_key(ls):
77 s.append(self.lsalias.get(ls))
78 else:
79 s.append('-')
80 self.linestyles = s
81
82 self.color = 0;
83 self.linestyle = 0;
84 self.attributes = {}
85 self.loc = 0
86
87 self.buffering = buffering
88
89 def clear(self):
90 """
91 Delete all lines from the plot. Line numbering will restart from 0.
92 """
93
94 for i in range(len(self.lines)):
95 self.delete(i)
96 self.axes.clear()
97 self.color = 0
98 self.lines = []
99
100 def palette(self, color, colormap=None, linestyle=0, linestyles=None):
101 if colormap:
102 if isinstance(colormap,list):
103 self.colormap = colormap
104 elif isinstance(colormap,str):
105 self.colormap = colormap.split()
106 if 0 <= color < len(self.colormap):
107 self.color = color
108 if linestyles:
109 self.linestyles = []
110 if isinstance(linestyles,list):
111 styles = linestyles
112 elif isinstance(linestyles,str):
113 styles = linestyles.split()
114 for ls in styles:
115 if self.lsalias.has_key(ls):
116 self.linestyles.append(self.lsalias.get(ls))
117 else:
118 self.linestyles.append(self.lsalias.get('line'))
119 if 0 <= linestyle < len(self.linestyles):
120 self.linestyle = linestyle
121
122 def delete(self, numbers=None):
123 """
124 Delete the 0-relative line number, default is to delete the last.
125 The remaining lines are NOT renumbered.
126 """
127
128 if numbers is None: numbers = [len(self.lines)-1]
129
130 if not hasattr(numbers, '__iter__'):
131 numbers = [numbers]
132
133 for number in numbers:
134 if 0 <= number < len(self.lines):
135 if self.lines[number] is not None:
136 for line in self.lines[number]:
137 line.set_linestyle('None')
138 self.lines[number] = None
139 self.show()
140
141 def get_line(self):
142 """
143 Get the current default line attributes.
144 """
145 return self.attributes
146
147
148 def hist(self, x=None, y=None, fmt=None, add=None):
149 """
150 Plot a histogram. N.B. the x values refer to the start of the
151 histogram bin.
152
153 fmt is the line style as in plot().
154 """
155 from matplotlib.numerix import array
156 from matplotlib.numerix.ma import MaskedArray
157
158 if x is None:
159 if y is None: return
160 x = range(len(y))
161
162 if len(x) != len(y):
163 return
164 l2 = 2*len(x)
165 x2 = range(l2)
166 y2 = range(12)
167 y2 = range(l2)
168 m2 = range(l2)
169 ymsk = None
170 ydat = None
171 if hasattr(y, "raw_mask"):
172 # numpy < 1.1
173 ymsk = y.raw_mask()
174 ydat = y.raw_data()
175 else:
176 ymsk = y.mask
177 ydat = y.data
178
179 for i in range(l2):
180 x2[i] = x[i/2]
181 m2[i] = ymsk[i/2]
182
183 y2[0] = 0.0
184 for i in range(1,l2):
185 y2[i] = ydat[(i-1)/2]
186
187 self.plot(x2, MaskedArray(y2,mask=m2,copy=0), fmt, add)
188
189
190 def hold(self, hold=True):
191 """
192 Buffer graphics until subsequently released.
193 """
194 self.buffering = hold
195
196
197 def legend(self, loc=None):
198 """
199 Add a legend to the plot.
200
201 Any other value for loc else disables the legend:
202 1: upper right
203 2: upper left
204 3: lower left
205 4: lower right
206 5: right
207 6: center left
208 7: center right
209 8: lower center
210 9: upper center
211 10: center
212
213 """
214 if isinstance(loc, int):
215 self.loc = None
216 if 0 <= loc <= 10: self.loc = loc
217 else:
218 self.loc = None
219 #self.show()
220
221
222 def plot(self, x=None, y=None, fmt=None, add=None):
223 """
224 Plot the next line in the current frame using the current line
225 attributes. The ASAPlot graphics window will be mapped and raised.
226
227 The argument list works a bit like the matlab plot() function.
228 """
229 if x is None:
230 if y is None: return
231 x = range(len(y))
232
233 elif y is None:
234 y = x
235 x = range(len(y))
236 if fmt is None:
237 line = self.axes.plot(x, y)
238 else:
239 line = self.axes.plot(x, y, fmt)
240
241 # Add to an existing line?
242 i = None
243 if add is None or len(self.lines) < add < 0:
244 # Don't add.
245 self.lines.append(line)
246 i = len(self.lines) - 1
247 else:
248 if add == 0: add = len(self.lines)
249 i = add - 1
250 self.lines[i].extend(line)
251
252 # Set/reset attributes for the line.
253 gotcolour = False
254 for k, v in self.attributes.iteritems():
255 if k == 'color': gotcolour = True
256 for segment in self.lines[i]:
257 getattr(segment, "set_%s"%k)(v)
258
259 if not gotcolour and len(self.colormap):
260 for segment in self.lines[i]:
261 getattr(segment, "set_color")(self.colormap[self.color])
262 if len(self.colormap) == 1:
263 getattr(segment, "set_dashes")(self.linestyles[self.linestyle])
264
265 self.color += 1
266 if self.color >= len(self.colormap):
267 self.color = 0
268
269 if len(self.colormap) == 1:
270 self.linestyle += 1
271 if self.linestyle >= len(self.linestyles):
272 self.linestyle = 0
273
274 self.show()
275
276
277 def position(self):
278 """
279 Use the mouse to get a position from a graph.
280 """
281
282 def position_disable(event):
283 self.register('button_press', None)
284 print '%.4f, %.4f' % (event.xdata, event.ydata)
285
286 print 'Press any mouse button...'
287 self.register('button_press', position_disable)
288
289
290 def get_region(self):
291 pos = []
292 print "Please select the bottom/left point"
293 pos.append(self.figure.ginput(n=1, show_clicks=False)[0])
294 print "Please select the top/right point"
295 pos.append(self.figure.ginput(n=1, show_clicks=False)[0])
296 return pos
297
298 def get_point(self):
299 print "Please select the point"
300 pt = self.figure.ginput(n=1, show_clicks=False)
301 if pt:
302 return pt[0]
303 else:
304 return None
305
306 def region(self):
307 """
308 Use the mouse to get a rectangular region from a plot.
309
310 The return value is [x0, y0, x1, y1] in world coordinates.
311 """
312
313 def region_start(event):
314 height = self.canvas.figure.bbox.height()
315 self.rect = {'fig': None, 'height': height,
316 'x': event.x, 'y': height - event.y,
317 'world': [event.xdata, event.ydata,
318 event.xdata, event.ydata]}
319 self.register('button_press', None)
320 self.register('motion_notify', region_draw)
321 self.register('button_release', region_disable)
322
323 def region_draw(event):
324 self.canvas._tkcanvas.delete(self.rect['fig'])
325 self.rect['fig'] = self.canvas._tkcanvas.create_rectangle(
326 self.rect['x'], self.rect['y'],
327 event.x, self.rect['height'] - event.y)
328
329 def region_disable(event):
330 self.register('motion_notify', None)
331 self.register('button_release', None)
332
333 self.canvas._tkcanvas.delete(self.rect['fig'])
334
335 self.rect['world'][2:4] = [event.xdata, event.ydata]
336 print '(%.2f, %.2f) (%.2f, %.2f)' % (self.rect['world'][0],
337 self.rect['world'][1], self.rect['world'][2],
338 self.rect['world'][3])
339
340 self.register('button_press', region_start)
341
342 # This has to be modified to block and return the result (currently
343 # printed by region_disable) when that becomes possible in matplotlib.
344
345 return [0.0, 0.0, 0.0, 0.0]
346
347
348 def register(self, type=None, func=None):
349 """
350 Register, reregister, or deregister events of type 'button_press',
351 'button_release', or 'motion_notify'.
352
353 The specified callback function should have the following signature:
354
355 def func(event)
356
357 where event is an MplEvent instance containing the following data:
358
359 name # Event name.
360 canvas # FigureCanvas instance generating the event.
361 x = None # x position - pixels from left of canvas.
362 y = None # y position - pixels from bottom of canvas.
363 button = None # Button pressed: None, 1, 2, 3.
364 key = None # Key pressed: None, chr(range(255)), shift,
365 win, or control
366 inaxes = None # Axes instance if cursor within axes.
367 xdata = None # x world coordinate.
368 ydata = None # y world coordinate.
369
370 For example:
371
372 def mouse_move(event):
373 print event.xdata, event.ydata
374
375 a = asaplot()
376 a.register('motion_notify', mouse_move)
377
378 If func is None, the event is deregistered.
379
380 Note that in TkAgg keyboard button presses don't generate an event.
381 """
382
383 if not self.events.has_key(type): return
384
385 if func is None:
386 if self.events[type] is not None:
387 # It's not clear that this does anything.
388 self.canvas.mpl_disconnect(self.events[type])
389 self.events[type] = None
390
391 # It seems to be necessary to return events to the toolbar.
392 if type == 'motion_notify':
393 self.canvas.mpl_connect(type + '_event',
394 self.figmgr.toolbar.mouse_move)
395 elif type == 'button_press':
396 self.canvas.mpl_connect(type + '_event',
397 self.figmgr.toolbar.press)
398 elif type == 'button_release':
399 self.canvas.mpl_connect(type + '_event',
400 self.figmgr.toolbar.release)
401
402 else:
403 self.events[type] = self.canvas.mpl_connect(type + '_event', func)
404
405
406 def release(self):
407 """
408 Release buffered graphics.
409 """
410 self.buffering = False
411 self.show()
412
413
414 def save(self, fname=None, orientation=None, dpi=None, papertype=None):
415 """
416 Save the plot to a file.
417
418 fname is the name of the output file. The image format is determined
419 from the file suffix; 'png', 'ps', and 'eps' are recognized. If no
420 file name is specified 'yyyymmdd_hhmmss.png' is created in the current
421 directory.
422 """
423 from asap import rcParams
424 if papertype is None:
425 papertype = rcParams['plotter.papertype']
426 if fname is None:
427 from datetime import datetime
428 dstr = datetime.now().strftime('%Y%m%d_%H%M%S')
429 fname = 'asap'+dstr+'.png'
430
431 d = ['png','.ps','eps']
432
433 from os.path import expandvars
434 fname = expandvars(fname)
435
436 if fname[-3:].lower() in d:
437 try:
438 if fname[-3:].lower() == ".ps":
439 from matplotlib import __version__ as mv
440 w = self.figure.get_figwidth()
441 h = self.figure.get_figheight()
442
443 if orientation is None:
444 # oriented
445 if w > h:
446 orientation = 'landscape'
447 else:
448 orientation = 'portrait'
449 from matplotlib.backends.backend_ps import papersize
450 pw,ph = papersize[papertype.lower()]
451 ds = None
452 if orientation == 'landscape':
453 ds = min(ph/w, pw/h)
454 else:
455 ds = min(pw/w, ph/h)
456 ow = ds * w
457 oh = ds * h
458 self.figure.set_size_inches((ow, oh))
459 self.figure.savefig(fname, orientation=orientation,
460 papertype=papertype.lower())
461 self.figure.set_size_inches((w, h))
462 print 'Written file %s' % (fname)
463 else:
464 if dpi is None:
465 dpi =150
466 self.figure.savefig(fname,dpi=dpi)
467 print 'Written file %s' % (fname)
468 except IOError, msg:
469 print 'Failed to save %s: Error msg was\n\n%s' % (fname, err)
470 return
471 else:
472 print "Invalid image type. Valid types are:"
473 print "'ps', 'eps', 'png'"
474
475
476 def set_axes(self, what=None, *args, **kwargs):
477 """
478 Set attributes for the axes by calling the relevant Axes.set_*()
479 method. Colour translation is done as described in the doctext
480 for palette().
481 """
482
483 if what is None: return
484 if what[-6:] == 'colour': what = what[:-6] + 'color'
485
486 key = "colour"
487 if kwargs.has_key(key):
488 val = kwargs.pop(key)
489 kwargs["color"] = val
490
491 getattr(self.axes, "set_%s"%what)(*args, **kwargs)
492
493 self.show(hardrefresh=False)
494
495
496 def set_figure(self, what=None, *args, **kwargs):
497 """
498 Set attributes for the figure by calling the relevant Figure.set_*()
499 method. Colour translation is done as described in the doctext
500 for palette().
501 """
502
503 if what is None: return
504 if what[-6:] == 'colour': what = what[:-6] + 'color'
505 #if what[-5:] == 'color' and len(args):
506 # args = (get_colour(args[0]),)
507
508 newargs = {}
509 for k, v in kwargs.iteritems():
510 k = k.lower()
511 if k == 'colour': k = 'color'
512 newargs[k] = v
513
514 getattr(self.figure, "set_%s"%what)(*args, **newargs)
515 self.show(hardrefresh=False)
516
517
518 def set_limits(self, xlim=None, ylim=None):
519 """
520 Set x-, and y-limits for each subplot.
521
522 xlim = [xmin, xmax] as in axes.set_xlim().
523 ylim = [ymin, ymax] as in axes.set_ylim().
524 """
525 for s in self.subplots:
526 self.axes = s['axes']
527 self.lines = s['lines']
528 oldxlim = list(self.axes.get_xlim())
529 oldylim = list(self.axes.get_ylim())
530 if xlim is not None:
531 for i in range(len(xlim)):
532 if xlim[i] is not None:
533 oldxlim[i] = xlim[i]
534 if ylim is not None:
535 for i in range(len(ylim)):
536 if ylim[i] is not None:
537 oldylim[i] = ylim[i]
538 self.axes.set_xlim(oldxlim)
539 self.axes.set_ylim(oldylim)
540 return
541
542
543 def set_line(self, number=None, **kwargs):
544 """
545 Set attributes for the specified line, or else the next line(s)
546 to be plotted.
547
548 number is the 0-relative number of a line that has already been
549 plotted. If no such line exists, attributes are recorded and used
550 for the next line(s) to be plotted.
551
552 Keyword arguments specify Line2D attributes, e.g. color='r'. Do
553
554 import matplotlib
555 help(matplotlib.lines)
556
557 The set_* methods of class Line2D define the attribute names and
558 values. For non-US usage, "colour" is recognized as synonymous with
559 "color".
560
561 Set the value to None to delete an attribute.
562
563 Colour translation is done as described in the doctext for palette().
564 """
565
566 redraw = False
567 for k, v in kwargs.iteritems():
568 k = k.lower()
569 if k == 'colour': k = 'color'
570
571 if 0 <= number < len(self.lines):
572 if self.lines[number] is not None:
573 for line in self.lines[number]:
574 getattr(line, "set_%s"%k)(v)
575 redraw = True
576 else:
577 if v is None:
578 del self.attributes[k]
579 else:
580 self.attributes[k] = v
581
582 if redraw: self.show(hardrefresh=False)
583
584
585 def set_panels(self, rows=1, cols=0, n=-1, nplots=-1, ganged=True):
586 """
587 Set the panel layout.
588
589 rows and cols, if cols != 0, specify the number of rows and columns in
590 a regular layout. (Indexing of these panels in matplotlib is row-
591 major, i.e. column varies fastest.)
592
593 cols == 0 is interpreted as a retangular layout that accomodates
594 'rows' panels, e.g. rows == 6, cols == 0 is equivalent to
595 rows == 2, cols == 3.
596
597 0 <= n < rows*cols is interpreted as the 0-relative panel number in
598 the configuration specified by rows and cols to be added to the
599 current figure as its next 0-relative panel number (i). This allows
600 non-regular panel layouts to be constructed via multiple calls. Any
601 other value of n clears the plot and produces a rectangular array of
602 empty panels. The number of these may be limited by nplots.
603 """
604 if n < 0 and len(self.subplots):
605 self.figure.clear()
606 self.set_title()
607
608 if rows < 1: rows = 1
609
610 if cols <= 0:
611 i = int(sqrt(rows))
612 if i*i < rows: i += 1
613 cols = i
614
615 if i*(i-1) >= rows: i -= 1
616 rows = i
617
618 if 0 <= n < rows*cols:
619 i = len(self.subplots)
620 self.subplots.append({})
621
622 self.subplots[i]['axes'] = self.figure.add_subplot(rows,
623 cols, n+1)
624 self.subplots[i]['lines'] = []
625
626 if i == 0: self.subplot(0)
627
628 self.rows = 0
629 self.cols = 0
630
631 else:
632 self.subplots = []
633
634 if nplots < 1 or rows*cols < nplots:
635 nplots = rows*cols
636 if ganged:
637 hsp,wsp = None,None
638 if rows > 1: hsp = 0.0001
639 if cols > 1: wsp = 0.0001
640 self.figure.subplots_adjust(wspace=wsp,hspace=hsp)
641 for i in range(nplots):
642 self.subplots.append({})
643 self.subplots[i]['lines'] = []
644 if not ganged:
645 self.subplots[i]['axes'] = self.figure.add_subplot(rows,
646 cols, i+1)
647 if asaprcParams['plotter.xaxisformatting'] == 'mpl':
648 self.subplots[i]['axes'].xaxis.set_major_formatter(OldScalarFormatter())
649 else:
650 if i == 0:
651 self.subplots[i]['axes'] = self.figure.add_subplot(rows,
652 cols, i+1)
653 if asaprcParams['plotter.xaxisformatting'] != 'mpl':
654
655 self.subplots[i]['axes'].xaxis.set_major_formatter(OldScalarFormatter())
656 else:
657 self.subplots[i]['axes'] = self.figure.add_subplot(rows,
658 cols, i+1,
659 sharex=self.subplots[0]['axes'],
660 sharey=self.subplots[0]['axes'])
661
662 # Suppress tick labelling for interior subplots.
663 if i <= (rows-1)*cols - 1:
664 if i+cols < nplots:
665 # Suppress x-labels for frames width
666 # adjacent frames
667 for tick in self.subplots[i]['axes'].xaxis.majorTicks:
668 tick.label1On = False
669 self.subplots[i]['axes'].xaxis.label.set_visible(False)
670 if i%cols:
671 # Suppress y-labels for frames not in the left column.
672 for tick in self.subplots[i]['axes'].yaxis.majorTicks:
673 tick.label1On = False
674 self.subplots[i]['axes'].yaxis.label.set_visible(False)
675 # disable the first tick of [1:ncol-1] of the last row
676 #if i+1 < nplots:
677 # self.subplots[i]['axes'].xaxis.majorTicks[0].label1On = False
678 self.rows = rows
679 self.cols = cols
680 self.subplot(0)
681
682 def tidy(self):
683 # this needs to be exceuted after the first "refresh"
684 nplots = len(self.subplots)
685 if nplots == 1: return
686 for i in xrange(nplots):
687 ax = self.subplots[i]['axes']
688 if i%self.cols:
689 ax.xaxis.majorTicks[0].label1On = False
690 else:
691 if i != 0:
692 ax.yaxis.majorTicks[-1].label1On = False
693
694
695 def set_title(self, title=None):
696 """
697 Set the title of the plot window. Use the previous title if title is
698 omitted.
699 """
700 if title is not None:
701 self.title = title
702
703 self.figure.text(0.5, 0.95, self.title, horizontalalignment='center')
704
705
706 def show(self, hardrefresh=True):
707 """
708 Show graphics dependent on the current buffering state.
709 """
710 if not hardrefresh: return
711 if not self.buffering:
712 if self.loc is not None:
713 for sp in self.subplots:
714 lines = []
715 labels = []
716 i = 0
717 for line in sp['lines']:
718 i += 1
719 if line is not None:
720 lines.append(line[0])
721 lbl = line[0].get_label()
722 if lbl == '':
723 lbl = str(i)
724 labels.append(lbl)
725
726 if len(lines):
727 fp = FP(size=rcParams['legend.fontsize'])
728 fsz = fp.get_size_in_points() - len(lines)
729 fp.set_size(max(fsz,6))
730 sp['axes'].legend(tuple(lines), tuple(labels),
731 self.loc, prop=fp)
732 else:
733 sp['axes'].legend((' '))
734
735 from matplotlib.artist import setp
736 fp = FP(size=rcParams['xtick.labelsize'])
737 xts = fp.get_size_in_points()- (self.cols)/2
738 fp = FP(size=rcParams['ytick.labelsize'])
739 yts = fp.get_size_in_points() - (self.rows)/2
740 for sp in self.subplots:
741 ax = sp['axes']
742 s = ax.title.get_size()
743 tsize = s-(self.cols+self.rows)
744 ax.title.set_size(tsize)
745 fp = FP(size=rcParams['axes.labelsize'])
746 setp(ax.get_xticklabels(), fontsize=xts)
747 setp(ax.get_yticklabels(), fontsize=yts)
748 origx = fp.get_size_in_points()
749 origy = origx
750 off = 0
751 if self.cols > 1: off = self.cols
752 xfsize = origx-off
753 ax.xaxis.label.set_size(xfsize)
754 off = 0
755 if self.rows > 1: off = self.rows
756 yfsize = origy-off
757 ax.yaxis.label.set_size(yfsize)
758
759 def subplot(self, i=None, inc=None):
760 """
761 Set the subplot to the 0-relative panel number as defined by one or
762 more invokations of set_panels().
763 """
764 l = len(self.subplots)
765 if l:
766 if i is not None:
767 self.i = i
768
769 if inc is not None:
770 self.i += inc
771
772 self.i %= l
773 self.axes = self.subplots[self.i]['axes']
774 self.lines = self.subplots[self.i]['lines']
775
776 def text(self, *args, **kwargs):
777 """
778 Add text to the figure.
779 """
780 self.figure.text(*args, **kwargs)
781 self.show()
782
783 def vline_with_label(self, x, y, label,
784 location='bottom', rotate=0.0, **kwargs):
785 """
786 Plot a vertical line with label.
787 It takes "world" values fo x and y.
788 """
789 ax = self.axes
790 # need this to suppress autoscaling during this function
791 self.axes.set_autoscale_on(False)
792 ymin = 0.0
793 ymax = 1.0
794 valign = 'center'
795 if location.lower() == 'top':
796 y = max(0.0, y)
797 elif location.lower() == 'bottom':
798 y = min(0.0, y)
799 lbloffset = 0.06
800 # a rough estimate for the bb of the text
801 if rotate > 0.0: lbloffset = 0.03*len(label)
802 peakoffset = 0.01
803 xy = None
804 xy0 = None
805 # matplotlib api change 0.98 is using transform now
806 if hasattr(ax.transData, "inverse_xy_tup"):
807 # get relative coords
808 xy0 = ax.transData.xy_tup((x,y))
809 xy = ax.transAxes.inverse_xy_tup(xy0)
810 else:
811 xy0 = ax.transData.transform((x,y))
812 # get relative coords
813 xy = ax.transAxes.inverted().transform(xy0)
814 if location.lower() == 'top':
815 ymax = 1.0-lbloffset
816 ymin = xy[1]+peakoffset
817 valign = 'bottom'
818 ylbl = ymax+0.01
819 elif location.lower() == 'bottom':
820 ymin = lbloffset
821 ymax = xy[1]-peakoffset
822 valign = 'top'
823 ylbl = ymin-0.01
824 trans = blended_transform_factory(ax.transData, ax.transAxes)
825 l = ax.axvline(x, ymin, ymax, color='black', **kwargs)
826 t = ax.text(x, ylbl ,label, verticalalignment=valign,
827 horizontalalignment='center',
828 rotation=rotate,transform = trans)
829 self.axes.set_autoscale_on(True)
Note: See TracBrowser for help on using the repository browser.