source: tags/asap2.3.1/python/asaplotbase.py@ 2803

Last change on this file since 2803 was 1561, checked in by Malte Marquarding, 15 years ago

fix for numpy >= 1.1

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