source: branches/mergetest/python/asaplotbase.py@ 1965

Last change on this file since 1965 was 1819, checked in by Kana Sugimoto, 14 years ago

New Development: No

JIRA Issue: No (merge alma branch to trunk)

Ready for Test: Yes

Interface Changes: No

Test Programs: regressions may work

Module(s): all single dish modules

Description:

Merged all changes in alma (r1386:1818) and newfiller (r1774:1818) branch.


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