Skip to content

making onselect a keyword argument on selectors #26000

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 1 commit into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions doc/api/next_api_changes/behavior/26000-t.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
onselect argument to selector widgets made optional
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The *onselect* argument to `.EllipseSelector`, `.LassoSelector`, `.PolygonSelector`, and
`.RectangleSelector` is no longer required.
65 changes: 30 additions & 35 deletions lib/matplotlib/tests/test_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def test_save_blitted_widget_as_pdf():
def test_rectangle_selector(ax, kwargs):
onselect = mock.Mock(spec=noop, return_value=None)

tool = widgets.RectangleSelector(ax, onselect, **kwargs)
tool = widgets.RectangleSelector(ax, onselect=onselect, **kwargs)
do_event(tool, 'press', xdata=100, ydata=100, button=1)
do_event(tool, 'onmove', xdata=199, ydata=199, button=1)

Expand Down Expand Up @@ -105,7 +105,7 @@ def test_rectangle_minspan(ax, spancoords, minspanx, x1, minspany, y1):
minspanx, minspany = (ax.transData.transform((x1, y1)) -
ax.transData.transform((x0, y0)))

tool = widgets.RectangleSelector(ax, onselect, interactive=True,
tool = widgets.RectangleSelector(ax, onselect=onselect, interactive=True,
spancoords=spancoords,
minspanx=minspanx, minspany=minspany)
# Too small to create a selector
Expand All @@ -132,7 +132,7 @@ def test_rectangle_minspan(ax, spancoords, minspanx, x1, minspany, y1):


def test_deprecation_selector_visible_attribute(ax):
tool = widgets.RectangleSelector(ax, lambda *args: None)
tool = widgets.RectangleSelector(ax)

assert tool.get_visible()

Expand All @@ -145,7 +145,7 @@ def test_deprecation_selector_visible_attribute(ax):
[[True, (60, 75)],
[False, (30, 20)]])
def test_rectangle_drag(ax, drag_from_anywhere, new_center):
tool = widgets.RectangleSelector(ax, onselect=noop, interactive=True,
tool = widgets.RectangleSelector(ax, interactive=True,
drag_from_anywhere=drag_from_anywhere)
# Create rectangle
click_and_drag(tool, start=(0, 10), end=(100, 120))
Expand All @@ -166,7 +166,7 @@ def test_rectangle_drag(ax, drag_from_anywhere, new_center):


def test_rectangle_selector_set_props_handle_props(ax):
tool = widgets.RectangleSelector(ax, onselect=noop, interactive=True,
tool = widgets.RectangleSelector(ax, interactive=True,
props=dict(facecolor='b', alpha=0.2),
handle_props=dict(alpha=0.5))
# Create rectangle
Expand All @@ -187,7 +187,7 @@ def test_rectangle_selector_set_props_handle_props(ax):


def test_rectangle_resize(ax):
tool = widgets.RectangleSelector(ax, onselect=noop, interactive=True)
tool = widgets.RectangleSelector(ax, interactive=True)
# Create rectangle
click_and_drag(tool, start=(0, 10), end=(100, 120))
assert tool.extents == (0.0, 100.0, 10.0, 120.0)
Expand Down Expand Up @@ -222,7 +222,7 @@ def test_rectangle_resize(ax):


def test_rectangle_add_state(ax):
tool = widgets.RectangleSelector(ax, onselect=noop, interactive=True)
tool = widgets.RectangleSelector(ax, interactive=True)
# Create rectangle
click_and_drag(tool, start=(70, 65), end=(125, 130))

Expand All @@ -238,7 +238,7 @@ def test_rectangle_add_state(ax):

@pytest.mark.parametrize('add_state', [True, False])
def test_rectangle_resize_center(ax, add_state):
tool = widgets.RectangleSelector(ax, onselect=noop, interactive=True)
tool = widgets.RectangleSelector(ax, interactive=True)
# Create rectangle
click_and_drag(tool, start=(70, 65), end=(125, 130))
assert tool.extents == (70.0, 125.0, 65.0, 130.0)
Expand Down Expand Up @@ -312,7 +312,7 @@ def test_rectangle_resize_center(ax, add_state):

@pytest.mark.parametrize('add_state', [True, False])
def test_rectangle_resize_square(ax, add_state):
tool = widgets.RectangleSelector(ax, onselect=noop, interactive=True)
tool = widgets.RectangleSelector(ax, interactive=True)
# Create rectangle
click_and_drag(tool, start=(70, 65), end=(120, 115))
assert tool.extents == (70.0, 120.0, 65.0, 115.0)
Expand Down Expand Up @@ -385,7 +385,7 @@ def test_rectangle_resize_square(ax, add_state):


def test_rectangle_resize_square_center(ax):
tool = widgets.RectangleSelector(ax, onselect=noop, interactive=True)
tool = widgets.RectangleSelector(ax, interactive=True)
# Create rectangle
click_and_drag(tool, start=(70, 65), end=(120, 115))
tool.add_state('square')
Expand Down Expand Up @@ -450,7 +450,7 @@ def test_rectangle_resize_square_center(ax):
@pytest.mark.parametrize('selector_class',
[widgets.RectangleSelector, widgets.EllipseSelector])
def test_rectangle_rotate(ax, selector_class):
tool = selector_class(ax, onselect=noop, interactive=True)
tool = selector_class(ax, interactive=True)
# Draw rectangle
click_and_drag(tool, start=(100, 100), end=(130, 140))
assert tool.extents == (100, 130, 100, 140)
Expand Down Expand Up @@ -483,7 +483,7 @@ def test_rectangle_rotate(ax, selector_class):


def test_rectangle_add_remove_set(ax):
tool = widgets.RectangleSelector(ax, onselect=noop, interactive=True)
tool = widgets.RectangleSelector(ax, interactive=True)
# Draw rectangle
click_and_drag(tool, start=(100, 100), end=(130, 140))
assert tool.extents == (100, 130, 100, 140)
Expand All @@ -499,7 +499,7 @@ def test_rectangle_add_remove_set(ax):
def test_rectangle_resize_square_center_aspect(ax, use_data_coordinates):
ax.set_aspect(0.8)

tool = widgets.RectangleSelector(ax, onselect=noop, interactive=True,
tool = widgets.RectangleSelector(ax, interactive=True,
use_data_coordinates=use_data_coordinates)
# Create rectangle
click_and_drag(tool, start=(70, 65), end=(120, 115))
Expand Down Expand Up @@ -531,8 +531,7 @@ def test_rectangle_resize_square_center_aspect(ax, use_data_coordinates):

def test_ellipse(ax):
"""For ellipse, test out the key modifiers"""
tool = widgets.EllipseSelector(ax, onselect=noop,
grab_range=10, interactive=True)
tool = widgets.EllipseSelector(ax, grab_range=10, interactive=True)
tool.extents = (100, 150, 100, 150)

# drag the rectangle
Expand All @@ -558,9 +557,7 @@ def test_ellipse(ax):


def test_rectangle_handles(ax):
tool = widgets.RectangleSelector(ax, onselect=noop,
grab_range=10,
interactive=True,
tool = widgets.RectangleSelector(ax, grab_range=10, interactive=True,
handle_props={'markerfacecolor': 'r',
'markeredgecolor': 'b'})
tool.extents = (100, 150, 100, 150)
Expand Down Expand Up @@ -595,7 +592,7 @@ def test_rectangle_selector_onselect(ax, interactive):
# check when press and release events take place at the same position
onselect = mock.Mock(spec=noop, return_value=None)

tool = widgets.RectangleSelector(ax, onselect, interactive=interactive)
tool = widgets.RectangleSelector(ax, onselect=onselect, interactive=interactive)
# move outside of axis
click_and_drag(tool, start=(100, 110), end=(150, 120))

Expand All @@ -611,7 +608,7 @@ def test_rectangle_selector_onselect(ax, interactive):
def test_rectangle_selector_ignore_outside(ax, ignore_event_outside):
onselect = mock.Mock(spec=noop, return_value=None)

tool = widgets.RectangleSelector(ax, onselect,
tool = widgets.RectangleSelector(ax, onselect=onselect,
ignore_event_outside=ignore_event_outside)
click_and_drag(tool, start=(100, 110), end=(150, 120))
onselect.assert_called_once()
Expand Down Expand Up @@ -773,10 +770,11 @@ def test_span_selector_set_props_handle_props(ax):

@pytest.mark.parametrize('selector', ['span', 'rectangle'])
def test_selector_clear(ax, selector):
kwargs = dict(ax=ax, onselect=noop, interactive=True)
kwargs = dict(ax=ax, interactive=True)
if selector == 'span':
Selector = widgets.SpanSelector
kwargs['direction'] = 'horizontal'
kwargs['onselect'] = noop
else:
Selector = widgets.RectangleSelector

Expand Down Expand Up @@ -807,7 +805,7 @@ def test_selector_clear_method(ax, selector):
interactive=True,
ignore_event_outside=True)
else:
tool = widgets.RectangleSelector(ax, onselect=noop, interactive=True)
tool = widgets.RectangleSelector(ax, interactive=True)
click_and_drag(tool, start=(10, 10), end=(100, 120))
assert tool._selection_completed
assert tool.get_visible()
Expand Down Expand Up @@ -1000,7 +998,7 @@ def test_span_selector_extents(ax):
def test_lasso_selector(ax, kwargs):
onselect = mock.Mock(spec=noop, return_value=None)

tool = widgets.LassoSelector(ax, onselect, **kwargs)
tool = widgets.LassoSelector(ax, onselect=onselect, **kwargs)
do_event(tool, 'press', xdata=100, ydata=100, button=1)
do_event(tool, 'onmove', xdata=125, ydata=125, button=1)
do_event(tool, 'release', xdata=150, ydata=150, button=1)
Expand All @@ -1011,7 +1009,8 @@ def test_lasso_selector(ax, kwargs):
def test_lasso_selector_set_props(ax):
onselect = mock.Mock(spec=noop, return_value=None)

tool = widgets.LassoSelector(ax, onselect, props=dict(color='b', alpha=0.2))
tool = widgets.LassoSelector(ax, onselect=onselect,
props=dict(color='b', alpha=0.2))

artist = tool._selection_artist
assert mcolors.same_color(artist.get_color(), 'b')
Expand Down Expand Up @@ -1380,7 +1379,7 @@ def check_polygon_selector(event_sequence, expected_result, selections_count,

onselect = mock.Mock(spec=noop, return_value=None)

tool = widgets.PolygonSelector(ax, onselect, **kwargs)
tool = widgets.PolygonSelector(ax, onselect=onselect, **kwargs)

for (etype, event_args) in event_sequence:
do_event(tool, etype, **event_args)
Expand Down Expand Up @@ -1517,7 +1516,7 @@ def test_polygon_selector(draw_bounding_box):

@pytest.mark.parametrize('draw_bounding_box', [False, True])
def test_polygon_selector_set_props_handle_props(ax, draw_bounding_box):
tool = widgets.PolygonSelector(ax, onselect=noop,
tool = widgets.PolygonSelector(ax,
props=dict(color='b', alpha=0.2),
handle_props=dict(alpha=0.5),
draw_bounding_box=draw_bounding_box)
Expand Down Expand Up @@ -1554,8 +1553,7 @@ def test_rect_visibility(fig_test, fig_ref):
ax_test = fig_test.subplots()
_ = fig_ref.subplots()

tool = widgets.RectangleSelector(ax_test, onselect=noop,
props={'visible': False})
tool = widgets.RectangleSelector(ax_test, props={'visible': False})
tool.extents = (0.2, 0.8, 0.3, 0.7)


Expand Down Expand Up @@ -1608,8 +1606,7 @@ def test_polygon_selector_redraw(ax, draw_bounding_box):
*polygon_place_vertex(*verts[1]),
]

tool = widgets.PolygonSelector(ax, onselect=noop,
draw_bounding_box=draw_bounding_box)
tool = widgets.PolygonSelector(ax, draw_bounding_box=draw_bounding_box)
for (etype, event_args) in event_sequence:
do_event(tool, etype, **event_args)
# After removing two verts, only one remains, and the
Expand All @@ -1623,14 +1620,12 @@ def test_polygon_selector_verts_setter(fig_test, fig_ref, draw_bounding_box):
verts = [(0.1, 0.4), (0.5, 0.9), (0.3, 0.2)]
ax_test = fig_test.add_subplot()

tool_test = widgets.PolygonSelector(
ax_test, onselect=noop, draw_bounding_box=draw_bounding_box)
tool_test = widgets.PolygonSelector(ax_test, draw_bounding_box=draw_bounding_box)
tool_test.verts = verts
assert tool_test.verts == verts

ax_ref = fig_ref.add_subplot()
tool_ref = widgets.PolygonSelector(
ax_ref, onselect=noop, draw_bounding_box=draw_bounding_box)
tool_ref = widgets.PolygonSelector(ax_ref, draw_bounding_box=draw_bounding_box)
event_sequence = [
*polygon_place_vertex(*verts[0]),
*polygon_place_vertex(*verts[1]),
Expand All @@ -1654,7 +1649,7 @@ def test_polygon_selector_box(ax):
]

# Create selector
tool = widgets.PolygonSelector(ax, onselect=noop, draw_bounding_box=True)
tool = widgets.PolygonSelector(ax, draw_bounding_box=True)
for (etype, event_args) in event_sequence:
do_event(tool, etype, **event_args)

Expand Down
21 changes: 12 additions & 9 deletions lib/matplotlib/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -2091,12 +2091,15 @@ def onmove(self, event):

class _SelectorWidget(AxesWidget):

def __init__(self, ax, onselect, useblit=False, button=None,
def __init__(self, ax, onselect=None, useblit=False, button=None,
state_modifier_keys=None, use_data_coordinates=False):
super().__init__(ax)

self._visible = True
self.onselect = onselect
if onselect is None:
self.onselect = lambda *args: None
else:
self.onselect = onselect
self.useblit = useblit and self.canvas.supports_blit
self.connect_default_events()

Expand Down Expand Up @@ -3041,7 +3044,7 @@ def closest(self, x, y):
ax : `~matplotlib.axes.Axes`
The parent Axes for the widget.

onselect : function
onselect : function, optional
A callback function that is called after a release event and the
selection is created, changed or removed.
It must have the signature::
Expand Down Expand Up @@ -3154,7 +3157,8 @@ class RectangleSelector(_SelectorWidget):
See also: :doc:`/gallery/widgets/rectangle_selector`
"""

def __init__(self, ax, onselect, *, minspanx=0, minspany=0, useblit=False,
def __init__(self, ax, onselect=None, *, minspanx=0,
minspany=0, useblit=False,
props=None, spancoords='data', button=None, grab_range=10,
handle_props=None, interactive=False,
state_modifier_keys=None, drag_from_anywhere=False,
Expand Down Expand Up @@ -3676,7 +3680,7 @@ def onselect(verts):
----------
ax : `~matplotlib.axes.Axes`
The parent Axes for the widget.
onselect : function
onselect : function, optional
Whenever the lasso is released, the *onselect* function is called and
passed the vertices of the selected path.
useblit : bool, default: True
Expand All @@ -3691,7 +3695,7 @@ def onselect(verts):
which corresponds to all buttons.
"""

def __init__(self, ax, onselect, *, useblit=True, props=None, button=None):
def __init__(self, ax, onselect=None, *, useblit=True, props=None, button=None):
super().__init__(ax, onselect, useblit=useblit, button=button)
self.verts = None
props = {
Expand Down Expand Up @@ -3749,7 +3753,7 @@ class PolygonSelector(_SelectorWidget):
ax : `~matplotlib.axes.Axes`
The parent Axes for the widget.

onselect : function
onselect : function, optional
When a polygon is completed or modified after completion,
the *onselect* function is called and passed a list of the vertices as
``(xdata, ydata)`` tuples.
Expand Down Expand Up @@ -3801,7 +3805,7 @@ class PolygonSelector(_SelectorWidget):
point.
"""

def __init__(self, ax, onselect, *, useblit=False,
def __init__(self, ax, onselect=None, *, useblit=False,
props=None, handle_props=None, grab_range=10,
draw_bounding_box=False, box_handle_props=None,
box_props=None):
Expand Down Expand Up @@ -3851,7 +3855,6 @@ def _get_bbox(self):

def _add_box(self):
self._box = RectangleSelector(self.ax,
onselect=lambda *args, **kwargs: None,
useblit=self.useblit,
grab_range=self.grab_range,
handle_props=self._box_handle_props,
Expand Down
8 changes: 4 additions & 4 deletions lib/matplotlib/widgets.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ class _SelectorWidget(AxesWidget):
def __init__(
self,
ax: Axes,
onselect: Callable[[float, float], Any],
onselect: Callable[[float, float], Any] | None = ...,
useblit: bool = ...,
button: MouseButton | Collection[MouseButton] | None = ...,
state_modifier_keys: dict[str, str] | None = ...,
Expand Down Expand Up @@ -403,7 +403,7 @@ class RectangleSelector(_SelectorWidget):
def __init__(
self,
ax: Axes,
onselect: Callable[[MouseEvent, MouseEvent], Any],
onselect: Callable[[MouseEvent, MouseEvent], Any] | None = ...,
*,
minspanx: float = ...,
minspany: float = ...,
Expand Down Expand Up @@ -443,7 +443,7 @@ class LassoSelector(_SelectorWidget):
def __init__(
self,
ax: Axes,
onselect: Callable[[list[tuple[float, float]]], Any],
onselect: Callable[[list[tuple[float, float]]], Any] | None = ...,
*,
useblit: bool = ...,
props: dict[str, Any] | None = ...,
Expand All @@ -455,7 +455,7 @@ class PolygonSelector(_SelectorWidget):
def __init__(
self,
ax: Axes,
onselect: Callable[[ArrayLike, ArrayLike], Any],
onselect: Callable[[ArrayLike, ArrayLike], Any] | None = ...,
*,
useblit: bool = ...,
props: dict[str, Any] | None = ...,
Expand Down
Loading