From 61ab6dfe5b9b9725b7a1d845e4f9b2bd35f3591c Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Thu, 11 Sep 2014 06:22:30 -0500 Subject: [PATCH 01/18] Factor more behavior into the _SelectorWidget class. --- lib/matplotlib/widgets.py | 365 ++++++++++++++++++++++---------------- 1 file changed, 208 insertions(+), 157 deletions(-) diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index 73cf771322f6..7fb2f8096577 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -1096,6 +1096,27 @@ def _update(self): class _SelectorWidget(AxesWidget): + + def __init__(self, ax, onselect, useblit=False, button=None): + AxesWidget.__init__(self, ax) + + self.visible = True + self.connect_default_events() + + self.background = None + self.artists = [] + self.useblit = useblit and self.canvas.supports_blit + + if button is None or isinstance(button, list): + self.validButtons = button + elif isinstance(button, int): + self.validButtons = [button] + + # will save the data (position at mouseclick) + self.eventpress = None + # will save the data (pos. at mouserelease) + self.eventrelease = None + def set_active(self, active): AxesWidget.set_active(self, active) if active: @@ -1108,6 +1129,152 @@ def update_background(self, event): if self.useblit: self.background = self.canvas.copy_from_bbox(self.ax.bbox) + def connect_default_events(self): + """Connect the major canvas events to methods."""" + 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.connect_event('key_press_event', self._on_key_press) + self.connect_event('scroll_event', self._on_scroll) + + def ignore(self, event): + """return *True* if *event* should be ignored""" + if not self.active: + return True + + # If canvas was locked + if not self.canvas.widgetlock.available(self): + return True + + if not hasattr(event, 'button'): + event.button = None + + # Only do rectangle selection if event was triggered + # with a desired button + if self.validButtons is not None: + if not event.button in self.validButtons: + return True + + # If no button was pressed yet ignore the event if it was out + # of the axes + if self.eventpress is None: + return event.inaxes != self.ax + + # If a button was pressed, check if the release-button is the + # same. If event is out of axis, limit the data coordinates to axes + # boundaries. + if event.button == self.eventpress.button and event.inaxes != self.ax: + (xdata, ydata) = self.ax.transData.inverted().transform_point( + (event.x, event.y)) + x0, x1 = self.ax.get_xbound() + y0, y1 = self.ax.get_ybound() + xdata = max(x0, xdata) + xdata = min(x1, xdata) + ydata = max(y0, ydata) + ydata = min(y1, ydata) + event.xdata = xdata + event.ydata = ydata + return False + + # If a button was pressed, check if the release-button is the + # same. + return (event.inaxes != self.ax or + event.button != self.eventpress.button) + + def update(self): + """draw using newfangled blit or oldfangled draw depending on + useblit + + """ + if self.useblit: + if self.background is not None: + self.canvas.restore_region(self.background) + for artist in self.artists: + self.ax.draw_artist(artist) + self.canvas.blit(self.ax.bbox) + else: + self.canvas.draw_idle() + return False + + def _press(self, event): + """Button press event""" + if not self.ignore(event): + self.eventpress = event + self.press(event) + + def press(self, event): + """Button press handler""" + pass + + def _release(self, event): + if not self.ignore(event) and not self.eventpress is None: + self.eventrelease = event + self.release(event) + self.eventpress = None + self.eventrelease = None + + def release(self, event): + """Button release event""" + pass + + def _onmove(self, event): + if not self.ignore(event): + self.onmove(event) + + def onmove(self, event): + """Cursor motion event""" + pass + + def _on_scroll(self, event): + if not self.ignore(event): + self.on_scroll(event) + + def on_scroll(self, event): + """Mouse scroll event""" + pass + + def _on_key_press(self, event): + if not self.ignore(event): + self.on_key_press(event) + + def on_key_press(self, event): + """Key press event""" + pass + + def set_active(self, active): + """ + Use this to activate / deactivate the Selector + from your program with an boolean parameter *active*. + """ + self.active = active + + def get_active(self): + """ Get status of active mode (boolean variable)""" + return self.active + + def set_visible(self, visible): + """ Set the visibility of our artists """ + for artist in self.artists: + artist.set_visible(visible) + + def draw_rubberband(self, x0, x1, y0, y1): + """Draw a box using the native toolkit given data coordinates + """ + height = self.canvas.figure.bbox.height + + x0, y0 = self.ax.transData.transform([x0, y0]) + x1, y1 = self.ax.transData.transform([x1, y1]) + + y1 = height - y1 + y0 = height - y0 + + w = abs(x1 - x0) + h = abs(y1 - y0) + + rect = [int(val)for val in (min(x0, x1), min(y0, y1), w, h)] + self.canvas.drawRectangle(rect) + class SpanSelector(_SelectorWidget): """ @@ -1131,7 +1298,8 @@ def onselect(vmin, vmax): """ def __init__(self, ax, onselect, direction, minspan=None, useblit=False, - rectprops=None, onmove_callback=None, span_stays=False): + rectprops=None, onmove_callback=None, span_stays=False, + button=None): """ Create a span selector in *ax*. When a selection is made, clear the span and call *onselect* with:: @@ -1152,8 +1320,18 @@ def __init__(self, ax, onselect, direction, minspan=None, useblit=False, If *span_stays* is True, the span stays visble after making a valid selection. + + *button* is a list of integers indicating which mouse buttons should + be used for selection. You can also specify a single + integer if only a single button is desired. Default is *None*, + which does not limit which button can be used. + + Note, typically: + 1 = left mouse button + 2 = center mouse button (scroll wheel) + 3 = right mouse button """ - AxesWidget.__init__(self, ax) + _SelectorWidget.__init__(self, ax, onselect, useblit=useblit, button=button) if rectprops is None: rectprops = dict(facecolor='red', alpha=0.5) @@ -1161,25 +1339,17 @@ 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.visible = True - self.rect = None - self.background = None self.pressv = None self.rectprops = rectprops - self.onselect = onselect self.onmove_callback = onmove_callback self.minspan = minspan self.span_stays = span_stays # Needed when dragging out of axes - self.buttonDown = False self.prev = (0, 0) - # Set useblit based on original canvas. - self.useblit = useblit and self.canvas.supports_blit - # Reset canvas so that `new_axes` connects events. self.canvas = None self.new_axes(ax) @@ -1190,10 +1360,7 @@ def new_axes(self, ax): 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.connect_default_events() if self.direction == 'horizontal': trans = blended_transform_factory(self.ax.transData, @@ -1216,22 +1383,14 @@ def new_axes(self, ax): if not self.useblit: self.ax.add_patch(self.rect) + self.artists = [self.rect] def ignore(self, event): """return *True* if *event* should be ignored""" - # If canvas was locked - if not self.canvas.widgetlock.available(self): - return True - 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 + return _SelectorWidget.ignore(self, event) or not self.visible def press(self, event): """on button press event""" - if self.ignore(event): - return - self.buttonDown = True - self.rect.set_visible(self.visible) if self.span_stays: self.stay_rect.set_visible(False) @@ -1244,8 +1403,6 @@ def press(self, event): def release(self, event): """on button release event""" - if self.ignore(event) and not self.buttonDown: - return if self.pressv is None: return self.buttonDown = False @@ -1275,21 +1432,6 @@ def release(self, event): self.pressv = None return False - def update(self): - """ - Draw using newfangled blit or oldfangled draw depending - on *useblit* - """ - if self.useblit: - if self.background is not None: - self.canvas.restore_region(self.background) - self.ax.draw_artist(self.rect) - self.canvas.blit(self.ax.bbox) - else: - self.canvas.draw_idle() - - return False - def onmove(self, event): """on motion notify event""" if self.pressv is None or self.ignore(event): @@ -1409,16 +1551,9 @@ def __init__(self, ax, onselect, drawtype='box', 2 = center mouse button (scroll wheel) 3 = right mouse button """ - AxesWidget.__init__(self, ax) - - self.visible = True - 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) + _SelectorWidget.__init__(self, ax, onselect, useblit=useblit, button=button) self.to_draw = None - self.background = None if drawtype == 'none': drawtype = 'line' # draw a line but make it @@ -1441,85 +1576,26 @@ def __init__(self, ax, onselect, drawtype='box', **self.lineprops) self.ax.add_line(self.to_draw) - self.onselect = onselect - self.useblit = useblit and self.canvas.supports_blit self.minspanx = minspanx self.minspany = minspany - if button is None or isinstance(button, list): - self.validButtons = button - elif isinstance(button, int): - self.validButtons = [button] - assert(spancoords in ('data', 'pixels')) self.spancoords = spancoords self.drawtype = drawtype - # will save the data (position at mouseclick) - self.eventpress = None - # will save the data (pos. at mouserelease) - self.eventrelease = None - - def ignore(self, event): - """return *True* if *event* should be ignored""" - if not self.active: - return True - - # If canvas was locked - if not self.canvas.widgetlock.available(self): - return True - - # Only do rectangle selection if event was triggered - # with a desired button - if self.validButtons is not None: - if not event.button in self.validButtons: - return True - - # If no button was pressed yet ignore the event if it was out - # of the axes - if self.eventpress is None: - return event.inaxes != self.ax - - # If a button was pressed, check if the release-button is the - # same. If event is out of axis, limit the data coordinates to axes - # boundaries. - if event.button == self.eventpress.button and event.inaxes != self.ax: - (xdata, ydata) = self.ax.transData.inverted().transform_point( - (event.x, event.y)) - x0, x1 = self.ax.get_xbound() - y0, y1 = self.ax.get_ybound() - xdata = max(x0, xdata) - xdata = min(x1, xdata) - ydata = max(y0, ydata) - ydata = min(y1, ydata) - event.xdata = xdata - event.ydata = ydata - return False - - # If a button was pressed, check if the release-button is the - # same. - return (event.inaxes != self.ax or - event.button != self.eventpress.button) + self.artists = [self.to_draw] def press(self, event): """on button press event""" - if self.ignore(event): - return - # make the drawed box/line visible get the click-coordinates, - # button, ... + # make the drawed box/line visible self.to_draw.set_visible(self.visible) - self.eventpress = event return False def release(self, event): """on button release event""" - 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() - # release coordinates, button, ... - self.eventrelease = event if self.spancoords == 'data': xmin, ymin = self.eventpress.xdata, self.eventpress.ydata @@ -1550,22 +1626,6 @@ def release(self, event): self.onselect(self.eventpress, self.eventrelease) # call desired function - self.eventpress = None # reset the variables to their - self.eventrelease = None # inital values - return False - - def update(self): - """draw using newfangled blit or oldfangled draw depending on - useblit - - """ - if self.useblit: - if self.background is not None: - self.canvas.restore_region(self.background) - self.ax.draw_artist(self.to_draw) - self.canvas.blit(self.ax.bbox) - else: - self.canvas.draw_idle() return False def onmove(self, event): @@ -1625,13 +1685,22 @@ def onselect(verts): print verts lasso = LassoSelector(ax, onselect) + *button* is a list of integers indicating which mouse buttons should + be used for rectangle selection. You can also specify a single + integer if only a single button is desired. Default is *None*, + which does not limit which button can be used. + + Note, typically: + 1 = left mouse button + 2 = center mouse button (scroll wheel) + 3 = right mouse button + """ - def __init__(self, ax, onselect=None, useblit=True, lineprops=None): - AxesWidget.__init__(self, ax) + def __init__(self, ax, onselect=None, useblit=True, lineprops=None, + button=None): + _SelectorWidget.__init__(self, ax, onselect, useblit=useblit, button=button) - self.useblit = useblit and self.canvas.supports_blit - self.onselect = onselect self.verts = None if lineprops is None: @@ -1639,52 +1708,34 @@ def __init__(self, ax, onselect=None, useblit=True, lineprops=None): self.line = Line2D([], [], **lineprops) self.line.set_visible(False) self.ax.add_line(self.line) - - self.connect_event('button_press_event', self.onpress) - self.connect_event('button_release_event', self.onrelease) - self.connect_event('motion_notify_event', self.onmove) - self.connect_event('draw_event', self.update_background) - - def ignore(self, event): - wrong_button = hasattr(event, 'button') and event.button != 1 - return not self.active or wrong_button + self.artists = [self.line] def onpress(self, event): - if self.ignore(event) or event.inaxes != self.ax: - return + self.press(event) + + def press(self, event): self.verts = [(event.xdata, event.ydata)] self.line.set_visible(True) def onrelease(self, event): - if self.ignore(event): - return + self.release(event) + + def release(self, event): if self.verts is not None: - if event.inaxes == self.ax: - self.verts.append((event.xdata, event.ydata)) + self.verts.append((event.xdata, event.ydata)) self.onselect(self.verts) self.line.set_data([[], []]) self.line.set_visible(False) self.verts = None def onmove(self, event): - if self.ignore(event) or event.inaxes != self.ax: - return if self.verts is None: return - if event.inaxes != self.ax: - return - if event.button != 1: - return self.verts.append((event.xdata, event.ydata)) self.line.set_data(list(zip(*self.verts))) - if self.useblit: - self.canvas.restore_region(self.background) - self.ax.draw_artist(self.line) - self.canvas.blit(self.ax.bbox) - else: - self.canvas.draw_idle() + self.update() class Lasso(AxesWidget): From e43c7884cae6007801ff70ff4027d66223be29d3 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Thu, 11 Sep 2014 20:25:46 -0500 Subject: [PATCH 02/18] Fix indentation --- lib/matplotlib/widgets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index 7fb2f8096577..38714cac8364 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -1100,8 +1100,8 @@ class _SelectorWidget(AxesWidget): def __init__(self, ax, onselect, useblit=False, button=None): AxesWidget.__init__(self, ax) - self.visible = True - self.connect_default_events() + self.visible = True + self.connect_default_events() self.background = None self.artists = [] From ea732ef0d1f48e8c2d49a483a6c6b3f73dd5fbab Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Thu, 11 Sep 2014 21:06:40 -0500 Subject: [PATCH 03/18] Put onselect in __init__, fix syntax error, make sure lines are animated. --- lib/matplotlib/widgets.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index 38714cac8364..b2825ae98689 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -1101,6 +1101,7 @@ def __init__(self, ax, onselect, useblit=False, button=None): AxesWidget.__init__(self, ax) self.visible = True + self.onselect = onselect self.connect_default_events() self.background = None @@ -1130,7 +1131,7 @@ def update_background(self, event): self.background = self.canvas.copy_from_bbox(self.ax.bbox) def connect_default_events(self): - """Connect the major canvas events to methods."""" + """Connect the major canvas events to methods.""" self.connect_event('motion_notify_event', self._onmove) self.connect_event('button_press_event', self._press) self.connect_event('button_release_event', self._release) @@ -1357,7 +1358,8 @@ 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: - self.disconnect_events() + if not self.canvas is None: + self.disconnect_events() self.canvas = ax.figure.canvas self.connect_default_events() @@ -1572,6 +1574,8 @@ def __init__(self, ax, onselect, drawtype='box', lineprops = dict(color='black', linestyle='-', linewidth=2, alpha=0.5) self.lineprops = lineprops + if useblit: + self.lineprops['animated'] = True self.to_draw = Line2D([0, 0], [0, 0], visible=False, **self.lineprops) self.ax.add_line(self.to_draw) @@ -1705,6 +1709,8 @@ def __init__(self, ax, onselect=None, useblit=True, lineprops=None, if lineprops is None: lineprops = dict() + if useblit: + lineprops['animated'] = True self.line = Line2D([], [], **lineprops) self.line.set_visible(False) self.ax.add_line(self.line) From 900a6ea09018d534ea62a330513ae929156f884d Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Thu, 11 Sep 2014 21:07:58 -0500 Subject: [PATCH 04/18] Add tests for the selection widgets --- lib/matplotlib/tests/test_widgets.py | 160 +++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 lib/matplotlib/tests/test_widgets.py diff --git a/lib/matplotlib/tests/test_widgets.py b/lib/matplotlib/tests/test_widgets.py new file mode 100644 index 000000000000..fb1e68ebf19e --- /dev/null +++ b/lib/matplotlib/tests/test_widgets.py @@ -0,0 +1,160 @@ +from __future__ import (absolute_import, division, print_function, + unicode_literals) + +try: + # mock in python 3.3+ + from unittest import mock +except ImportError: + import mock + +import matplotlib.widgets as widgets +import matplotlib.pyplot as plt + + +def get_event(ax, button=1, xdata=0, ydata=0, key=None, step=1): + """ + *name* + the event name + + *canvas* + the FigureCanvas instance generating the event + + *guiEvent* + the GUI event that triggered the matplotlib event + + *x* + x position - pixels from left of canvas + + *y* + y position - pixels from bottom of canvas + + *inaxes* + the :class:`~matplotlib.axes.Axes` instance if mouse is over axes + + *xdata* + x coord of mouse in data coords + + *ydata* + y coord of mouse in data coords + + *button* + button pressed None, 1, 2, 3, 'up', 'down' (up and down are used + for scroll events) + + *key* + the key depressed when the mouse event triggered (see + :class:`KeyEvent`) + + *step* + number of scroll steps (positive for 'up', negative for 'down') + """ + event = mock.Mock() + event.button = button + event.x, event.y = ax.transData.transform((xdata, ydata)) + event.xdata, event.ydata = xdata, ydata + event.inaxes = ax + event.canvas = ax.figure.canvas + event.key = key + event.step = step + event.guiEvent = None + event.name = 'Custom' + return event + + +def check_rectangle(**kwargs): + ax = plt.gca() + ax.plot([0, 200], [0, 200]) + + def onselect(epress, erelease): + ax._got_onselect = True + assert epress.xdata == 100 + assert epress.ydata == 100 + assert erelease.xdata == 150 + assert erelease.ydata == 150 + + tool = widgets.RectangleSelector(ax, onselect, **kwargs) + event = get_event(ax, xdata=100, ydata=100, button=1) + tool._press(event) + + event = get_event(ax, xdata=125, ydata=125, button=1) + tool._onmove(event) + + event = get_event(ax, xdata=150, ydata=150, button=1) + tool._release(event) + + assert ax._got_onselect + + +def test_rectangle_selector(): + check_rectangle() + check_rectangle(drawtype='line', useblit=False) + check_rectangle(useblit=True, button=1) + check_rectangle(drawtype='none', minspanx=10, minspany=10) + check_rectangle(minspanx=10, minspany=10, spancoords='pixels') + check_rectangle(rectprops=dict(fill=True)) + + +def check_span(*args, **kwargs): + ax = plt.gca() + ax.plot([0, 200], [0, 200]) + + def onselect(vmin, vmax): + ax._got_onselect = True + assert vmin == 100 + assert vmax == 150 + + def onmove(vmin, vmax): + assert vmin == 100 + assert vmax == 125 + ax._got_on_move = True + + if 'onmove_callback' in kwargs: + kwargs['onmove_callback'] = onmove + + tool = widgets.SpanSelector(ax, onselect, *args, **kwargs) + event = get_event(ax, xdata=100, ydata=100, button=1) + tool._press(event) + + event = get_event(ax, xdata=125, ydata=125, button=1) + tool._onmove(event) + + event = get_event(ax, xdata=150, ydata=150, button=1) + tool._release(event) + + assert ax._got_onselect + + if 'onmove_callback' in kwargs: + assert ax._got_on_move + + +def test_span_selector(): + check_span('horizontal', minspan=10, useblit=True) + check_span('vertical', onmove_callback=True, button=1) + check_span('horizontal', rectprops=dict(fill=True)) + + +def check_lasso_selector(**kwargs): + ax = plt.gca() + ax.plot([0, 200], [0, 200]) + + def onselect(verts): + ax._got_onselect = True + assert verts == [(100, 100), (125, 125), (150, 150)] + + tool = widgets.LassoSelector(ax, onselect, **kwargs) + event = get_event(ax, xdata=100, ydata=100, button=1) + tool._press(event) + + event = get_event(ax, xdata=125, ydata=125, button=1) + tool._onmove(event) + + event = get_event(ax, xdata=150, ydata=150, button=1) + tool._release(event) + + assert ax._got_onselect + + +def test_lasso_selector(): + check_lasso_selector() + check_lasso_selector(useblit=False, lineprops=dict(color='red')) + check_lasso_selector(useblit=True, button=1) From 706b5b400a11e2e8bf118c64e3180ac8572a0bad Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Thu, 11 Sep 2014 21:38:18 -0500 Subject: [PATCH 05/18] Remove private event handling methods to allow for subclassing old api --- lib/matplotlib/tests/test_widgets.py | 23 +++++---- lib/matplotlib/widgets.py | 77 +++++++++++----------------- 2 files changed, 45 insertions(+), 55 deletions(-) diff --git a/lib/matplotlib/tests/test_widgets.py b/lib/matplotlib/tests/test_widgets.py index fb1e68ebf19e..ca8094b7f0ed 100644 --- a/lib/matplotlib/tests/test_widgets.py +++ b/lib/matplotlib/tests/test_widgets.py @@ -8,6 +8,10 @@ import mock import matplotlib.widgets as widgets + +import numpy as np +import matplotlib +from matplotlib.testing.decorators import image_comparison, cleanup import matplotlib.pyplot as plt @@ -74,13 +78,13 @@ def onselect(epress, erelease): tool = widgets.RectangleSelector(ax, onselect, **kwargs) event = get_event(ax, xdata=100, ydata=100, button=1) - tool._press(event) + tool.press(event) event = get_event(ax, xdata=125, ydata=125, button=1) - tool._onmove(event) + tool.onmove(event) event = get_event(ax, xdata=150, ydata=150, button=1) - tool._release(event) + tool.release(event) assert ax._got_onselect @@ -113,13 +117,13 @@ def onmove(vmin, vmax): tool = widgets.SpanSelector(ax, onselect, *args, **kwargs) event = get_event(ax, xdata=100, ydata=100, button=1) - tool._press(event) + tool.press(event) event = get_event(ax, xdata=125, ydata=125, button=1) - tool._onmove(event) + tool.onmove(event) event = get_event(ax, xdata=150, ydata=150, button=1) - tool._release(event) + tool.release(event) assert ax._got_onselect @@ -139,17 +143,18 @@ def check_lasso_selector(**kwargs): def onselect(verts): ax._got_onselect = True + print(verts) assert verts == [(100, 100), (125, 125), (150, 150)] tool = widgets.LassoSelector(ax, onselect, **kwargs) event = get_event(ax, xdata=100, ydata=100, button=1) - tool._press(event) + tool.press(event) event = get_event(ax, xdata=125, ydata=125, button=1) - tool._onmove(event) + tool.onmove(event) event = get_event(ax, xdata=150, ydata=150, button=1) - tool._release(event) + tool.release(event) assert ax._got_onselect diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index b2825ae98689..b4bb45b24065 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -1132,12 +1132,12 @@ def update_background(self, event): def connect_default_events(self): """Connect the major canvas events to methods.""" - 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('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.connect_event('key_press_event', self._on_key_press) - self.connect_event('scroll_event', self._on_scroll) + self.connect_event('key_press_event', self.on_key_press) + self.connect_event('scroll_event', self.on_scroll) def ignore(self, event): """return *True* if *event* should be ignored""" @@ -1198,64 +1198,36 @@ def update(self): self.canvas.draw_idle() return False - def _press(self, event): - """Button press event""" - if not self.ignore(event): - self.eventpress = event - self.press(event) - def press(self, event): """Button press handler""" - pass - - def _release(self, event): - if not self.ignore(event) and not self.eventpress is None: - self.eventrelease = event - self.release(event) - self.eventpress = None - self.eventrelease = None + if not self.ignore(event): + self.eventpress = event + return True + return False def release(self, event): """Button release event""" - pass - - def _onmove(self, event): - if not self.ignore(event): - self.onmove(event) + if not self.ignore(event) and not self.eventpress is None: + self.eventrelease = event + return True + else: + return False def onmove(self, event): - """Cursor motion event""" + """Cursor move event""" pass - def _on_scroll(self, event): - if not self.ignore(event): - self.on_scroll(event) - def on_scroll(self, event): """Mouse scroll event""" pass - def _on_key_press(self, event): - if not self.ignore(event): - self.on_key_press(event) - def on_key_press(self, event): """Key press event""" pass - def set_active(self, active): - """ - Use this to activate / deactivate the Selector - from your program with an boolean parameter *active*. - """ - self.active = active - - def get_active(self): - """ Get status of active mode (boolean variable)""" - return self.active - def set_visible(self, visible): """ Set the visibility of our artists """ + self.visible = visible for artist in self.artists: artist.set_visible(visible) @@ -1393,6 +1365,8 @@ def ignore(self, event): def press(self, event): """on button press event""" + if not _SelectorWidget.press(self, event): + return False self.rect.set_visible(self.visible) if self.span_stays: self.stay_rect.set_visible(False) @@ -1405,7 +1379,7 @@ def press(self, event): def release(self, event): """on button release event""" - if self.pressv is None: + if not _SelectorWidget.release(self, event) or self.pressv is None: return self.buttonDown = False @@ -1467,6 +1441,7 @@ def onmove(self, event): self.onmove_callback(vmin, vmax) self.update() + self.eventpress = None return False @@ -1591,12 +1566,17 @@ def __init__(self, ax, onselect, drawtype='box', def press(self, event): """on button press event""" + if not _SelectorWidget.press(self, event): + return True # make the drawed box/line visible self.to_draw.set_visible(self.visible) return False def release(self, event): """on button release event""" + if not _SelectorWidget.release(self, event): + return True + # make the box/line invisible again self.to_draw.set_visible(False) self.canvas.draw() @@ -1630,6 +1610,7 @@ def release(self, event): self.onselect(self.eventpress, self.eventrelease) # call desired function + self.eventpress = None return False def onmove(self, event): @@ -1720,6 +1701,8 @@ def onpress(self, event): self.press(event) def press(self, event): + if not _SelectorWidget.press(self, event): + return self.verts = [(event.xdata, event.ydata)] self.line.set_visible(True) @@ -1727,6 +1710,8 @@ def onrelease(self, event): self.release(event) def release(self, event): + if not _SelectorWidget.release(self, event): + return if self.verts is not None: self.verts.append((event.xdata, event.ydata)) self.onselect(self.verts) @@ -1735,7 +1720,7 @@ def release(self, event): self.verts = None def onmove(self, event): - if self.verts is None: + if self.ignore(event) or self.verts is None: return self.verts.append((event.xdata, event.ydata)) From ffd715a8e71d1798e3119b298d00c7758afdfd5a Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Fri, 12 Sep 2014 06:05:39 -0500 Subject: [PATCH 06/18] Remove draw_rubberband and minor cleanup --- lib/matplotlib/tests/test_widgets.py | 22 +++++++++------------- lib/matplotlib/widgets.py | 23 ++++------------------- setupext.py | 6 ++++-- 3 files changed, 17 insertions(+), 34 deletions(-) diff --git a/lib/matplotlib/tests/test_widgets.py b/lib/matplotlib/tests/test_widgets.py index ca8094b7f0ed..327a6699ee6e 100644 --- a/lib/matplotlib/tests/test_widgets.py +++ b/lib/matplotlib/tests/test_widgets.py @@ -8,10 +8,6 @@ import mock import matplotlib.widgets as widgets - -import numpy as np -import matplotlib -from matplotlib.testing.decorators import image_comparison, cleanup import matplotlib.pyplot as plt @@ -90,12 +86,12 @@ def onselect(epress, erelease): def test_rectangle_selector(): - check_rectangle() - check_rectangle(drawtype='line', useblit=False) - check_rectangle(useblit=True, button=1) - check_rectangle(drawtype='none', minspanx=10, minspany=10) - check_rectangle(minspanx=10, minspany=10, spancoords='pixels') - check_rectangle(rectprops=dict(fill=True)) + check_rectangle() + check_rectangle(drawtype='line', useblit=False) + check_rectangle(useblit=True, button=1) + check_rectangle(drawtype='none', minspanx=10, minspany=10) + check_rectangle(minspanx=10, minspany=10, spancoords='pixels') + check_rectangle(rectprops=dict(fill=True)) def check_span(*args, **kwargs): @@ -160,6 +156,6 @@ def onselect(verts): def test_lasso_selector(): - check_lasso_selector() - check_lasso_selector(useblit=False, lineprops=dict(color='red')) - check_lasso_selector(useblit=True, button=1) + check_lasso_selector() + check_lasso_selector(useblit=False, lineprops=dict(color='red')) + check_lasso_selector(useblit=True, button=1) diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index b4bb45b24065..b92e1bd6d499 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -1231,23 +1231,6 @@ def set_visible(self, visible): for artist in self.artists: artist.set_visible(visible) - def draw_rubberband(self, x0, x1, y0, y1): - """Draw a box using the native toolkit given data coordinates - """ - height = self.canvas.figure.bbox.height - - x0, y0 = self.ax.transData.transform([x0, y0]) - x1, y1 = self.ax.transData.transform([x1, y1]) - - y1 = height - y1 - y0 = height - y0 - - w = abs(x1 - x0) - h = abs(y1 - y0) - - rect = [int(val)for val in (min(x0, x1), min(y0, y1), w, h)] - self.canvas.drawRectangle(rect) - class SpanSelector(_SelectorWidget): """ @@ -1304,7 +1287,8 @@ def __init__(self, ax, onselect, direction, minspan=None, useblit=False, 2 = center mouse button (scroll wheel) 3 = right mouse button """ - _SelectorWidget.__init__(self, ax, onselect, useblit=useblit, button=button) + _SelectorWidget.__init__(self, ax, onselect, useblit=useblit, + button=button) if rectprops is None: rectprops = dict(facecolor='red', alpha=0.5) @@ -1528,7 +1512,8 @@ def __init__(self, ax, onselect, drawtype='box', 2 = center mouse button (scroll wheel) 3 = right mouse button """ - _SelectorWidget.__init__(self, ax, onselect, useblit=useblit, button=button) + _SelectorWidget.__init__(self, ax, onselect, useblit=useblit, + button=button) self.to_draw = None diff --git a/setupext.py b/setupext.py index 81c1463db6c0..e193e3825580 100755 --- a/setupext.py +++ b/setupext.py @@ -42,12 +42,13 @@ def check_output(*popenargs, **kwargs): return output -if sys.platform != 'win32': +try: if sys.version_info[0] < 3: from commands import getstatusoutput else: from subprocess import getstatusoutput - +except ImportError: + pass if PY3: import configparser @@ -146,6 +147,7 @@ def get_base_dirs(): return options['basedirlist'] basedir_map = { + 'win32': ['win32_static', ], 'darwin': ['/usr/local/', '/usr', '/usr/X11', '/opt/X11', '/opt/local'], From 53b6056b254d8da950fecb17ecdfcfc07ad8330b Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sun, 19 Oct 2014 15:29:09 -0500 Subject: [PATCH 07/18] Add to default_test_modules --- lib/matplotlib/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 42ce1af22cb4..076895866604 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -1429,6 +1429,7 @@ def tk_window_focus(): 'matplotlib.tests.test_transforms', 'matplotlib.tests.test_triangulation', 'mpl_toolkits.tests.test_mplot3d', + 'matplotlib.tests.test_widgets', ] From ddfcf5976bf6fec503dce6ff4195765e0d8e8425 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sun, 9 Nov 2014 11:28:43 -0600 Subject: [PATCH 08/18] Attempt to fix affine transform error --- lib/matplotlib/tests/test_widgets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/tests/test_widgets.py b/lib/matplotlib/tests/test_widgets.py index 327a6699ee6e..4f0c6617a50f 100644 --- a/lib/matplotlib/tests/test_widgets.py +++ b/lib/matplotlib/tests/test_widgets.py @@ -50,7 +50,7 @@ def get_event(ax, button=1, xdata=0, ydata=0, key=None, step=1): """ event = mock.Mock() event.button = button - event.x, event.y = ax.transData.transform((xdata, ydata)) + event.x, event.y = ax.transData.transform(([xdata], [ydata])) event.xdata, event.ydata = xdata, ydata event.inaxes = ax event.canvas = ax.figure.canvas From 76721c1f7d2863ba2c8f0cc8478ce147999bd093 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sun, 9 Nov 2014 12:44:15 -0600 Subject: [PATCH 09/18] Fix affine transform error --- lib/matplotlib/tests/test_widgets.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/tests/test_widgets.py b/lib/matplotlib/tests/test_widgets.py index 4f0c6617a50f..caae0c1823d9 100644 --- a/lib/matplotlib/tests/test_widgets.py +++ b/lib/matplotlib/tests/test_widgets.py @@ -50,7 +50,8 @@ def get_event(ax, button=1, xdata=0, ydata=0, key=None, step=1): """ event = mock.Mock() event.button = button - event.x, event.y = ax.transData.transform(([xdata], [ydata])) + event.x, event.y = ax.transData.transform([(xdata, ydata), + (xdata, ydata)])[00] event.xdata, event.ydata = xdata, ydata event.inaxes = ax event.canvas = ax.figure.canvas From cf668122e02b2c50eff33a5073c9495cd7872570 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sun, 9 Nov 2014 18:48:34 -0600 Subject: [PATCH 10/18] Add test cleanup decorator --- lib/matplotlib/tests/test_widgets.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/matplotlib/tests/test_widgets.py b/lib/matplotlib/tests/test_widgets.py index caae0c1823d9..dc895351e2c4 100644 --- a/lib/matplotlib/tests/test_widgets.py +++ b/lib/matplotlib/tests/test_widgets.py @@ -9,6 +9,7 @@ import matplotlib.widgets as widgets import matplotlib.pyplot as plt +from matplotlib.testing.decorators import cleanup def get_event(ax, button=1, xdata=0, ydata=0, key=None, step=1): @@ -86,6 +87,7 @@ def onselect(epress, erelease): assert ax._got_onselect +@cleanup def test_rectangle_selector(): check_rectangle() check_rectangle(drawtype='line', useblit=False) @@ -128,6 +130,7 @@ def onmove(vmin, vmax): assert ax._got_on_move +@cleanup def test_span_selector(): check_span('horizontal', minspan=10, useblit=True) check_span('vertical', onmove_callback=True, button=1) @@ -156,6 +159,7 @@ def onselect(verts): assert ax._got_onselect +@cleanup def test_lasso_selector(): check_lasso_selector() check_lasso_selector(useblit=False, lineprops=dict(color='red')) From babc377a5d22a320af30261bc65519fc376cd15b Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sun, 9 Nov 2014 18:52:16 -0600 Subject: [PATCH 11/18] Move cleanup to the individual checks --- lib/matplotlib/tests/test_widgets.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/tests/test_widgets.py b/lib/matplotlib/tests/test_widgets.py index dc895351e2c4..1a253d3a2d72 100644 --- a/lib/matplotlib/tests/test_widgets.py +++ b/lib/matplotlib/tests/test_widgets.py @@ -63,6 +63,7 @@ def get_event(ax, button=1, xdata=0, ydata=0, key=None, step=1): return event +@cleanup def check_rectangle(**kwargs): ax = plt.gca() ax.plot([0, 200], [0, 200]) @@ -87,7 +88,6 @@ def onselect(epress, erelease): assert ax._got_onselect -@cleanup def test_rectangle_selector(): check_rectangle() check_rectangle(drawtype='line', useblit=False) @@ -97,6 +97,7 @@ def test_rectangle_selector(): check_rectangle(rectprops=dict(fill=True)) +@cleanup def check_span(*args, **kwargs): ax = plt.gca() ax.plot([0, 200], [0, 200]) @@ -130,13 +131,13 @@ def onmove(vmin, vmax): assert ax._got_on_move -@cleanup def test_span_selector(): check_span('horizontal', minspan=10, useblit=True) check_span('vertical', onmove_callback=True, button=1) check_span('horizontal', rectprops=dict(fill=True)) +@cleanup def check_lasso_selector(**kwargs): ax = plt.gca() ax.plot([0, 200], [0, 200]) @@ -159,7 +160,6 @@ def onselect(verts): assert ax._got_onselect -@cleanup def test_lasso_selector(): check_lasso_selector() check_lasso_selector(useblit=False, lineprops=dict(color='red')) From cf58c0a387b7284a4832c5a8be07a1ac2dca3444 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Mon, 10 Nov 2014 20:18:49 -0600 Subject: [PATCH 12/18] Fix failing tests --- lib/matplotlib/tests/test_widgets.py | 2 +- lib/matplotlib/widgets.py | 19 +++++++++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/lib/matplotlib/tests/test_widgets.py b/lib/matplotlib/tests/test_widgets.py index 1a253d3a2d72..70b82bb1ee2c 100644 --- a/lib/matplotlib/tests/test_widgets.py +++ b/lib/matplotlib/tests/test_widgets.py @@ -75,6 +75,7 @@ def onselect(epress, erelease): assert erelease.xdata == 150 assert erelease.ydata == 150 + tool = widgets.RectangleSelector(ax, onselect, **kwargs) event = get_event(ax, xdata=100, ydata=100, button=1) tool.press(event) @@ -144,7 +145,6 @@ def check_lasso_selector(**kwargs): def onselect(verts): ax._got_onselect = True - print(verts) assert verts == [(100, 100), (125, 125), (150, 150)] tool = widgets.LassoSelector(ax, onselect, **kwargs) diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index b92e1bd6d499..13eec2a1b4e1 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -1108,10 +1108,10 @@ def __init__(self, ax, onselect, useblit=False, button=None): self.artists = [] self.useblit = useblit and self.canvas.supports_blit - if button is None or isinstance(button, list): - self.validButtons = button - elif isinstance(button, int): + if isinstance(button, int): self.validButtons = [button] + else: + self.validButtons = button # will save the data (position at mouseclick) self.eventpress = None @@ -1192,8 +1192,16 @@ def update(self): if self.background is not None: self.canvas.restore_region(self.background) for artist in self.artists: - self.ax.draw_artist(artist) - self.canvas.blit(self.ax.bbox) + try: + self.ax.draw_artist(artist) + except AssertionError: + self.canvas.draw_idle() + return False + try: + self.canvas.blit(self.ax.bbox) + except AttributeError: + self.canvas.draw_idle() + return False else: self.canvas.draw_idle() return False @@ -1425,7 +1433,6 @@ def onmove(self, event): self.onmove_callback(vmin, vmax) self.update() - self.eventpress = None return False From f3261cf895da4a6e92d1b62b93d64ecde5c3a377 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 11 Nov 2014 06:33:56 -0600 Subject: [PATCH 13/18] Fix pep8 error --- lib/matplotlib/tests/test_widgets.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/matplotlib/tests/test_widgets.py b/lib/matplotlib/tests/test_widgets.py index 70b82bb1ee2c..7af24d4ec619 100644 --- a/lib/matplotlib/tests/test_widgets.py +++ b/lib/matplotlib/tests/test_widgets.py @@ -75,7 +75,6 @@ def onselect(epress, erelease): assert erelease.xdata == 150 assert erelease.ydata == 150 - tool = widgets.RectangleSelector(ax, onselect, **kwargs) event = get_event(ax, xdata=100, ydata=100, button=1) tool.press(event) From c25efbd54dd409ca5acae8b0fc5df010ecc20947 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 11 Nov 2014 10:14:21 -0600 Subject: [PATCH 14/18] Improve handling of out-of-bounds releases --- lib/matplotlib/tests/test_widgets.py | 7 ++-- lib/matplotlib/widgets.py | 60 ++++++++++++++++------------ 2 files changed, 38 insertions(+), 29 deletions(-) diff --git a/lib/matplotlib/tests/test_widgets.py b/lib/matplotlib/tests/test_widgets.py index 7af24d4ec619..6e1a98f7abbd 100644 --- a/lib/matplotlib/tests/test_widgets.py +++ b/lib/matplotlib/tests/test_widgets.py @@ -72,8 +72,8 @@ def onselect(epress, erelease): ax._got_onselect = True assert epress.xdata == 100 assert epress.ydata == 100 - assert erelease.xdata == 150 - assert erelease.ydata == 150 + assert erelease.xdata == 200 + assert erelease.ydata == 200 tool = widgets.RectangleSelector(ax, onselect, **kwargs) event = get_event(ax, xdata=100, ydata=100, button=1) @@ -82,7 +82,8 @@ def onselect(epress, erelease): event = get_event(ax, xdata=125, ydata=125, button=1) tool.onmove(event) - event = get_event(ax, xdata=150, ydata=150, button=1) + # purposely drag outside of axis for release + event = get_event(ax, xdata=250, ydata=250, button=1) tool.release(event) assert ax._got_onselect diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index 13eec2a1b4e1..83d230bf7a5a 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -12,6 +12,7 @@ from __future__ import (absolute_import, division, print_function, unicode_literals) +import copy import six from six.moves import zip @@ -1163,19 +1164,8 @@ def ignore(self, event): return event.inaxes != self.ax # If a button was pressed, check if the release-button is the - # same. If event is out of axis, limit the data coordinates to axes - # boundaries. - if event.button == self.eventpress.button and event.inaxes != self.ax: - (xdata, ydata) = self.ax.transData.inverted().transform_point( - (event.x, event.y)) - x0, x1 = self.ax.get_xbound() - y0, y1 = self.ax.get_ybound() - xdata = max(x0, xdata) - xdata = min(x1, xdata) - ydata = max(y0, ydata) - ydata = min(y1, ydata) - event.xdata = xdata - event.ydata = ydata + # same. + if event.button == self.eventpress.button: return False # If a button was pressed, check if the release-button is the @@ -1206,17 +1196,31 @@ def update(self): self.canvas.draw_idle() return False + def _get_data(self, event): + """Limit the xdata and ydata to the axes limits""" + x0, x1 = self.ax.get_xbound() + y0, y1 = self.ax.get_ybound() + xdata = max(x0, event.xdata) + xdata = min(x1, xdata) + ydata = max(y0, event.ydata) + ydata = min(y1, ydata) + return xdata, ydata + def press(self, event): """Button press handler""" if not self.ignore(event): - self.eventpress = event + self.eventpress = copy.copy(event) + self.eventpress.xdata, self.eventpress.ydata = ( + self._get_data(event)) return True return False def release(self, event): """Button release event""" if not self.ignore(event) and not self.eventpress is None: - self.eventrelease = event + self.eventrelease = copy.copy(event) + self.eventrelease.xdata, self.eventrelease.ydata = ( + self._get_data(event)) return True else: return False @@ -1363,10 +1367,11 @@ def press(self, event): if self.span_stays: self.stay_rect.set_visible(False) + xdata, ydata = self._get_data(event) if self.direction == 'horizontal': - self.pressv = event.xdata + self.pressv = xdata else: - self.pressv = event.ydata + self.pressv = ydata return False def release(self, event): @@ -1386,10 +1391,11 @@ def release(self, event): self.canvas.draw() vmin = self.pressv + xdata, ydata = self._get_data(event) if self.direction == 'horizontal': - vmax = event.xdata or self.prev[0] + vmax = xdata or self.prev[0] else: - vmax = event.ydata or self.prev[1] + vmax = ydata or self.prev[1] if vmin > vmax: vmin, vmax = vmax, vmin @@ -1404,7 +1410,7 @@ def onmove(self, event): """on motion notify event""" if self.pressv is None or self.ignore(event): return - x, y = event.xdata, event.ydata + x, y = self._get_data(event) self.prev = x, y if self.direction == 'horizontal': v = x @@ -1423,10 +1429,11 @@ def onmove(self, event): if self.onmove_callback is not None: vmin = self.pressv + xdata, ydata = self._get_data(event) if self.direction == 'horizontal': - vmax = event.xdata or self.prev[0] + vmax = xdata or self.prev[0] else: - vmax = event.ydata or self.prev[1] + vmax = ydata or self.prev[1] if vmin > vmax: vmin, vmax = vmax, vmin @@ -1609,7 +1616,8 @@ def onmove(self, event): """on motion notify event if box/line is wanted""" if self.eventpress is None or self.ignore(event): return - x, y = event.xdata, event.ydata # actual position (with + + x, y = self._get_data(event) # actual position (with # (button still pressed) if self.drawtype == 'box': minx, maxx = self.eventpress.xdata, x # click-x and actual mouse-x @@ -1695,7 +1703,7 @@ def onpress(self, event): def press(self, event): if not _SelectorWidget.press(self, event): return - self.verts = [(event.xdata, event.ydata)] + self.verts = [self._get_data(event)] self.line.set_visible(True) def onrelease(self, event): @@ -1705,7 +1713,7 @@ def release(self, event): if not _SelectorWidget.release(self, event): return if self.verts is not None: - self.verts.append((event.xdata, event.ydata)) + self.verts.append(self._get_data(event)) self.onselect(self.verts) self.line.set_data([[], []]) self.line.set_visible(False) @@ -1714,7 +1722,7 @@ def release(self, event): def onmove(self, event): if self.ignore(event) or self.verts is None: return - self.verts.append((event.xdata, event.ydata)) + self.verts.append(self._get_data(event)) self.line.set_data(list(zip(*self.verts))) From ce93c9860d34c5e4903149b9404cb3e6865bdd2b Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Wed, 12 Nov 2014 05:40:12 -0600 Subject: [PATCH 15/18] Revert changes to setupext.py --- setupext.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/setupext.py b/setupext.py index e193e3825580..81c1463db6c0 100755 --- a/setupext.py +++ b/setupext.py @@ -42,13 +42,12 @@ def check_output(*popenargs, **kwargs): return output -try: +if sys.platform != 'win32': if sys.version_info[0] < 3: from commands import getstatusoutput else: from subprocess import getstatusoutput -except ImportError: - pass + if PY3: import configparser @@ -147,7 +146,6 @@ def get_base_dirs(): return options['basedirlist'] basedir_map = { - 'win32': ['win32_static', ], 'darwin': ['/usr/local/', '/usr', '/usr/X11', '/opt/X11', '/opt/local'], From 51c70f080084bca7ca64bea1ce19c8b6305639c2 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Wed, 12 Nov 2014 05:40:28 -0600 Subject: [PATCH 16/18] Style change and use self.blit instead of blit. --- lib/matplotlib/widgets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index 83d230bf7a5a..bb910b47098a 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -1326,7 +1326,7 @@ 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: - if not self.canvas is None: + if self.canvas is not None: self.disconnect_events() self.canvas = ax.figure.canvas @@ -1548,7 +1548,7 @@ def __init__(self, ax, onselect, drawtype='box', lineprops = dict(color='black', linestyle='-', linewidth=2, alpha=0.5) self.lineprops = lineprops - if useblit: + if self.useblit: self.lineprops['animated'] = True self.to_draw = Line2D([0, 0], [0, 0], visible=False, **self.lineprops) From d7119406bda5e1e07b53f53992d9ad4eed5d953f Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 11 Nov 2014 13:06:53 -0500 Subject: [PATCH 17/18] MNT : pep8 + pyflake changes - strip white space - rearrange 'not's --- lib/matplotlib/widgets.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index bb910b47098a..6244a665b4df 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -1155,7 +1155,7 @@ def ignore(self, event): # Only do rectangle selection if event was triggered # with a desired button if self.validButtons is not None: - if not event.button in self.validButtons: + if event.button not in self.validButtons: return True # If no button was pressed yet ignore the event if it was out @@ -1164,7 +1164,7 @@ def ignore(self, event): return event.inaxes != self.ax # If a button was pressed, check if the release-button is the - # same. + # same. if event.button == self.eventpress.button: return False @@ -1217,7 +1217,7 @@ def press(self, event): def release(self, event): """Button release event""" - if not self.ignore(event) and not self.eventpress is None: + if not self.ignore(event) and self.eventpress is not None: self.eventrelease = copy.copy(event) self.eventrelease.xdata, self.eventrelease.ydata = ( self._get_data(event)) From 86f28fa1b2e0637dedd95e2a1b0b7986b5336f6b Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 11 Nov 2014 13:07:54 -0500 Subject: [PATCH 18/18] TST : ensure canvas drawn before testing widets Widgets assume that the canvas has been drawn atleast once before they are called (which is reasonable for interactive usage as the user needs to be able to _see_ the gui before they can interact with it). Ensure that the tests draw the canvas before trying to use the widgets. Doing this allows for removing some of the error handling logic from the widgets. --- lib/matplotlib/tests/test_widgets.py | 8 ++++++-- lib/matplotlib/widgets.py | 14 ++++---------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/lib/matplotlib/tests/test_widgets.py b/lib/matplotlib/tests/test_widgets.py index 6e1a98f7abbd..64b0e342a21b 100644 --- a/lib/matplotlib/tests/test_widgets.py +++ b/lib/matplotlib/tests/test_widgets.py @@ -65,8 +65,9 @@ def get_event(ax, button=1, xdata=0, ydata=0, key=None, step=1): @cleanup def check_rectangle(**kwargs): - ax = plt.gca() + fig, ax = plt.subplots(1, 1) ax.plot([0, 200], [0, 200]) + ax.figure.canvas.draw() def onselect(epress, erelease): ax._got_onselect = True @@ -100,8 +101,9 @@ def test_rectangle_selector(): @cleanup def check_span(*args, **kwargs): - ax = plt.gca() + fig, ax = plt.subplots(1, 1) ax.plot([0, 200], [0, 200]) + ax.figure.canvas.draw() def onselect(vmin, vmax): ax._got_onselect = True @@ -140,8 +142,10 @@ def test_span_selector(): @cleanup def check_lasso_selector(**kwargs): + fig, ax = plt.subplots(1, 1) ax = plt.gca() ax.plot([0, 200], [0, 200]) + ax.figure.canvas.draw() def onselect(verts): ax._got_onselect = True diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index 6244a665b4df..945db5802dc2 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -1182,16 +1182,10 @@ def update(self): if self.background is not None: self.canvas.restore_region(self.background) for artist in self.artists: - try: - self.ax.draw_artist(artist) - except AssertionError: - self.canvas.draw_idle() - return False - try: - self.canvas.blit(self.ax.bbox) - except AttributeError: - self.canvas.draw_idle() - return False + self.ax.draw_artist(artist) + + self.canvas.blit(self.ax.bbox) + else: self.canvas.draw_idle() return False