source: trunk/python/asaplotbase.py @ 1739

Last change on this file since 1739 was 1739, checked in by Malte Marquarding, 14 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.