source: branches/newfiller/python/asaplotbase.py @ 1798

Last change on this file since 1798 was 1798, checked in by Malte Marquarding, 14 years ago

merge -r1774:1797 from alma to newfiller

  • 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.