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

Last change on this file since 1613 was 1612, checked in by Takeshi Nakazato, 17 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
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
[1259]15from matplotlib.ticker import OldScalarFormatter
[1019]16from matplotlib.ticker import NullLocator
[1147]17
[1603]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
[1612]24from taskinit import *
25
[1095]26if int(matplotlib.__version__.split(".")[1]) < 87:
[1612]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' )
[1019]29
[1259]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)
[1019]36
[705]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):
[1019]43 """
44 Create a new instance of the ASAPlot plotting class.
[705]45
[1019]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 """
[705]49 self.is_dead = False
[1019]50 self.figure = Figure(figsize=size, facecolor='#ddddee')
[705]51 self.canvas = None
52
[1019]53 self.set_title(title)
54 self.subplots = []
55 if rows > 0:
56 self.set_panels(rows, cols)
[705]57
[710]58 # Set matplotlib default colour sequence.
59 self.colormap = "green red black cyan magenta orange blue purple yellow pink".split()
[1019]60
[710]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
[705]85 self.color = 0;
[710]86 self.linestyle = 0;
[1019]87 self.attributes = {}
88 self.loc = 0
[705]89
[1019]90 self.buffering = buffering
[705]91
92 def clear(self):
[1019]93 """
[1147]94 Delete all lines from the plot. Line numbering will restart from 0.
[1019]95 """
[705]96
[1019]97 for i in range(len(self.lines)):
98 self.delete(i)
99 self.axes.clear()
100 self.color = 0
101 self.lines = []
[705]102
[710]103 def palette(self, color, colormap=None, linestyle=0, linestyles=None):
[705]104 if colormap:
[710]105 if isinstance(colormap,list):
106 self.colormap = colormap
107 elif isinstance(colormap,str):
108 self.colormap = colormap.split()
[705]109 if 0 <= color < len(self.colormap):
110 self.color = color
[710]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
[705]124
125 def delete(self, numbers=None):
[1019]126 """
127 Delete the 0-relative line number, default is to delete the last.
128 The remaining lines are NOT renumbered.
129 """
[705]130
[1019]131 if numbers is None: numbers = [len(self.lines)-1]
[705]132
[1019]133 if not hasattr(numbers, '__iter__'):
134 numbers = [numbers]
[705]135
[1019]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()
[705]143
144 def get_line(self):
[1019]145 """
146 Get the current default line attributes.
147 """
148 return self.attributes
[705]149
150
[1086]151 def hist(self, x=None, y=None, fmt=None, add=None):
[1019]152 """
153 Plot a histogram. N.B. the x values refer to the start of the
154 histogram bin.
[705]155
[1019]156 fmt is the line style as in plot().
157 """
[1086]158 from matplotlib.numerix import array
159 from matplotlib.numerix.ma import MaskedArray
[1019]160 if x is None:
161 if y is None: return
[1023]162 x = range(len(y))
[705]163
[1019]164 if len(x) != len(y):
165 return
166 l2 = 2*len(x)
[1023]167 x2 = range(l2)
[1086]168 y2 = range(12)
[1023]169 y2 = range(l2)
170 m2 = range(l2)
[1603]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
[1023]180 for i in range(l2):
[1019]181 x2[i] = x[i/2]
[1086]182 m2[i] = ymsk[i/2]
[705]183
[1023]184 y2[0] = 0.0
[1019]185 for i in range(1,l2):
[1086]186 y2[i] = ydat[(i-1)/2]
[705]187
[1086]188 self.plot(x2, MaskedArray(y2,mask=m2,copy=0), fmt, add)
[705]189
190
191 def hold(self, hold=True):
[1019]192 """
193 Buffer graphics until subsequently released.
194 """
195 self.buffering = hold
[705]196
197
198 def legend(self, loc=None):
[1019]199 """
200 Add a legend to the plot.
[705]201
[1019]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
[705]213
[1019]214 """
[1095]215 if isinstance(loc, int):
[1098]216 self.loc = None
217 if 0 <= loc <= 10: self.loc = loc
[1095]218 else:
219 self.loc = None
220 #self.show()
[705]221
222
[1086]223 def plot(self, x=None, y=None, fmt=None, add=None):
[1019]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.
[705]227
[1019]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))
[705]233
[1019]234 elif y is None:
235 y = x
236 x = range(len(y))
[1086]237 if fmt is None:
238 line = self.axes.plot(x, y)
[1019]239 else:
[1086]240 line = self.axes.plot(x, y, fmt)
[705]241
[1019]242 # Add to an existing line?
[1086]243 i = None
[1019]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)
[705]252
[1019]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)
[705]259
[1019]260 if not gotcolour and len(self.colormap):
261 for segment in self.lines[i]:
262 getattr(segment, "set_color")(self.colormap[self.color])
[710]263 if len(self.colormap) == 1:
264 getattr(segment, "set_dashes")(self.linestyles[self.linestyle])
[1086]265
[1019]266 self.color += 1
267 if self.color >= len(self.colormap):
268 self.color = 0
[705]269
[710]270 if len(self.colormap) == 1:
271 self.linestyle += 1
[1019]272 if self.linestyle >= len(self.linestyles):
273 self.linestyle = 0
[710]274
[1019]275 self.show()
[705]276
277
278 def position(self):
[1019]279 """
280 Use the mouse to get a position from a graph.
281 """
[705]282
[1019]283 def position_disable(event):
284 self.register('button_press', None)
285 print '%.4f, %.4f' % (event.xdata, event.ydata)
[705]286
[1019]287 print 'Press any mouse button...'
288 self.register('button_press', position_disable)
[705]289
290
291 def region(self):
[1019]292 """
293 Use the mouse to get a rectangular region from a plot.
[705]294
[1019]295 The return value is [x0, y0, x1, y1] in world coordinates.
296 """
[705]297
[1019]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)
[705]307
[1019]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)
[705]313
[1019]314 def region_disable(event):
315 self.register('motion_notify', None)
316 self.register('button_release', None)
[705]317
[1019]318 self.canvas._tkcanvas.delete(self.rect['fig'])
[705]319
[1019]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])
[705]324
[1019]325 self.register('button_press', region_start)
[705]326
[1019]327 # This has to be modified to block and return the result (currently
328 # printed by region_disable) when that becomes possible in matplotlib.
[705]329
[1019]330 return [0.0, 0.0, 0.0, 0.0]
[705]331
332
333 def register(self, type=None, func=None):
[1019]334 """
335 Register, reregister, or deregister events of type 'button_press',
336 'button_release', or 'motion_notify'.
[705]337
[1019]338 The specified callback function should have the following signature:
[705]339
[1019]340 def func(event)
[705]341
[1019]342 where event is an MplEvent instance containing the following data:
[705]343
[1019]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.
[705]354
[1019]355 For example:
[705]356
[1019]357 def mouse_move(event):
358 print event.xdata, event.ydata
[705]359
[1019]360 a = asaplot()
361 a.register('motion_notify', mouse_move)
[705]362
[1019]363 If func is None, the event is deregistered.
[705]364
[1019]365 Note that in TkAgg keyboard button presses don't generate an event.
366 """
[705]367
[1019]368 if not self.events.has_key(type): return
[705]369
[1019]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
[705]375
[1019]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)
[705]386
[1019]387 else:
388 self.events[type] = self.canvas.mpl_connect(type + '_event', func)
[705]389
390
391 def release(self):
[1019]392 """
393 Release buffered graphics.
394 """
395 self.buffering = False
396 self.show()
[705]397
398
[1095]399 def save(self, fname=None, orientation=None, dpi=None, papertype=None):
[1019]400 """
401 Save the plot to a file.
[705]402
[1019]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 """
[1095]408 from asap import rcParams
409 if papertype is None:
410 papertype = rcParams['plotter.papertype']
[1019]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'
[705]415
[1019]416 d = ['png','.ps','eps']
[705]417
[1019]418 from os.path import expandvars
419 fname = expandvars(fname)
[705]420
[1019]421 if fname[-3:].lower() in d:
422 try:
[705]423 if fname[-3:].lower() == ".ps":
[1020]424 from matplotlib import __version__ as mv
[1603]425 w = self.figure.get_figwidth()
426 h = self.figure.get_figheight()
[1019]427
[705]428 if orientation is None:
[1147]429 # oriented
[705]430 if w > h:
431 orientation = 'landscape'
432 else:
433 orientation = 'portrait'
[1095]434 from matplotlib.backends.backend_ps import papersize
435 pw,ph = papersize[papertype.lower()]
[1025]436 ds = None
437 if orientation == 'landscape':
[1095]438 ds = min(ph/w, pw/h)
[1025]439 else:
[1095]440 ds = min(pw/w, ph/h)
[1025]441 ow = ds * w
442 oh = ds * h
[1603]443 self.figure.set_size_inches((ow, oh))
[1095]444 self.figure.savefig(fname, orientation=orientation,
445 papertype=papertype.lower())
[1603]446 self.figure.set_size_inches((w, h))
[705]447 print 'Written file %s' % (fname)
[1019]448 else:
[705]449 if dpi is None:
450 dpi =150
[1025]451 self.figure.savefig(fname,dpi=dpi)
[705]452 print 'Written file %s' % (fname)
[1019]453 except IOError, msg:
[1612]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' )
[1019]456 return
457 else:
[1612]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' )
[705]462
463
464 def set_axes(self, what=None, *args, **kwargs):
[1019]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 """
[705]470
[1019]471 if what is None: return
472 if what[-6:] == 'colour': what = what[:-6] + 'color'
[705]473
[1153]474 key = "colour"
475 if kwargs.has_key(key):
476 val = kwargs.pop(key)
477 kwargs["color"] = val
[705]478
[1153]479 getattr(self.axes, "set_%s"%what)(*args, **kwargs)
[705]480
[1153]481 self.show(hardrefresh=False)
[705]482
[1019]483
[705]484 def set_figure(self, what=None, *args, **kwargs):
[1019]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 """
[705]490
[1019]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]),)
[705]495
[1019]496 newargs = {}
497 for k, v in kwargs.iteritems():
498 k = k.lower()
499 if k == 'colour': k = 'color'
500 newargs[k] = v
[705]501
[1019]502 getattr(self.figure, "set_%s"%what)(*args, **newargs)
[1153]503 self.show(hardrefresh=False)
[705]504
505
506 def set_limits(self, xlim=None, ylim=None):
[1019]507 """
508 Set x-, and y-limits for each subplot.
[705]509
[1019]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']
[705]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]
[1019]522 if ylim is not None:
[705]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):
[1019]532 """
533 Set attributes for the specified line, or else the next line(s)
534 to be plotted.
[705]535
[1019]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.
[705]539
[1019]540 Keyword arguments specify Line2D attributes, e.g. color='r'. Do
[705]541
[1019]542 import matplotlib
543 help(matplotlib.lines)
[705]544
[1019]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".
[705]548
[1019]549 Set the value to None to delete an attribute.
[705]550
[1019]551 Colour translation is done as described in the doctext for palette().
552 """
[705]553
[1019]554 redraw = False
555 for k, v in kwargs.iteritems():
556 k = k.lower()
557 if k == 'colour': k = 'color'
[705]558
[1019]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
[705]569
[1153]570 if redraw: self.show(hardrefresh=False)
[705]571
572
573 def set_panels(self, rows=1, cols=0, n=-1, nplots=-1, ganged=True):
[1019]574 """
575 Set the panel layout.
[705]576
[1019]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.)
[705]580
[1019]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.
[705]584
[1019]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()
[705]595
[1019]596 if rows < 1: rows = 1
[705]597
[1019]598 if cols <= 0:
599 i = int(sqrt(rows))
600 if i*i < rows: i += 1
601 cols = i
[705]602
[1019]603 if i*(i-1) >= rows: i -= 1
604 rows = i
[705]605
[1019]606 if 0 <= n < rows*cols:
607 i = len(self.subplots)
608 self.subplots.append({})
[705]609
[1019]610 self.subplots[i]['axes'] = self.figure.add_subplot(rows,
611 cols, n+1)
612 self.subplots[i]['lines'] = []
[705]613
[1019]614 if i == 0: self.subplot(0)
[705]615
[1019]616 self.rows = 0
617 self.cols = 0
[705]618
[1019]619 else:
620 self.subplots = []
[705]621
[1019]622 if nplots < 1 or rows*cols < nplots:
623 nplots = rows*cols
[1025]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)
[1019]629 for i in range(nplots):
630 self.subplots.append({})
[1153]631 self.subplots[i]['lines'] = []
632 if not ganged:
633 self.subplots[i]['axes'] = self.figure.add_subplot(rows,
[1019]634 cols, i+1)
[1603]635 if asaprcParams['plotter.xaxisformatting'] == 'mpl':
636 self.subplots[i]['axes'].xaxis.set_major_formatter(OldScalarFormatter())
[1153]637 else:
638 if i == 0:
639 self.subplots[i]['axes'] = self.figure.add_subplot(rows,
640 cols, i+1)
[1603]641 if asaprcParams['plotter.xaxisformatting'] != 'mpl':
642
643 self.subplots[i]['axes'].xaxis.set_major_formatter(OldScalarFormatter())
[1153]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'])
[1259]649
[705]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
[1153]655 for tick in self.subplots[i]['axes'].xaxis.majorTicks:
656 tick.label1On = False
[1019]657 self.subplots[i]['axes'].xaxis.label.set_visible(False)
[705]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)
[1025]663 # disable the first tick of [1:ncol-1] of the last row
[1153]664 #if i+1 < nplots:
665 # self.subplots[i]['axes'].xaxis.majorTicks[0].label1On = False
[1019]666 self.rows = rows
667 self.cols = cols
668 self.subplot(0)
[705]669
[1153]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
[705]683 def set_title(self, title=None):
[1019]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
[705]690
[1019]691 self.figure.text(0.5, 0.95, self.title, horizontalalignment='center')
[705]692
693
[1153]694 def show(self, hardrefresh=True):
[1019]695 """
696 Show graphics dependent on the current buffering state.
697 """
[1153]698 if not hardrefresh: return
[1019]699 if not self.buffering:
700 if self.loc is not None:
[1086]701 for sp in self.subplots:
[1019]702 lines = []
703 labels = []
704 i = 0
[1086]705 for line in sp['lines']:
[1019]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)
[705]713
[1019]714 if len(lines):
[1147]715 fp = FP(size=rcParams['legend.fontsize'])
716 fsz = fp.get_size_in_points() - len(lines)
717 fp.set_size(max(fsz,6))
[1086]718 sp['axes'].legend(tuple(lines), tuple(labels),
[1147]719 self.loc, prop=fp)
[1019]720 else:
[1086]721 sp['axes'].legend((' '))
[705]722
[1086]723 from matplotlib.artist import setp
[1147]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
[1086]728 for sp in self.subplots:
729 ax = sp['axes']
[1603]730 s = ax.title.get_size()
731 tsize = s-(self.cols+self.rows)
732 ax.title.set_size(tsize)
[1147]733 fp = FP(size=rcParams['axes.labelsize'])
[1086]734 setp(ax.get_xticklabels(), fontsize=xts)
735 setp(ax.get_yticklabels(), fontsize=yts)
[1147]736 origx = fp.get_size_in_points()
737 origy = origx
[1086]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)
[705]746
747 def subplot(self, i=None, inc=None):
[1019]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
[705]756
[1019]757 if inc is not None:
758 self.i += inc
[705]759
[1019]760 self.i %= l
761 self.axes = self.subplots[self.i]['axes']
762 self.lines = self.subplots[self.i]['lines']
[705]763
764 def text(self, *args, **kwargs):
[1019]765 """
766 Add text to the figure.
767 """
768 self.figure.text(*args, **kwargs)
769 self.show()
[1147]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
[1603]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)
[1147]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
[1603]812 trans = blended_transform_factory(ax.transData, ax.transAxes)
[1147]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.