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

Last change on this file since 1614 was 1614, 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: No

Module(s): Module Names change impacts.

Description: Describe your changes here...

  1. Added level parameter to print_log()
  2. Replaced casalog.post() to asaplog.push() + print_log().


  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.9 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 asap import asaplog
25
26if int(matplotlib.__version__.split(".")[1]) < 87:
27    #print "Warning: matplotlib version < 0.87. This might cause errors. Please upgrade."
28    asaplog.push( "matplotlib version < 0.87. This might cause errors. Please upgrade." )
29    print_log( 'WARN' )
30
31#class MyFormatter(OldScalarFormatter):
32#    def __call__(self, x, pos=None):
33#        last = len(self.locs)-2
34#        if pos==0:
35#            return ''
36#        else: return OldScalarFormatter.__call__(self, x, pos)
37
38class asaplotbase:
39    """
40    ASAP plotting base class based on matplotlib.
41    """
42
43    def __init__(self, rows=1, cols=0, title='', size=(8,6), buffering=False):
44        """
45        Create a new instance of the ASAPlot plotting class.
46
47        If rows < 1 then a separate call to set_panels() is required to define
48        the panel layout; refer to the doctext for set_panels().
49        """
50        self.is_dead = False
51        self.figure = Figure(figsize=size, facecolor='#ddddee')
52        self.canvas = None
53
54        self.set_title(title)
55        self.subplots = []
56        if rows > 0:
57            self.set_panels(rows, cols)
58
59        # Set matplotlib default colour sequence.
60        self.colormap = "green red black cyan magenta orange blue purple yellow pink".split()
61
62        c = asaprcParams['plotter.colours']
63        if isinstance(c,str) and len(c) > 0:
64            self.colormap = c.split()
65
66        self.lsalias = {"line":  [1,0],
67                        "dashdot": [4,2,1,2],
68                        "dashed" : [4,2,4,2],
69                        "dotted" : [1,2],
70                        "dashdotdot": [4,2,1,2,1,2],
71                        "dashdashdot": [4,2,4,2,1,2]
72                        }
73
74        styles = "line dashed dotted dashdot".split()
75        c = asaprcParams['plotter.linestyles']
76        if isinstance(c,str) and len(c) > 0:
77            styles = c.split()
78        s = []
79        for ls in styles:
80            if self.lsalias.has_key(ls):
81                s.append(self.lsalias.get(ls))
82            else:
83                s.append('-')
84        self.linestyles = s
85
86        self.color = 0;
87        self.linestyle = 0;
88        self.attributes = {}
89        self.loc = 0
90
91        self.buffering = buffering
92
93    def clear(self):
94        """
95        Delete all lines from the plot.  Line numbering will restart from 0.
96        """
97
98        for i in range(len(self.lines)):
99           self.delete(i)
100        self.axes.clear()
101        self.color = 0
102        self.lines = []
103
104    def palette(self, color, colormap=None, linestyle=0, linestyles=None):
105        if colormap:
106            if isinstance(colormap,list):
107                self.colormap = colormap
108            elif isinstance(colormap,str):
109                self.colormap = colormap.split()
110        if 0 <= color < len(self.colormap):
111            self.color = color
112        if linestyles:
113            self.linestyles = []
114            if isinstance(linestyles,list):
115                styles = linestyles
116            elif isinstance(linestyles,str):
117                styles = linestyles.split()
118            for ls in styles:
119                if self.lsalias.has_key(ls):
120                    self.linestyles.append(self.lsalias.get(ls))
121                else:
122                    self.linestyles.append(self.lsalias.get('line'))
123        if 0 <= linestyle < len(self.linestyles):
124            self.linestyle = linestyle
125
126    def delete(self, numbers=None):
127        """
128        Delete the 0-relative line number, default is to delete the last.
129        The remaining lines are NOT renumbered.
130        """
131
132        if numbers is None: numbers = [len(self.lines)-1]
133
134        if not hasattr(numbers, '__iter__'):
135            numbers = [numbers]
136
137        for number in numbers:
138            if 0 <= number < len(self.lines):
139                if self.lines[number] is not None:
140                    for line in self.lines[number]:
141                        line.set_linestyle('None')
142                        self.lines[number] = None
143        self.show()
144
145    def get_line(self):
146        """
147        Get the current default line attributes.
148        """
149        return self.attributes
150
151
152    def hist(self, x=None, y=None, fmt=None, add=None):
153        """
154        Plot a histogram.  N.B. the x values refer to the start of the
155        histogram bin.
156
157        fmt is the line style as in plot().
158        """
159        from matplotlib.numerix import array
160        from matplotlib.numerix.ma import MaskedArray
161        if x is None:
162            if y is None: return
163            x = range(len(y))
164
165        if len(x) != len(y):
166            return
167        l2 = 2*len(x)
168        x2 = range(l2)
169        y2 = range(12)
170        y2 = range(l2)
171        m2 = range(l2)
172        ymsk = None
173        ydat = None
174        if hasattr(y, "raw_mask"):
175            # numpy < 1.1
176            ymsk = y.raw_mask()
177            ydat = y.raw_data()
178        else:
179            ymsk = y.mask
180            ydat = y.data
181        for i in range(l2):
182            x2[i] = x[i/2]
183            m2[i] = ymsk[i/2]
184
185        y2[0] = 0.0
186        for i in range(1,l2):
187            y2[i] = ydat[(i-1)/2]
188
189        self.plot(x2, MaskedArray(y2,mask=m2,copy=0), fmt, add)
190
191
192    def hold(self, hold=True):
193        """
194        Buffer graphics until subsequently released.
195        """
196        self.buffering = hold
197
198
199    def legend(self, loc=None):
200        """
201        Add a legend to the plot.
202
203        Any other value for loc else disables the legend:
204             1: upper right
205             2: upper left
206             3: lower left
207             4: lower right
208             5: right
209             6: center left
210             7: center right
211             8: lower center
212             9: upper center
213            10: center
214
215        """
216        if isinstance(loc, int):
217            self.loc = None
218            if 0 <= loc <= 10: self.loc = loc
219        else:
220            self.loc = None
221        #self.show()
222
223
224    def plot(self, x=None, y=None, fmt=None, add=None):
225        """
226        Plot the next line in the current frame using the current line
227        attributes.  The ASAPlot graphics window will be mapped and raised.
228
229        The argument list works a bit like the matlab plot() function.
230        """
231        if x is None:
232            if y is None: return
233            x = range(len(y))
234
235        elif y is None:
236            y = x
237            x = range(len(y))
238        if fmt is None:
239            line = self.axes.plot(x, y)
240        else:
241            line = self.axes.plot(x, y, fmt)
242
243        # Add to an existing line?
244        i = None
245        if add is None or len(self.lines) < add < 0:
246            # Don't add.
247            self.lines.append(line)
248            i = len(self.lines) - 1
249        else:
250            if add == 0: add = len(self.lines)
251            i = add - 1
252            self.lines[i].extend(line)
253
254        # Set/reset attributes for the line.
255        gotcolour = False
256        for k, v in self.attributes.iteritems():
257            if k == 'color': gotcolour = True
258            for segment in self.lines[i]:
259                getattr(segment, "set_%s"%k)(v)
260
261        if not gotcolour and len(self.colormap):
262            for segment in self.lines[i]:
263                getattr(segment, "set_color")(self.colormap[self.color])
264                if len(self.colormap)  == 1:
265                    getattr(segment, "set_dashes")(self.linestyles[self.linestyle])
266
267            self.color += 1
268            if self.color >= len(self.colormap):
269                self.color = 0
270
271            if len(self.colormap) == 1:
272                self.linestyle += 1
273            if self.linestyle >= len(self.linestyles):
274                self.linestyle = 0
275
276        self.show()
277
278
279    def position(self):
280        """
281        Use the mouse to get a position from a graph.
282        """
283
284        def position_disable(event):
285            self.register('button_press', None)
286            print '%.4f, %.4f' % (event.xdata, event.ydata)
287
288        print 'Press any mouse button...'
289        self.register('button_press', position_disable)
290
291
292    def region(self):
293        """
294        Use the mouse to get a rectangular region from a plot.
295
296        The return value is [x0, y0, x1, y1] in world coordinates.
297        """
298
299        def region_start(event):
300            height = self.canvas.figure.bbox.height()
301            self.rect = {'fig': None, 'height': height,
302                         'x': event.x, 'y': height - event.y,
303                         'world': [event.xdata, event.ydata,
304                                   event.xdata, event.ydata]}
305            self.register('button_press', None)
306            self.register('motion_notify', region_draw)
307            self.register('button_release', region_disable)
308
309        def region_draw(event):
310            self.canvas._tkcanvas.delete(self.rect['fig'])
311            self.rect['fig'] = self.canvas._tkcanvas.create_rectangle(
312                                self.rect['x'], self.rect['y'],
313                                event.x, self.rect['height'] - event.y)
314
315        def region_disable(event):
316            self.register('motion_notify', None)
317            self.register('button_release', None)
318
319            self.canvas._tkcanvas.delete(self.rect['fig'])
320
321            self.rect['world'][2:4] = [event.xdata, event.ydata]
322            print '(%.2f, %.2f)  (%.2f, %.2f)' % (self.rect['world'][0],
323                self.rect['world'][1], self.rect['world'][2],
324                self.rect['world'][3])
325
326        self.register('button_press', region_start)
327
328        # This has to be modified to block and return the result (currently
329        # printed by region_disable) when that becomes possible in matplotlib.
330
331        return [0.0, 0.0, 0.0, 0.0]
332
333
334    def register(self, type=None, func=None):
335        """
336        Register, reregister, or deregister events of type 'button_press',
337        'button_release', or 'motion_notify'.
338
339        The specified callback function should have the following signature:
340
341            def func(event)
342
343        where event is an MplEvent instance containing the following data:
344
345            name                # Event name.
346            canvas              # FigureCanvas instance generating the event.
347            x      = None       # x position - pixels from left of canvas.
348            y      = None       # y position - pixels from bottom of canvas.
349            button = None       # Button pressed: None, 1, 2, 3.
350            key    = None       # Key pressed: None, chr(range(255)), shift,
351                                  win, or control
352            inaxes = None       # Axes instance if cursor within axes.
353            xdata  = None       # x world coordinate.
354            ydata  = None       # y world coordinate.
355
356        For example:
357
358            def mouse_move(event):
359                print event.xdata, event.ydata
360
361            a = asaplot()
362            a.register('motion_notify', mouse_move)
363
364        If func is None, the event is deregistered.
365
366        Note that in TkAgg keyboard button presses don't generate an event.
367        """
368
369        if not self.events.has_key(type): return
370
371        if func is None:
372            if self.events[type] is not None:
373                # It's not clear that this does anything.
374                self.canvas.mpl_disconnect(self.events[type])
375                self.events[type] = None
376
377                # It seems to be necessary to return events to the toolbar.
378                if type == 'motion_notify':
379                    self.canvas.mpl_connect(type + '_event',
380                        self.figmgr.toolbar.mouse_move)
381                elif type == 'button_press':
382                    self.canvas.mpl_connect(type + '_event',
383                        self.figmgr.toolbar.press)
384                elif type == 'button_release':
385                    self.canvas.mpl_connect(type + '_event',
386                        self.figmgr.toolbar.release)
387
388        else:
389            self.events[type] = self.canvas.mpl_connect(type + '_event', func)
390
391
392    def release(self):
393        """
394        Release buffered graphics.
395        """
396        self.buffering = False
397        self.show()
398
399
400    def save(self, fname=None, orientation=None, dpi=None, papertype=None):
401        """
402        Save the plot to a file.
403
404        fname is the name of the output file.  The image format is determined
405        from the file suffix; 'png', 'ps', and 'eps' are recognized.  If no
406        file name is specified 'yyyymmdd_hhmmss.png' is created in the current
407        directory.
408        """
409        from asap import rcParams
410        if papertype is None:
411            papertype = rcParams['plotter.papertype']
412        if fname is None:
413            from datetime import datetime
414            dstr = datetime.now().strftime('%Y%m%d_%H%M%S')
415            fname = 'asap'+dstr+'.png'
416
417        d = ['png','.ps','eps']
418
419        from os.path import expandvars
420        fname = expandvars(fname)
421
422        if fname[-3:].lower() in d:
423            try:
424                if fname[-3:].lower() == ".ps":
425                    from matplotlib import __version__ as mv
426                    w = self.figure.get_figwidth()
427                    h = self.figure.get_figheight()
428
429                    if orientation is None:
430                        # oriented
431                        if w > h:
432                            orientation = 'landscape'
433                        else:
434                            orientation = 'portrait'
435                    from matplotlib.backends.backend_ps import papersize
436                    pw,ph = papersize[papertype.lower()]
437                    ds = None
438                    if orientation == 'landscape':
439                        ds = min(ph/w, pw/h)
440                    else:
441                        ds = min(pw/w, ph/h)
442                    ow = ds * w
443                    oh = ds * h
444                    self.figure.set_size_inches((ow, oh))
445                    self.figure.savefig(fname, orientation=orientation,
446                                        papertype=papertype.lower())
447                    self.figure.set_size_inches((w, h))
448                    print 'Written file %s' % (fname)
449                else:
450                    if dpi is None:
451                        dpi =150
452                    self.figure.savefig(fname,dpi=dpi)
453                    print 'Written file %s' % (fname)
454            except IOError, msg:
455                #print 'Failed to save %s: Error msg was\n\n%s' % (fname, err)
456                print_log()
457                asaplog.push('Failed to save %s: Error msg was\n\n%s' % (fname, msg))
458                print_log( 'ERROR' )
459                return
460        else:
461            #print "Invalid image type. Valid types are:"
462            #print "'ps', 'eps', 'png'"
463            asaplog.push( "Invalid image type. Valid types are:" )
464            asaplog.push( "'ps', 'eps', 'png'" )
465            print_log('WARN')
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.xaxisformatting'] == '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.xaxisformatting'] != '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            from matplotlib.artist import setp
728            fp = FP(size=rcParams['xtick.labelsize'])
729            xts = fp.get_size_in_points()- (self.cols)/2
730            fp = FP(size=rcParams['ytick.labelsize'])
731            yts = fp.get_size_in_points() - (self.rows)/2
732            for sp in self.subplots:
733                ax = sp['axes']
734                s = ax.title.get_size()
735                tsize = s-(self.cols+self.rows)
736                ax.title.set_size(tsize)
737                fp = FP(size=rcParams['axes.labelsize'])
738                setp(ax.get_xticklabels(), fontsize=xts)
739                setp(ax.get_yticklabels(), fontsize=yts)
740                origx =  fp.get_size_in_points()
741                origy = origx
742                off = 0
743                if self.cols > 1: off = self.cols
744                xfsize = origx-off
745                ax.xaxis.label.set_size(xfsize)
746                off = 0
747                if self.rows > 1: off = self.rows
748                yfsize = origy-off
749                ax.yaxis.label.set_size(yfsize)
750
751    def subplot(self, i=None, inc=None):
752        """
753        Set the subplot to the 0-relative panel number as defined by one or
754        more invokations of set_panels().
755        """
756        l = len(self.subplots)
757        if l:
758            if i is not None:
759                self.i = i
760
761            if inc is not None:
762                self.i += inc
763
764            self.i %= l
765            self.axes  = self.subplots[self.i]['axes']
766            self.lines = self.subplots[self.i]['lines']
767
768    def text(self, *args, **kwargs):
769        """
770        Add text to the figure.
771        """
772        self.figure.text(*args, **kwargs)
773        self.show()
774
775    def vline_with_label(self, x, y, label,
776                         location='bottom', rotate=0.0, **kwargs):
777        """
778        Plot a vertical line with label.
779        It takes "world" values fo x and y.
780        """
781        ax = self.axes
782        # need this to suppress autoscaling during this function
783        self.axes.set_autoscale_on(False)
784        ymin = 0.0
785        ymax = 1.0
786        valign = 'center'
787        if location.lower() == 'top':
788            y = max(0.0, y)
789        elif location.lower() == 'bottom':
790            y = min(0.0, y)
791        lbloffset = 0.06
792        # a rough estimate for the bb of the text
793        if rotate > 0.0: lbloffset = 0.03*len(label)
794        peakoffset = 0.01
795        xy = None
796        xy0 = None
797        # matplotlib api change 0.98 is using transform now
798        if hasattr(ax.transData, "inverse_xy_tup"):
799            # get relative coords
800            xy0 = ax.transData.xy_tup((x,y))
801            xy = ax.transAxes.inverse_xy_tup(xy0)
802        else:
803            xy0 = ax.transData.transform((x,y))
804            # get relative coords
805            xy = ax.transAxes.inverted().transform(xy0)
806        if location.lower() == 'top':
807            ymax = 1.0-lbloffset
808            ymin = xy[1]+peakoffset
809            valign = 'bottom'
810            ylbl = ymax+0.01
811        elif location.lower() == 'bottom':
812            ymin = lbloffset
813            ymax = xy[1]-peakoffset
814            valign = 'top'
815            ylbl = ymin-0.01
816        trans = blended_transform_factory(ax.transData, ax.transAxes)
817        l = ax.axvline(x, ymin, ymax, color='black', **kwargs)
818        t = ax.text(x, ylbl ,label, verticalalignment=valign,
819                                    horizontalalignment='center',
820                    rotation=rotate,transform = trans)
821        self.axes.set_autoscale_on(True)
Note: See TracBrowser for help on using the repository browser.