source: branches/asap-3.x/python/asaplotbase.py@ 2692

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

Replace matplotlib.numerix with numpy

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