Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Add AxesWidget base class to handle event activation and clean up. #724

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Mar 17, 2012
Prev Previous commit
Next Next commit
Add default ignore method and check it in callbacks.
* Attribute name "active" can be confused with parameter to `RadioButtons`, but `RadioButtons` doesn't save that parameter as an attribute, so there's no name clash. BUT this is still really confusing to users. Consider renaming `AxesWidget.active`.
*
* * This could have been implemented as a decorator, but some callbacks wouldn't be compatible. For example, `SpanSelector.release` should not be ignored if widget was deactivated during mouse press.
*
* * `SpanSelector` and `RectangleSelector` already had `ignore` methods, but they do not call it in `update_background`. I don't change the current behavior, although it seems desirable.
  • Loading branch information
tonysyu committed Feb 28, 2012
commit c8f152aafa28b167b02440c5832e759b09d0a558
65 changes: 50 additions & 15 deletions lib/matplotlib/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"""

from __future__ import print_function
import functools
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this imported?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops. I had the ignore calls implemented as a decorator, originally. Thanks!

import numpy as np

from mlab import dist
Expand Down Expand Up @@ -78,6 +79,7 @@ def __init__(self, ax):
self.ax = ax
self.canvas = ax.figure.canvas
self.cids = []
self.active = True

def connect_event(self, event, callback):
self.canvas.mpl_connect(event, callback)
Expand All @@ -87,6 +89,14 @@ def disconnect_events(self):
for c in self.cids:
self.canvas.mpl_disconnect(c)

def ignore(self, event):
"""Return True if event should be ignored.

This method (or a version of it) should be called at the beginning
of any event callback.
"""
return not self.active


class Button(AxesWidget):
"""
Expand Down Expand Up @@ -155,6 +165,8 @@ def __init__(self, ax, label, image=None,
self._lastcolor = color

def _click(self, event):
if self.ignore(event):
return
if event.inaxes != self.ax:
return
if not self.eventson:
Expand All @@ -163,6 +175,8 @@ def _click(self, event):
event.canvas.grab_mouse(self.ax)

def _release(self, event):
if self.ignore(event):
return
if event.canvas.mouse_grabber != self.ax:
return
event.canvas.release_mouse(self.ax)
Expand All @@ -174,6 +188,8 @@ def _release(self, event):
func(event)

def _motion(self, event):
if self.ignore(event):
return
if event.inaxes==self.ax:
c = self.hovercolor
else:
Expand Down Expand Up @@ -303,6 +319,9 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt='%1.2f',

def _update(self, event):
'update the slider position'
if self.ignore(event):
return

if event.button != 1:
return

Expand Down Expand Up @@ -461,6 +480,8 @@ def __init__(self, ax, labels, actives):
self.observers = {}

def _clicked(self, event):
if self.ignore(event):
return
if event.button !=1 : return
if event.inaxes != self.ax: return

Expand Down Expand Up @@ -572,6 +593,8 @@ def __init__(self, ax, labels, active=0, activecolor='blue'):
self.observers = {}

def _clicked(self, event):
if self.ignore(event):
return
if event.button !=1 : return
if event.inaxes != self.ax: return
xy = self.ax.transAxes.inverted().transform_point((event.x, event.y))
Expand Down Expand Up @@ -795,16 +818,19 @@ def __init__(self, ax, useblit=False, **lineprops):
self.background = None
self.needclear = False


def clear(self, event):
'clear the cursor'
if self.ignore(event):
return
if self.useblit:
self.background = self.canvas.copy_from_bbox(self.ax.bbox)
self.linev.set_visible(False)
self.lineh.set_visible(False)

def onmove(self, event):
'on mouse motion draw the cursor if visible'
if self.ignore(event):
return
if event.inaxes != self.ax:
self.linev.set_visible(False)
self.lineh.set_visible(False)
Expand Down Expand Up @@ -1021,17 +1047,21 @@ def new_axes(self,ax):

def update_background(self, event):
'force an update of the background'
# If you add a call to `ignore` here, you'll want to check edge case:
# `release` can call a draw event even when `ignore` is True.
if self.useblit:
self.background = self.canvas.copy_from_bbox(self.ax.bbox)


def ignore(self, event):
'return ``True`` if *event* should be ignored'
return event.inaxes!=self.ax or not self.visible or event.button !=1
widget_off = not self.visible or not self.active
non_event = event.inaxes!=self.ax or event.button !=1
return widget_off or non_event

def press(self, event):
'on button press event'
if self.ignore(event): return
if self.ignore(event):
return
self.buttonDown = True

self.rect.set_visible(self.visible)
Expand All @@ -1041,10 +1071,12 @@ def press(self, event):
self.pressv = event.ydata
return False


def release(self, event):
'on button release event'
if self.pressv is None or (self.ignore(event) and not self.buttonDown): return
if self.ignore(event) and not self.buttonDown:
return
if self.pressv is None:
return
self.buttonDown = False

self.rect.set_visible(False)
Expand Down Expand Up @@ -1079,7 +1111,8 @@ def update(self):

def onmove(self, event):
'on motion notify event'
if self.pressv is None or self.ignore(event): return
if self.pressv is None or self.ignore(event):
return
x, y = event.xdata, event.ydata
self.prev = x, y
if self.direction == 'horizontal':
Expand Down Expand Up @@ -1255,7 +1288,6 @@ def update_background(self, event):

def ignore(self, event):
'return ``True`` if *event* should be ignored'
# If RectangleSelector is not active :
if not self.active:
return True

Expand Down Expand Up @@ -1296,10 +1328,8 @@ def ignore(self, event):

def press(self, event):
'on button press event'
# Is the correct button pressed within the correct axes?
if self.ignore(event): return


if self.ignore(event):
return
# make the drawed box/line visible get the click-coordinates,
# button, ...
self.to_draw.set_visible(self.visible)
Expand All @@ -1309,7 +1339,8 @@ def press(self, event):

def release(self, event):
'on button release event'
if self.eventpress is None or self.ignore(event): return
if self.eventpress is None or self.ignore(event):
return
# make the box/line invisible again
self.to_draw.set_visible(False)
self.canvas.draw()
Expand Down Expand Up @@ -1360,10 +1391,10 @@ def update(self):
self.canvas.draw_idle()
return False


def onmove(self, event):
'on motion notify event if box/line is wanted'
if self.eventpress is None or self.ignore(event): return
if self.eventpress is None or self.ignore(event):
return
x,y = event.xdata, event.ydata # actual position (with
# (button still pressed)
if self.drawtype == 'box':
Expand Down Expand Up @@ -1411,6 +1442,8 @@ def __init__(self, ax, xy, callback=None, useblit=True):
self.connect_event('motion_notify_event', self.onmove)

def onrelease(self, event):
if self.ignore(event):
return
if self.verts is not None:
self.verts.append((event.xdata, event.ydata))
if len(self.verts)>2:
Expand All @@ -1420,6 +1453,8 @@ def onrelease(self, event):
self.disconnect_events()

def onmove(self, event):
if self.ignore(event):
return
if self.verts is None: return
if event.inaxes != self.ax: return
if event.button!=1: return
Expand Down