From 8af797d3253067b9b929aa9ce88a4ff09662ff19 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Mon, 27 Feb 2012 14:58:23 -0500 Subject: [PATCH 1/8] Change cursors and selectors to subclass Widget. --- lib/matplotlib/widgets.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index 9b4c97c1a814..f49573b6e2dd 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -734,7 +734,7 @@ def funchspace(self, val): if self.drawon: self.targetfig.canvas.draw() -class Cursor: +class Cursor(Widget): """ A horizontal and vertical line span the axes that and move with the pointer. You can turn off the hline or vline spectively with @@ -820,7 +820,7 @@ def _update(self): return False -class MultiCursor: +class MultiCursor(Widget): """ Provide a vertical line cursor shared between multiple axes @@ -895,7 +895,7 @@ def _update(self): self.canvas.draw_idle() -class SpanSelector: +class SpanSelector(Widget): """ Select a min/max range of the x or y axes for a matplotlib Axes @@ -1085,7 +1085,7 @@ def __init__(self, ax, onselect, **kwargs): SpanSelector.__init__(self, ax, onselect, 'horizontal', **kwargs) -class RectangleSelector: +class RectangleSelector(Widget): """ Select a min/max range of the x axes for a matplotlib Axes From 5b35427c4a0e977af8f6dd31c7661ba42deb1dbe Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Mon, 27 Feb 2012 15:15:35 -0500 Subject: [PATCH 2/8] Remove call to `new_axes` in SpanSelector. * This change is in preparation for generalizing the base Widget. * It's not clear to me why `new_axes` is necessary, but I left it in (for now). --- lib/matplotlib/widgets.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index f49573b6e2dd..1c8c874a793f 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -939,8 +939,8 @@ def __init__(self, ax, onselect, direction, minspan=None, useblit=False, assert direction in ['horizontal', 'vertical'], 'Must choose horizontal or vertical for direction' self.direction = direction - self.ax = None - self.canvas = None + self.ax = ax + self.canvas = ax.figure.canvas self.visible = True self.cids=[] @@ -958,8 +958,24 @@ def __init__(self, ax, onselect, direction, minspan=None, useblit=False, self.buttonDown = False self.prev = (0, 0) - self.new_axes(ax) + self.cids.append(self.canvas.mpl_connect('motion_notify_event', self.onmove)) + self.cids.append(self.canvas.mpl_connect('button_press_event', self.press)) + self.cids.append(self.canvas.mpl_connect('button_release_event', self.release)) + self.cids.append(self.canvas.mpl_connect('draw_event', self.update_background)) + + if self.direction == 'horizontal': + trans = blended_transform_factory(self.ax.transData, self.ax.transAxes) + w,h = 0,1 + else: + trans = blended_transform_factory(self.ax.transAxes, self.ax.transData) + w,h = 1,0 + self.rect = Rectangle( (0,0), w, h, + transform=trans, + visible=False, + **self.rectprops + ) + if not self.useblit: self.ax.add_patch(self.rect) def new_axes(self,ax): self.ax = ax From e37c135cc515f267318b9528c6670b2e3ab6197c Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Mon, 27 Feb 2012 15:40:56 -0500 Subject: [PATCH 3/8] Add AxesWidget class and let it initialize `ax` and `canvas` attributes. * Renamed `Lasso.axes` to `Lasso.ax` for consistency. * Remove `Lasso.figure`, which was unused. --- lib/matplotlib/widgets.py | 74 ++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index 1c8c874a793f..442bef804a06 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -63,10 +63,23 @@ class Widget(object): drawon = True eventson = True +class AxesWidget(Widget): + """ + Widget that is connected to a single :class:`Axes`. + + Attributes + ---------- + *ax* + The parent :class:`matplotlib.axes.Axes` for the widget + *canvas* + The parent FigureCanvas for the widget + """ + def __init__(self, ax): + self.ax = ax + self.canvas = ax.figure.canvas - -class Button(Widget): +class Button(AxesWidget): """ A GUI neutral button @@ -108,6 +121,8 @@ def __init__(self, ax, label, image=None, *hovercolor* The color of the button when the mouse is over it """ + AxesWidget.__init__(self, ax) + if image is not None: ax.imshow(image) self.label = ax.text(0.5, 0.5, label, @@ -117,8 +132,6 @@ def __init__(self, ax, label, image=None, self.cnt = 0 self.observers = {} - self.ax = ax - ax.figure.canvas.mpl_connect('button_press_event', self._click) ax.figure.canvas.mpl_connect('button_release_event', self._release) @@ -179,7 +192,7 @@ def disconnect(self, cid): -class Slider(Widget): +class Slider(AxesWidget): """ A slider representing a floating point range @@ -240,7 +253,7 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt='%1.2f', knob. See the :class:`matplotlib.patches.Rectangle` documentation valid property names (e.g., *facecolor*, *edgecolor*, *alpha*, ...) """ - self.ax = ax + AxesWidget.__init__(self, ax) self.valmin = valmin self.valmax = valmax @@ -351,7 +364,7 @@ def reset(self): -class CheckButtons(Widget): +class CheckButtons(AxesWidget): """ A GUI neutral radio button @@ -385,6 +398,7 @@ def __init__(self, ax, labels, actives): A len(buttons) list of booleans indicating whether the button is active """ + AxesWidget.__init__(self, ax) ax.set_xticks([]) ax.set_yticks([]) @@ -433,8 +447,6 @@ def __init__(self, ax, labels, actives): cnt += 1 ax.figure.canvas.mpl_connect('button_press_event', self._clicked) - self.ax = ax - self.cnt = 0 self.observers = {} @@ -479,7 +491,7 @@ def disconnect(self, cid): except KeyError: pass -class RadioButtons(Widget): +class RadioButtons(AxesWidget): """ A GUI neutral radio button @@ -512,8 +524,9 @@ def __init__(self, ax, labels, active=0, activecolor='blue'): *activecolor* The color of the button when clicked """ - self.activecolor = activecolor + AxesWidget.__init__(self, ax) + self.activecolor = activecolor ax.set_xticks([]) ax.set_yticks([]) @@ -545,8 +558,6 @@ def __init__(self, ax, labels, active=0, activecolor='blue'): cnt += 1 ax.figure.canvas.mpl_connect('button_press_event', self._clicked) - self.ax = ax - self.cnt = 0 self.observers = {} @@ -734,7 +745,7 @@ def funchspace(self, val): if self.drawon: self.targetfig.canvas.draw() -class Cursor(Widget): +class Cursor(AxesWidget): """ A horizontal and vertical line span the axes that and move with the pointer. You can turn off the hline or vline spectively with @@ -757,9 +768,7 @@ def __init__(self, ax, useblit=False, **lineprops): .. plot :: mpl_examples/widgets/cursor.py """ # TODO: Is the GTKAgg limitation still true? - - self.ax = ax - self.canvas = ax.figure.canvas + AxesWidget.__init__(self, ax) self.canvas.mpl_connect('motion_notify_event', self.onmove) self.canvas.mpl_connect('draw_event', self.clear) @@ -895,7 +904,7 @@ def _update(self): self.canvas.draw_idle() -class SpanSelector(Widget): +class SpanSelector(AxesWidget): """ Select a min/max range of the x or y axes for a matplotlib Axes @@ -933,14 +942,14 @@ def __init__(self, ax, onselect, direction, minspan=None, useblit=False, Set the visible attribute to ``False`` if you want to turn off the functionality of the span selector """ + AxesWidget.__init__(self, ax) + if rectprops is None: rectprops = dict(facecolor='red', alpha=0.5) assert direction in ['horizontal', 'vertical'], 'Must choose horizontal or vertical for direction' self.direction = direction - self.ax = ax - self.canvas = ax.figure.canvas self.visible = True self.cids=[] @@ -1101,7 +1110,7 @@ def __init__(self, ax, onselect, **kwargs): SpanSelector.__init__(self, ax, onselect, 'horizontal', **kwargs) -class RectangleSelector(Widget): +class RectangleSelector(AxesWidget): """ Select a min/max range of the x axes for a matplotlib Axes @@ -1181,9 +1190,9 @@ def __init__(self, ax, onselect, drawtype='box', 2 = center mouse button (scroll wheel) 3 = right mouse button """ - self.ax = ax + AxesWidget.__init__(self, ax) + self.visible = True - self.canvas = ax.figure.canvas self.canvas.mpl_connect('motion_notify_event', self.onmove) self.canvas.mpl_connect('button_press_event', self.press) self.canvas.mpl_connect('button_release_event', self.release) @@ -1378,19 +1387,18 @@ def get_active(self): """ Get status of active mode (boolean variable)""" return self.active -class Lasso(Widget): +class Lasso(AxesWidget): def __init__(self, ax, xy, callback=None, useblit=True): - self.axes = ax - self.figure = ax.figure - self.canvas = self.figure.canvas + AxesWidget.__init__(self, ax) + self.useblit = useblit if useblit: - self.background = self.canvas.copy_from_bbox(self.axes.bbox) + self.background = self.canvas.copy_from_bbox(self.ax.bbox) x, y = xy self.verts = [(x,y)] self.line = Line2D([x], [y], linestyle='-', color='black', lw=2) - self.axes.add_line(self.line) + self.ax.add_line(self.line) self.callback = callback self.cids = [] self.cids.append(self.canvas.mpl_connect('button_release_event', self.onrelease)) @@ -1401,14 +1409,14 @@ def onrelease(self, event): self.verts.append((event.xdata, event.ydata)) if len(self.verts)>2: self.callback(self.verts) - self.axes.lines.remove(self.line) + self.ax.lines.remove(self.line) self.verts = None for cid in self.cids: self.canvas.mpl_disconnect(cid) def onmove(self, event): if self.verts is None: return - if event.inaxes != self.axes: return + if event.inaxes != self.ax: return if event.button!=1: return self.verts.append((event.xdata, event.ydata)) @@ -1416,7 +1424,7 @@ def onmove(self, event): if self.useblit: self.canvas.restore_region(self.background) - self.axes.draw_artist(self.line) - self.canvas.blit(self.axes.bbox) + self.ax.draw_artist(self.line) + self.canvas.blit(self.ax.bbox) else: self.canvas.draw_idle() From 21bca27fc3df736561c47fe74c01845f39757ed3 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Mon, 27 Feb 2012 16:13:09 -0500 Subject: [PATCH 4/8] Add `connect_event` and `disconnect_events` to AxesWidget. --- lib/matplotlib/widgets.py | 67 +++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index 442bef804a06..079b62f62cf3 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -55,7 +55,6 @@ def locked(self): return self._owner is not None - class Widget(object): """ Abstract base class for GUI neutral widgets @@ -63,6 +62,7 @@ class Widget(object): drawon = True eventson = True + class AxesWidget(Widget): """ Widget that is connected to a single :class:`Axes`. @@ -77,6 +77,15 @@ class AxesWidget(Widget): def __init__(self, ax): self.ax = ax self.canvas = ax.figure.canvas + self.cids = [] + + def connect_event(self, event, callback): + self.canvas.mpl_connect(event, callback) + self.cids.append(callback) + + def disconnect_events(self): + for c in self.cids: + self.canvas.mpl_disconnect(c) class Button(AxesWidget): @@ -133,9 +142,9 @@ def __init__(self, ax, label, image=None, self.cnt = 0 self.observers = {} - ax.figure.canvas.mpl_connect('button_press_event', self._click) - ax.figure.canvas.mpl_connect('button_release_event', self._release) - ax.figure.canvas.mpl_connect('motion_notify_event', self._motion) + self.connect_event('button_press_event', self._click) + self.connect_event('button_release_event', self._release) + self.connect_event('motion_notify_event', self._motion) ax.set_navigate(False) ax.set_axis_bgcolor(color) ax.set_xticks([]) @@ -270,10 +279,10 @@ def __init__(self, ax, label, valmin, valmax, valinit=0.5, valfmt='%1.2f', ax.set_xticks([]) ax.set_navigate(False) - ax.figure.canvas.mpl_connect('button_press_event', self._update) - ax.figure.canvas.mpl_connect('button_release_event', self._update) + self.connect_event('button_press_event', self._update) + self.connect_event('button_release_event', self._update) if dragging: - ax.figure.canvas.mpl_connect('motion_notify_event', self._update) + self.connect_event('motion_notify_event', self._update) self.label = ax.text(-0.02, 0.5, label, transform=ax.transAxes, verticalalignment='center', horizontalalignment='right') @@ -446,7 +455,7 @@ def __init__(self, ax, labels, actives): ax.add_line(l2) cnt += 1 - ax.figure.canvas.mpl_connect('button_press_event', self._clicked) + self.connect_event('button_press_event', self._clicked) self.cnt = 0 self.observers = {} @@ -557,7 +566,7 @@ def __init__(self, ax, labels, active=0, activecolor='blue'): ax.add_patch(p) cnt += 1 - ax.figure.canvas.mpl_connect('button_press_event', self._clicked) + self.connect_event('button_press_event', self._clicked) self.cnt = 0 self.observers = {} @@ -770,8 +779,8 @@ def __init__(self, ax, useblit=False, **lineprops): # TODO: Is the GTKAgg limitation still true? AxesWidget.__init__(self, ax) - self.canvas.mpl_connect('motion_notify_event', self.onmove) - self.canvas.mpl_connect('draw_event', self.clear) + self.connect_event('motion_notify_event', self.onmove) + self.connect_event('draw_event', self.clear) self.visible = True self.horizOn = True @@ -951,7 +960,6 @@ def __init__(self, ax, onselect, direction, minspan=None, useblit=False, self.direction = direction self.visible = True - self.cids=[] self.rect = None self.background = None @@ -967,10 +975,10 @@ def __init__(self, ax, onselect, direction, minspan=None, useblit=False, self.buttonDown = False self.prev = (0, 0) - self.cids.append(self.canvas.mpl_connect('motion_notify_event', self.onmove)) - self.cids.append(self.canvas.mpl_connect('button_press_event', self.press)) - self.cids.append(self.canvas.mpl_connect('button_release_event', self.release)) - self.cids.append(self.canvas.mpl_connect('draw_event', self.update_background)) + self.connect_event('motion_notify_event', self.onmove) + self.connect_event('button_press_event', self.press) + self.connect_event('button_release_event', self.release) + self.connect_event('draw_event', self.update_background) if self.direction == 'horizontal': trans = blended_transform_factory(self.ax.transData, self.ax.transAxes) @@ -989,15 +997,14 @@ def __init__(self, ax, onselect, direction, minspan=None, useblit=False, def new_axes(self,ax): self.ax = ax if self.canvas is not ax.figure.canvas: - for cid in self.cids: - self.canvas.mpl_disconnect(cid) + self.disconnect_events() self.canvas = ax.figure.canvas + self.connect_event('motion_notify_event', self.onmove) + self.connect_event('button_press_event', self.press) + self.connect_event('button_release_event', self.release) + self.connect_event('draw_event', self.update_background) - self.cids.append(self.canvas.mpl_connect('motion_notify_event', self.onmove)) - self.cids.append(self.canvas.mpl_connect('button_press_event', self.press)) - self.cids.append(self.canvas.mpl_connect('button_release_event', self.release)) - self.cids.append(self.canvas.mpl_connect('draw_event', self.update_background)) if self.direction == 'horizontal': trans = blended_transform_factory(self.ax.transData, self.ax.transAxes) w,h = 0,1 @@ -1193,10 +1200,10 @@ def __init__(self, ax, onselect, drawtype='box', AxesWidget.__init__(self, ax) self.visible = True - self.canvas.mpl_connect('motion_notify_event', self.onmove) - self.canvas.mpl_connect('button_press_event', self.press) - self.canvas.mpl_connect('button_release_event', self.release) - self.canvas.mpl_connect('draw_event', self.update_background) + self.connect_event('motion_notify_event', self.onmove) + self.connect_event('button_press_event', self.press) + self.connect_event('button_release_event', self.release) + self.connect_event('draw_event', self.update_background) self.active = True # for activation / deactivation self.to_draw = None @@ -1400,9 +1407,8 @@ def __init__(self, ax, xy, callback=None, useblit=True): self.line = Line2D([x], [y], linestyle='-', color='black', lw=2) self.ax.add_line(self.line) self.callback = callback - self.cids = [] - self.cids.append(self.canvas.mpl_connect('button_release_event', self.onrelease)) - self.cids.append(self.canvas.mpl_connect('motion_notify_event', self.onmove)) + self.connect_event('button_release_event', self.onrelease) + self.connect_event('motion_notify_event', self.onmove) def onrelease(self, event): if self.verts is not None: @@ -1411,8 +1417,7 @@ def onrelease(self, event): self.callback(self.verts) self.ax.lines.remove(self.line) self.verts = None - for cid in self.cids: - self.canvas.mpl_disconnect(cid) + self.disconnect_events() def onmove(self, event): if self.verts is None: return From c8f152aafa28b167b02440c5832e759b09d0a558 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Mon, 27 Feb 2012 21:47:40 -0500 Subject: [PATCH 5/8] 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. --- lib/matplotlib/widgets.py | 65 ++++++++++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 15 deletions(-) diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index 079b62f62cf3..4929ccf61450 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -10,6 +10,7 @@ """ from __future__ import print_function +import functools import numpy as np from mlab import dist @@ -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) @@ -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): """ @@ -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: @@ -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) @@ -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: @@ -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 @@ -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 @@ -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)) @@ -795,9 +818,10 @@ 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) @@ -805,6 +829,8 @@ def clear(self, event): 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) @@ -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) @@ -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) @@ -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': @@ -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 @@ -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) @@ -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() @@ -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': @@ -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: @@ -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 From 6baa65a592a47011cfcd593a28a2ec6f512dd7a7 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Tue, 28 Feb 2012 13:30:51 -0500 Subject: [PATCH 6/8] Fix: save correct callback ids. Also, remove unused import. --- lib/matplotlib/widgets.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index 4929ccf61450..edc4dcb7fffe 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -10,7 +10,6 @@ """ from __future__ import print_function -import functools import numpy as np from mlab import dist @@ -82,8 +81,8 @@ def __init__(self, ax): self.active = True def connect_event(self, event, callback): - self.canvas.mpl_connect(event, callback) - self.cids.append(callback) + cid = self.canvas.mpl_connect(event, callback) + self.cids.append(cid) def disconnect_events(self): for c in self.cids: From 0f0286ea39eaa95282a46c7ae245f0a2fe52a922 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Tue, 28 Feb 2012 13:41:22 -0500 Subject: [PATCH 7/8] Remove duplicate code in `SpanSelector.__init__`. --- lib/matplotlib/widgets.py | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index edc4dcb7fffe..6c1f493e7219 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -1000,24 +1000,9 @@ def __init__(self, ax, onselect, direction, minspan=None, useblit=False, self.buttonDown = False self.prev = (0, 0) - self.connect_event('motion_notify_event', self.onmove) - self.connect_event('button_press_event', self.press) - self.connect_event('button_release_event', self.release) - self.connect_event('draw_event', self.update_background) - - if self.direction == 'horizontal': - trans = blended_transform_factory(self.ax.transData, self.ax.transAxes) - w,h = 0,1 - else: - trans = blended_transform_factory(self.ax.transAxes, self.ax.transData) - w,h = 1,0 - self.rect = Rectangle( (0,0), w, h, - transform=trans, - visible=False, - **self.rectprops - ) - - if not self.useblit: self.ax.add_patch(self.rect) + # Reset canvas so that `new_axes` connects events. + self.canvas = None + self.new_axes(ax) def new_axes(self,ax): self.ax = ax From f169460af338ec51ac08804bec16a626b8481a14 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Fri, 2 Mar 2012 00:38:51 -0500 Subject: [PATCH 8/8] Fix and improve docstring. Class links were incorrect. --- lib/matplotlib/widgets.py | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index 6c1f493e7219..f099d0f2e445 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -64,15 +64,16 @@ class Widget(object): class AxesWidget(Widget): - """ - Widget that is connected to a single :class:`Axes`. - - Attributes - ---------- - *ax* - The parent :class:`matplotlib.axes.Axes` for the widget - *canvas* - The parent FigureCanvas for the widget + """Widget that is connected to a single :class:`~matplotlib.axes.Axes`. + + Attributes: + + *ax* : :class:`~matplotlib.axes.Axes` + The parent axes for the widget + *canvas* : :class:`~matplotlib.backend_bases.FigureCanvasBase` subclass + The parent figure canvs for the widget. + *active* : bool + If False, the widget does not respond to events. """ def __init__(self, ax): self.ax = ax @@ -81,10 +82,16 @@ def __init__(self, ax): self.active = True def connect_event(self, event, callback): + """Connect callback with an event. + + This should be used in lieu of `figure.canvas.mpl_connect` since this + function stores call back ids for later clean up. + """ cid = self.canvas.mpl_connect(event, callback) self.cids.append(cid) def disconnect_events(self): + """Disconnect all events created by this widget.""" for c in self.cids: self.canvas.mpl_disconnect(c)