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

Remove visibility changes in draw for *Cursor widgets #19763

Merged
merged 2 commits into from
Dec 16, 2022
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/deprecations/19763-ES.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
``Cursor`` and ``MultiCursor`` event handlers are now private
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Access to the event handlers for the `.Cursor` and `.MultiCursor` widgets is
now deprecated.
4 changes: 2 additions & 2 deletions lib/matplotlib/tests/test_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -1517,7 +1517,7 @@ def test_MultiCursor(horizOn, vertOn):
# Can't use `do_event` as that helper requires the widget
# to have a single .ax attribute.
event = mock_event(ax1, xdata=.5, ydata=.25)
multi.onmove(event)
multi._onmove(event)

# the lines in the first two ax should both move
for l in multi.vlines:
Expand All @@ -1528,7 +1528,7 @@ def test_MultiCursor(horizOn, vertOn):
# test a move event in an Axes not part of the MultiCursor
# the lines in ax1 and ax2 should not have moved.
event = mock_event(ax3, xdata=.75, ydata=.75)
multi.onmove(event)
multi._onmove(event)
for l in multi.vlines:
assert l.get_xdata() == (.5, .5)
for l in multi.hlines:
Expand Down
51 changes: 34 additions & 17 deletions lib/matplotlib/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -1600,8 +1600,8 @@ def __init__(self, ax, horizOn=True, vertOn=True, useblit=False,
**lineprops):
super().__init__(ax)

self.connect_event('motion_notify_event', self.onmove)
self.connect_event('draw_event', self.clear)
self.connect_event('motion_notify_event', self._onmove)
self.connect_event('draw_event', self._clear)

self.visible = True
self.horizOn = horizOn
Expand All @@ -1616,16 +1616,25 @@ def __init__(self, ax, horizOn=True, vertOn=True, useblit=False,
self.background = None
self.needclear = False

@_api.deprecated('3.5')
def clear(self, event):
"""Internal event handler to clear the cursor."""
self._clear(event)
if self.ignore(event):
return
if self.useblit:
self.background = self.canvas.copy_from_bbox(self.ax.bbox)
self.linev.set_visible(False)
self.lineh.set_visible(False)

def onmove(self, event):
def _clear(self, event):
"""Internal event handler to clear the cursor."""
if self.ignore(event):
return
if self.useblit:
self.background = self.canvas.copy_from_bbox(self.ax.bbox)

onmove = _api.deprecate_privatize_attribute('3.5')

def _onmove(self, event):
"""Internal event handler to draw the cursor when the mouse moves."""
if self.ignore(event):
return
Expand All @@ -1640,15 +1649,15 @@ def onmove(self, event):
self.needclear = False
return
self.needclear = True
if not self.visible:
return

self.linev.set_xdata((event.xdata, event.xdata))
self.linev.set_visible(self.visible and self.vertOn)

self.lineh.set_ydata((event.ydata, event.ydata))
self.linev.set_visible(self.visible and self.vertOn)
self.lineh.set_visible(self.visible and self.horizOn)

self._update()
if self.visible and (self.vertOn or self.horizOn):
self._update()

def _update(self):
if self.useblit:
Expand Down Expand Up @@ -1749,8 +1758,8 @@ def connect(self):
"""Connect events."""
for canvas, info in self._canvas_infos.items():
info["cids"] = [
canvas.mpl_connect('motion_notify_event', self.onmove),
canvas.mpl_connect('draw_event', self.clear),
canvas.mpl_connect('motion_notify_event', self._onmove),
canvas.mpl_connect('draw_event', self._clear),
]

def disconnect(self):
Expand All @@ -1760,24 +1769,31 @@ def disconnect(self):
canvas.mpl_disconnect(cid)
info["cids"].clear()

@_api.deprecated('3.5')
def clear(self, event):
"""Clear the cursor."""
if self.ignore(event):
return
self._clear(event)
for line in self.vlines + self.hlines:
line.set_visible(False)

def _clear(self, event):
"""Clear the cursor."""
if self.ignore(event):
return
if self.useblit:
for canvas, info in self._canvas_infos.items():
info["background"] = canvas.copy_from_bbox(canvas.figure.bbox)
for line in self.vlines + self.hlines:
line.set_visible(False)

def onmove(self, event):
onmove = _api.deprecate_privatize_attribute('3.5')

def _onmove(self, event):
if (self.ignore(event)
or event.inaxes not in self.axes
or not event.canvas.widgetlock.available(self)):
return
self.needclear = True
Copy link
Contributor

Choose a reason for hiding this comment

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

Sidenote but as far as I can tell self.needclear is never actually used in MultiCursor

if not self.visible:
Copy link
Member

Choose a reason for hiding this comment

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

Why drop this?

Copy link
Member

Choose a reason for hiding this comment

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

I think we want to keep this short-circuit to avoid going to _update which avoids a draw_idle down the line.

Copy link
Member

Choose a reason for hiding this comment

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

If that's the case, we might want to clarify that for our future selves with a comment.

Copy link
Member Author

@QuLogic QuLogic Mar 26, 2021

Choose a reason for hiding this comment

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

Well, we want to remove it from here so that the later .set_visible is effective. I'll see if we can still skip the _update at least. Alternatively, we should turn the visibility attributes into property setters.

Copy link
Member

Choose a reason for hiding this comment

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

Oh, I see now. We used to always make the lines not visible so if not self.visible we could safely bail.

Do we need some more careful logic on this like to call self._update() if visible or just made invisible? I suspect there is now also some path where we can set self.vertOn or self.horizOn to False and then they never get removed?

Copy link
Member Author

Choose a reason for hiding this comment

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

I re-added a condition on the _update calls, which is hopefully sufficient.

return
if self.vertOn:
for line in self.vlines:
line.set_xdata((event.xdata, event.xdata))
Expand All @@ -1786,7 +1802,8 @@ def onmove(self, event):
for line in self.hlines:
line.set_ydata((event.ydata, event.ydata))
line.set_visible(self.visible)
self._update()
if self.visible and (self.vertOn or self.horizOn):
self._update()

def _update(self):
if self.useblit:
Expand Down