source: trunk/python/asaplotbase.py@ 2709

Last change on this file since 2709 was 2700, checked in by Kana Sugimoto, 12 years ago

New Development: No (just changed the order of methods)

JIRA Issue: No

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs:

Put in Release Notes: No

Module(s):

Description:

No actual change to codes.
Just changed the order of methods for future modifications.


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