Skip to content

Include child Axes inaxes calculation #25050

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

Closed
wants to merge 1 commit into from

Conversation

QuLogic
Copy link
Member

@QuLogic QuLogic commented Jan 21, 2023

PR Summary

This makes InsetAxes count for this field, and allows widgets to work in them.

Now, one question is that inaxes now is the innermost Axes only. That means axes_leave_event is triggered for a parent Axes when entering the child. Is that the behaviour that's desired? If we instead want this to only trigger when completely outside the parent Axes, we'd have to do something like make inaxes a list (or a private-but-related field if we don't want to change API.)

Fixes #25030

PR Checklist

Documentation and Tests

  • Has pytest style unit tests (and pytest passes)
  • [n/a] Documentation is sphinx and numpydoc compliant (the docs should build without error).
  • [n/a] New plotting related features are documented with examples.

Release Notes

  • [n/a] New features are marked with a .. versionadded:: directive in the docstring and documented in doc/users/next_whats_new/
  • [n/a] API changes are marked with a .. versionchanged:: directive in the docstring and documented in doc/api/next_api_changes/
  • [n/a] Release notes conform with instructions in next_whats_new/README.rst or next_api_changes/README.rst

This makes InsetAxes count for this field, and allows widgets to work in
them.

Fixes matplotlib#25030
@QuLogic
Copy link
Member Author

QuLogic commented Jan 21, 2023

As an example, I took the code from event_handling.rst, and modified it to use nested InsetAxes:

"""
Illustrate the figure and axes enter and leave events by changing the
frame colors on enter and leave
"""
import matplotlib.pyplot as plt


def enter_axes(event):
    print('enter_axes', event.inaxes)
    event.inaxes.patch.set_facecolor('yellow')
    event.canvas.draw()


def leave_axes(event):
    print('leave_axes', event.inaxes)
    event.inaxes.patch.set_facecolor('white')
    event.canvas.draw()


def enter_figure(event):
    print('enter_figure', event.canvas.figure)
    event.canvas.figure.patch.set_facecolor('red')
    event.canvas.draw()


def leave_figure(event):
    print('leave_figure', event.canvas.figure)
    event.canvas.figure.patch.set_facecolor('grey')
    event.canvas.draw()


fig, ax = plt.subplots()
fig.suptitle('mouse hover over figure or axes to trigger events')

ax.set_label('Level 0')
for i in range(4):
    ax = ax.inset_axes([0.2, 0.2, 0.6, 0.6])
    ax.set_label(f'Level {i+1}')

fig.canvas.mpl_connect('figure_enter_event', enter_figure)
fig.canvas.mpl_connect('figure_leave_event', leave_figure)
fig.canvas.mpl_connect('axes_enter_event', enter_axes)
fig.canvas.mpl_connect('axes_leave_event', leave_axes)

plt.show()

If you mouse over, then you will see the outer Axes leave events trigger as the mouse enters the inner Axes (i.e., only one Axes will ever be yellow).

@jklymak
Copy link
Member

jklymak commented Jan 31, 2023

It wouldn't seem that you want to say you left the axes if you didn't leave the axes? I'm a little unclear of the use case here - do we want inset axes to have widgets in them? Not clear what the interactive logic is here, particularly as an inset axes doesn't have to be on top of the parent at all. Is there a reason we only check if the mouse is in an axes versus over a GUI element?

@anntzer
Copy link
Contributor

anntzer commented Mar 21, 2023

In general I think axes_enter_event/axes_leave_event are rather poorly specified, exactly because it's unclear what should happen with overlapping axes.
Also the patch here is likely wrong, as noted by @jklymak, if the inset axes is not actually within the parent; this is actually a use case demonstrated in https://matplotlib.org/stable/gallery/lines_bars_and_markers/scatter_hist.html

FWIW I would just get rid of axes_enter_event and axes_leave_event, and just hook to motion_notify_event, something like

from matplotlib import pyplot as plt


def on_motion(event):
    inaxes = event.inaxes  # Depends on the actual inaxes semantics, of course.
    for ax in axs:
        ax.patch.set_facecolor("w")
    if inaxes:
        inaxes.patch.set_facecolor("y")
    event.canvas.draw()  # Could draw only if a change was actually made.


axs = []

fig, ax = plt.subplots()

ax.set_label('Level 0')
axs.append(ax)
for i in range(4):
    ax = ax.inset_axes([0.2, 0.2, 0.6, 0.6])
    ax.set_label(f'Level {i+1}')
    axs.append(ax)

fig.canvas.mpl_connect('motion_notify_event', on_motion)

plt.show()

@anntzer
Copy link
Contributor

anntzer commented May 12, 2023

I think #25555 may be a more general fix for the original issue, although it does not try to address what axes_{enter,leave}_event means in the presence of overlapping axes (again, I think that was not a really well-defined API to start with...).

@QuLogic
Copy link
Member Author

QuLogic commented May 31, 2023

Yes, I thought that might be the case when I first saw that PR, but did not try it out.

@QuLogic
Copy link
Member Author

QuLogic commented Aug 1, 2023

The original issue was fixed by #25555. While we should work out semantics for axes_enter/leave_event, not sure this is the right way to that.

@QuLogic QuLogic closed this Aug 1, 2023
@QuLogic QuLogic deleted the inaxes-children branch December 8, 2023 03:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[BUG]: Button widgets don't work in inset axes
3 participants