source: trunk/python/asaplotbase.py @ 1153

Last change on this file since 1153 was 1153, checked in by mar637, 18 years ago

lots of changes to support soft refresh, for things like text overlays, linecatlogs etc. reworked plot_lines to to auto-peak detection. added forwarding functions to matplotlib.axes. drawing functions

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