Skip to content

Interactive span selector improvement #20113

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 35 commits into from
Jun 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
afa875f
Add interactive option to SpanSelector to change it interactively aft…
ericpre Apr 25, 2021
6ebf76a
Add drag_from_anywhere functionality.
ericpre Apr 28, 2021
01319f1
Add test for dragging span selector.
ericpre Apr 28, 2021
cc1d69a
Use line handlers for span selector
ericpre Apr 28, 2021
7d37461
Set handle properties.
ericpre Apr 28, 2021
db23069
Update docstring.
ericpre Apr 28, 2021
db8b587
Tidy up.
ericpre Apr 28, 2021
369ff9d
Add API deprecation.
ericpre Apr 28, 2021
a3c321c
Make SpanSelector consistent with RectangleSelector to further improv…
ericpre Apr 29, 2021
349c134
Test move outside of axis.
ericpre Apr 29, 2021
52c3666
flake8 fixes.
ericpre Apr 29, 2021
bc3808b
Use @_api.rename_parameter instead of @_api.delete_parameter to renam…
ericpre May 12, 2021
1e774e0
Allow setting extents before the SpanSelector/RectangleSelector/Ellip…
ericpre May 12, 2021
4bf2d09
Privatize draw_shape for SpanSelector, RectangleSelector and EllipseS…
ericpre May 12, 2021
bb3c1ae
Deprecate SpanSelector.pressv
ericpre May 19, 2021
5122318
Reset arguments order in SpanSelector
ericpre May 19, 2021
aa023f4
Improve docstring, argument name, fix `set_animated`, `set_visible` i…
ericpre Jun 3, 2021
03d1414
Make rect and rectprops private (with deprecation)
ericpre Jun 3, 2021
524f2b7
Remove vmin, vmax of span selector, use extents instead
ericpre Jun 3, 2021
5587bb4
Privatize more attributes, which are not expected to be used by users.
ericpre Jun 4, 2021
fb7bdd7
Fix flake8 compliance
ericpre Jun 4, 2021
f10ab5c
MNT: restore clearing selection with 0-width selection
tacaswell Jun 18, 2021
472072b
DOC: show off more keyword arguments in span selector demo
tacaswell Jun 18, 2021
ab9eebf
Avoid calling update when clearing the span selector with 0-width sel…
ericpre Jun 18, 2021
bbf1156
Add new features and API changes entries
ericpre Jun 18, 2021
3f72e17
Fix typo and docstring
ericpre Jun 19, 2021
8eeea02
Privatize interactive in RectangleSelector and EllipseSelector
ericpre Jun 19, 2021
6266fcf
Fix clearing span without blitting.
ericpre Jun 19, 2021
ff07b6e
Clear RectangleSelector and EllipseSelector when clicking outside the…
ericpre Jun 19, 2021
9b98eec
Deprecate `SpanSelector.span_stays` attributes
ericpre Jun 19, 2021
d123ebf
Deprecate `SpanSelector.prev` attribute
ericpre Jun 19, 2021
f64e98b
Allow changing direction of span selector
ericpre Jun 19, 2021
7abf57c
Fix typos
ericpre Jun 29, 2021
e280ed9
Use deprecate_privatize_attribute in favour of deprecate to simplify …
ericpre Jun 30, 2021
92d1705
Use the property setter of direction when initialising a SpanSelector…
ericpre Jun 30, 2021
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
21 changes: 21 additions & 0 deletions doc/api/next_api_changes/deprecations/20113-EP.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
SpanSelector
~~~~~~~~~~~~
``span_stays`` is deprecated, use ``interactive`` argument instead
Several `~matplotlib.widgets.SpanSelector` class internals have been privatized
and deprecated:
- ``pressv``
- ``prev``
- ``rect``
- ``rectprops``
- ``active_handle``
- ``span_stays``


Several `~matplotlib.widgets.RectangleSelector` and
`~matplotlib.widgets.EllipseSelector` class internals have been privatized and
deprecated:
- ``to_draw``
- ``drawtype``
- ``rectprops``
- ``active_handle``
- ``interactive``
7 changes: 5 additions & 2 deletions doc/users/next_whats_new/widget_dragging.rst
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
Dragging selectors
------------------

The `~matplotlib.widgets.RectangleSelector` and
`~matplotlib.widgets.EllipseSelector` have a new keyword argument,
The `~matplotlib.widgets.SpanSelector`, `~matplotlib.widgets.RectangleSelector`
and `~matplotlib.widgets.EllipseSelector` have a new keyword argument,
*drag_from_anywhere*, which when set to `True` allows you to click and drag
from anywhere inside the selector to move it. Previously it was only possible
to move it by either activating the move modifier button, or clicking on the
central handle.

The size of the `~matplotlib.widgets.SpanSelector` can now be changed using
the edge handles.
16 changes: 12 additions & 4 deletions examples/widgets/span_selector.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
fig, (ax1, ax2) = plt.subplots(2, figsize=(8, 6))

x = np.arange(0.0, 5.0, 0.01)
y = np.sin(2*np.pi*x) + 0.5*np.random.randn(len(x))
y = np.sin(2 * np.pi * x) + 0.5 * np.random.randn(len(x))

ax1.plot(x, y)
ax1.set_ylim(-2, 2)
Expand All @@ -37,7 +37,8 @@ def onselect(xmin, xmax):
line2.set_data(region_x, region_y)
ax2.set_xlim(region_x[0], region_x[-1])
ax2.set_ylim(region_y.min(), region_y.max())
fig.canvas.draw()
fig.canvas.draw_idle()


#############################################################################
# .. note::
Expand All @@ -47,8 +48,15 @@ def onselect(xmin, xmax):
#


span = SpanSelector(ax1, onselect, 'horizontal', useblit=True,
rectprops=dict(alpha=0.5, facecolor='tab:blue'))
span = SpanSelector(
ax1,
onselect,
"horizontal",
useblit=True,
rectprops=dict(alpha=0.5, facecolor="tab:blue"),
interactive=True,
drag_from_anywhere=True
)
# Set useblit=True on most backends for enhanced performance.


Expand Down
88 changes: 84 additions & 4 deletions lib/matplotlib/tests/test_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,20 +195,21 @@ def check_span(*args, **kwargs):
def onselect(vmin, vmax):
ax._got_onselect = True
assert vmin == 100
assert vmax == 150
assert vmax == 199

def onmove(vmin, vmax):
assert vmin == 100
assert vmax == 125
assert vmax == 199
ax._got_on_move = True

if 'onmove_callback' in kwargs:
kwargs['onmove_callback'] = onmove

tool = widgets.SpanSelector(ax, onselect, *args, **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)
# move outside of axis
do_event(tool, 'onmove', xdata=199, ydata=199, button=1)
do_event(tool, 'release', xdata=250, ydata=250, button=1)

assert ax._got_onselect

Expand All @@ -222,6 +223,85 @@ def test_span_selector():
check_span('horizontal', rectprops=dict(fill=True))


@pytest.mark.parametrize('drag_from_anywhere', [True, False])
def test_span_selector_drag(drag_from_anywhere):
ax = get_ax()

def onselect(epress, erelease):
pass

# Create span
tool = widgets.SpanSelector(ax, onselect, 'horizontal', interactive=True,
drag_from_anywhere=drag_from_anywhere)
do_event(tool, 'press', xdata=10, ydata=10, button=1)
do_event(tool, 'onmove', xdata=100, ydata=120, button=1)
do_event(tool, 'release', xdata=100, ydata=120, button=1)
assert tool.extents == (10, 100)
# Drag inside span
#
# If drag_from_anywhere == True, this will move the span by 10,
# giving new value extents = 20, 110
#
# If drag_from_anywhere == False, this will create a new span with
# value extents = 25, 35
do_event(tool, 'press', xdata=25, ydata=15, button=1)
do_event(tool, 'onmove', xdata=35, ydata=25, button=1)
do_event(tool, 'release', xdata=35, ydata=25, button=1)
if drag_from_anywhere:
assert tool.extents == (20, 110)
else:
assert tool.extents == (25, 35)

# Check that in both cases, dragging outside the span draws a new span
do_event(tool, 'press', xdata=175, ydata=185, button=1)
do_event(tool, 'onmove', xdata=185, ydata=195, button=1)
do_event(tool, 'release', xdata=185, ydata=195, button=1)
assert tool.extents == (175, 185)


def test_span_selector_direction():
ax = get_ax()

def onselect(epress, erelease):
pass

tool = widgets.SpanSelector(ax, onselect, 'horizontal', interactive=True)
assert tool.direction == 'horizontal'
assert tool._edge_handles.direction == 'horizontal'

with pytest.raises(ValueError):
tool = widgets.SpanSelector(ax, onselect, 'invalid_direction')

tool.direction = 'vertical'
assert tool.direction == 'vertical'
assert tool._edge_handles.direction == 'vertical'

with pytest.raises(ValueError):
tool.direction = 'invalid_string'


def test_tool_line_handle():
ax = get_ax()

positions = [20, 30, 50]

tool_line_handle = widgets.ToolLineHandles(ax, positions, 'horizontal',
useblit=False)

for artist in tool_line_handle.artists:
assert not artist.get_animated()
assert not artist.get_visible()

tool_line_handle.set_visible(True)
tool_line_handle.set_animated(True)

for artist in tool_line_handle.artists:
assert artist.get_animated()
assert artist.get_visible()

assert tool_line_handle.positions == positions


def check_lasso_selector(**kwargs):
ax = get_ax()

Expand Down
Loading