source: branches/alma/python/asaplotbase.py @ 1612

Last change on this file since 1612 was 1612, checked in by Takeshi Nakazato, 15 years ago

New Development: No

JIRA Issue: Yes CAS-729, CAS-1147

Ready to Release: Yes

Interface Changes: No

What Interface Changed: Please list interface changes

Test Programs: List test programs

Put in Release Notes: Yes

Module(s): Module Names change impacts.

Description: Describe your changes here...

I have changed that almost all log messages are output to casapy.log,
not to the terminal window. After this change, asap becomes to depend on casapy
and is not running in standalone, because asap have to import taskinit module
to access casalogger.


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