Skip to content
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

figure_enter_event uses now LocationEvent instead of Event. Fix issue #9812. #9814

Merged
merged 4 commits into from
Mar 5, 2018
Merged

figure_enter_event uses now LocationEvent instead of Event. Fix issue #9812. #9814

merged 4 commits into from
Mar 5, 2018

Conversation

lkjell
Copy link
Contributor

@lkjell lkjell commented Nov 19, 2017

PR Summary

In the documentation 1 figure_enter_event uses LocationEvent. However, previously it just uses the base class Event. This cause some problem when trying to access LocationEvent attributes because they did not exist. This addresses issue #9812.

Fix also an issue that tkagg backend does not have a figure_enter_event.
gtk3, Qt5 and wx pass in coordinates when entering figure.

The tkagg backend did not have a figure_leave_event. Enabling that as well.

Sample script using Qt5 backend. Move the cursor in and out of the figure.

import matplotlib

matplotlib.use("Qt5Agg")
import matplotlib.pyplot as plt
import numpy as np

x = range(100)

fig, ax = plt.subplots()
ax.plot(np.random.rand(10))


def stat(event):
    print("axes: {}, x: {}, y: {}".format(event.inaxes, event.x, event.y))


cid = fig.canvas.mpl_connect('figure_enter_event', stat)
cid = fig.canvas.mpl_connect('figure_leave_event', stat)

plt.show()

PR Checklist

  • Code is PEP 8 compliant

@lkjell
Copy link
Contributor Author

lkjell commented Nov 19, 2017

Should perhaps change the backends to pass inn their coordinates as well. As for now the fix is having

else:
    x = None
    y = None

in FigureCanvasBase.enter_notify_event, as in the commit.

grep "FigureCanvasBase.enter_notify_event" *py
backend_gtk3.py:        FigureCanvasBase.enter_notify_event(self, event)
backend_gtk.py:        FigureCanvasBase.enter_notify_event(self, event, xy=(x, y))
backend_qt5.py:        FigureCanvasBase.enter_notify_event(self, guiEvent=event)
backend_wx.py:        FigureCanvasBase.enter_notify_event(self, guiEvent=evt)

@jklymak
Copy link
Member

jklymak commented Nov 19, 2017

Thanks for the PR. You'll probably get more testers if you give us a sample script to try that shows this works better.

@lkjell lkjell changed the title figure_enter_event uses now LocationEvent instead of Event. figure_enter_event uses now LocationEvent instead of Event. Fix issue #8576. Nov 19, 2017
@lkjell lkjell changed the title figure_enter_event uses now LocationEvent instead of Event. Fix issue #8576. figure_enter_event uses now LocationEvent instead of Event. Fix issue #9812. Nov 19, 2017
@lkjell lkjell closed this Nov 19, 2017
@lkjell lkjell reopened this Nov 19, 2017
@tacaswell tacaswell added this to the v2.2 milestone Nov 19, 2017
@tacaswell
Copy link
Member

wow, that is a pretty big likely long standing bug!

@tacaswell
Copy link
Member

tacaswell commented Nov 19, 2017

ok, so it looks like the sub-classes of FigureCanvasBase that over-ride enter_notify_event are changing the signature / purpose a bit (gtk, gtk3, tk). The method on FigureCanvasBase generates the Event instance that Matplotlib uses internally and turns the crank on our callbacks where as the methods of the sub-classes are registered as callbacks into the underlying GUI event handling frame work which has it's own required signature (if you look at the Qt5, Wx and Webagg backends they use a differently method to register into the GUI framework callback system).

Doing this from scratch I think the second pattern is better, but it is probably not worth the effort to deprecate and rename the bridge methods in {gtk,gtk3, tk} (the work would be to create new methods rename the methods to _on_enter, shim the behavior back into enter_notify_event and warn about usage. In a future release we would remove the methods on the sub-classes and just let it fallback to the base class behavior).

@lkjell
Copy link
Contributor Author

lkjell commented Nov 19, 2017

The method name enter_notify_event (gtk, gtk3, tk) I believe was the initial usage. After a while when changing the signature of the FigureCanvasBase.enter_notify_event to use add xy coordinates or LocationEvent something must have been missed out.

The bridge method for tk enter_notify_event I added in commit cb3146d was for consistency of the naming scheme used in the class.

Copy link
Member

@tacaswell tacaswell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor comments, but 👍 as-is

Tested on

  • qt5
  • tk

@@ -268,7 +268,8 @@ def get_width_height(self):
return int(w / self._dpi_ratio), int(h / self._dpi_ratio)

def enterEvent(self, event):
FigureCanvasBase.enter_notify_event(self, guiEvent=event)
x, y = self.mouseEventCoords(event.pos())
FigureCanvasBase.enter_notify_event(self, guiEvent=event, xy=(x, y))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can just be self.enter_notif_event(guiEvent=event, xy=(x, y))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could do but that would break some inconsistency with the other event as well. For example

def wheelEvent(self, event):
    x, y = self.mouseEventCoords(event)
    # from QWheelEvent::delta doc
    if event.pixelDelta().x() == 0 and event.pixelDelta().y() == 0:
        steps = event.angleDelta().y() / 120
    else:
        steps = event.pixelDelta().y()
    if steps:
        FigureCanvasBase.scroll_event(self, x, y, steps, guiEvent=event)

def keyPressEvent(self, event):
    key = self._get_key(event)
    if key is not None:
        FigureCanvasBase.key_press_event(self, key, guiEvent=event)

def keyReleaseEvent(self, event):
    key = self._get_key(event)
    if key is not None:
        FigureCanvasBase.key_release_event(self, key, guiEvent=event)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair. I suppose those could also all be changed to normal method calls, but that is beyond the scope of this PR.

@@ -2017,8 +2017,11 @@ def enter_notify_event(self, guiEvent=None, xy=None):
if xy is not None:
x, y = xy
self._lastx, self._lasty = x, y
else:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a warning here like

warnings.warn('enter_notify_event expects a location but your backend did not pass one. '
              'This may become mandatory in the future', stacklevel=2)

?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cbook.warn_deprecated?

x = evt.GetX()
y = self.figure.bbox.height - evt.GetY()
evt.Skip()
FigureCanvasBase.enter_notify_event(self, guiEvent=evt, xy=(x, y))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can also just be self.enter_notify_event.

@@ -340,6 +342,11 @@ def motion_notify_event(self, event):
y = self.figure.bbox.height - event.y
FigureCanvasBase.motion_notify_event(self, x, y, guiEvent=event)

def enter_notify_event(self, event):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably better named something else (as it is new)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could but breaks naming scheme used in the class.

@lkjell
Copy link
Contributor Author

lkjell commented Dec 7, 2017

@tacaswell Will this get merged soon or there need more testing?

@lkjell
Copy link
Contributor Author

lkjell commented Mar 2, 2018

This one has gone too long @tacaswell . I needed to strip some commits since there where some confilics with the master branch and I simple do not have the time to solve the merge conflics.

@tacaswell tacaswell modified the milestones: needs sorting, v3.0 Mar 2, 2018
@tacaswell
Copy link
Member

@lkjell Sorry this has sat for so long, I assure you it is not personal!

I am confused by your comment though as it looks like have fixed the merge conflicts (as the tests are running).

else:
x = None
y = None
warn_deprecated('2.2', 'enter_notify_event expects a location but your backend did not pass one.')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be changed to '3.0' ?

@tacaswell
Copy link
Member

tacaswell commented Mar 2, 2018

Can you also add an entry in https://github.com/matplotlib/matplotlib/tree/master/doc/users/next_whats_new (so people know they can use this!)

@lkjell
Copy link
Contributor Author

lkjell commented Mar 2, 2018

This is a bug fix. https://matplotlib.org/users/event_handling.html
I added some fixes such that backends passed in their coordinates as well. Apparently not all passed in their coordinates.

@tacaswell
Copy link
Member

🐑 your right, that is what I get for reading from the bottom!

@efiring
Copy link
Member

efiring commented Mar 4, 2018

If I understand correctly, the original PR included fixes to backends; the present version of this PR adds a warning, but does not have any fixes to the backends. Therefore, if this PR is merged, an attempt to use the figure enter/leave events will generate the deprecation warnings until another PR provides the backend fixes. It is unfortunate that those original fixes were wiped out because they needed to be rebased. Am I correct, or hopelessly confused?
It would be nice to get all this straightened out ASAP.

@lkjell
Copy link
Contributor Author

lkjell commented Mar 4, 2018

@efiring something like that. If memory serve right some backend did pass in None, None. Some did not register an Enter event(gtk).

The backend fix had merge confict and you need to edit the super to python3 only.

@lkjell
Copy link
Contributor Author

lkjell commented Mar 4, 2018

My fault for not looking into deeper. I restored the non-conflicting commits. The only conflicting backend is tk. It appears that file was renamed to _backend_tk.py

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.

None yet

5 participants