8000 Fix AxesWidgets on inset_axes that are outside their parent. · matplotlib/matplotlib@973a728 · GitHub
[go: up one dir, main page]

Skip to content

Commit 973a728

Browse files
committed
Fix AxesWidgets on inset_axes that are outside their parent.
When axes are overlapping, LocationEvent.inaxes can point not to the axes we care about, but to another one. Widgets currently recompute location event axes coordinates relative to the axes to which the widget is assigned, but this recomputation code was previously brittle wrt. events that are outside the axes they wrongly believe they belong to (so x/ydata is None), even though they are indeed within the axes they actually belong to. This can occur when a widget is associated with an "inset_axes" that's actually outside the parent axes. A practical case is given by ```python from pylab import * ax = figure(layout="constrained").add_subplot() ax1 = ax.inset_axes([0, 1, 1, .25], sharex=ax) ss = mpl.widgets.SpanSelector(ax1, print, "horizontal") show() # try to trigger the spanselector ``` which would raise an exception prior to this patch. Improve the recomputation logic by fully reparenting the event passed to the widget to the correct parent axes from the onset.
1 parent d797ee5 commit 973a728

File tree

2 files changed

+107
-60
lines changed

2 files changed

+107
-60
lines changed

lib/matplotlib/tests/test_widgets.py

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -623,27 +623,35 @@ def test_rectangle_selector_ignore_outside(ax, ignore_event_outside):
623623
('horizontal', False, dict(interactive=True)),
624624
])
625625
def test_span_selector(ax, orientation, onmove_callback, kwargs):
626-
onselect = mock.Mock(spec=noop, return_value=None)
627-
onmove = mock.Mock(spec=noop, return_value=None)
628-
if onmove_callback:
629-
kwargs['onmove_callback'] = onmove
630-
631-
# While at it, also test that span selectors work in the presence of twin axes on
632-
# top of the axes that contain the selector. Note that we need to unforce the axes
633-
# aspect here, otherwise the twin axes forces the original axes' limits (to respect
634-
# aspect=1) which makes some of the values below go out of bounds.
626+
# Also test that span selectors work in the presence of twin axes or for
627+
# outside-inset axes on top of the axes that contain the selector. Note
628+
# that we need to unforce the axes aspect here, otherwise the twin axes
629+
# forces the original axes' limits (to respect aspect=1) which makes some
630+
# of the values below go out of bounds.
635631
ax.set_aspect("auto")
636-
tax = ax.twinx()
637-
638-
tool = widgets.SpanSelector(ax, onselect, orientation, **kwargs)
639-
do_event(tool, 'press', xdata=100, ydata=100, button=1)
640-
# move outside of axis
641-
do_event(tool, 'onmove', xdata=199, ydata=199, button=1)
642-
do_event(tool, 'release', xdata=250, ydata=250, button=1)
643-
644-
onselect.assert_called_once_with(100, 199)
645-
if onmove_callback:
646-
onmove.assert_called_once_with(100, 199)
632+
ax.twinx()
633+
child = ax.inset_axes([0, 1, 1, 1], xlim=(0, 200), ylim=(0, 200))
634+
635+
for target in [ax, child]:
636+
selected = []
637+
def onselect(*args): selected.append(args)
638+
moved = []
639+
def onmove(*args): moved.append(args)
640+
if onmove_callback:
641+
kwargs['onmove_callback'] = onmove
642+
643+
tool = widgets.SpanSelector(target, onselect, orientation, **kwargs)
644+
x, y = target.transData.transform((100, 100))
645+
MouseEvent('button_press_event', ax.figure.canvas, x, y, button=1)._process()
646+
# move outside of axis
647+
x, y = target.transData.transform((199, 199))
648+
MouseEvent('motion_notify_event', ax.figure.canvas, x, y, button=1)._process()
649+
do_event(tool, 'release', xdata=250, ydata=250, button=1)
650+
651+
# tol is set by pixel size (~100 pixels & span of 200 data units)
652+
assert_allclose(selected, [(100, 199)], atol=.5)
653+
if onmove_callback:
654+
assert_allclose(moved, [(100, 199)], atol=.5)
647655

648656

649657
@pytest.mark.parametrize('interactive', [True, False])

0 commit comments

Comments
 (0)
0