Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[wip] Replace _remove_method by _on_remove list of callbacks #10876

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 2 commits into from

Conversation

anntzer
Copy link
Contributor

@anntzer anntzer commented Mar 25, 2018

PR Summary

First commit replaces Artist._remove_method (called by Artist.remove) by a list of callbacks (with the same signature), Artist._on_remove.

Second commit shows the use case of such a change: it allows us to disconnect the dragging handlers when an artist is removed from an axes. An minimal example is the following:

from pylab import *
rcdefaults()

ann = gca().annotate(
    "hello", xy=(.4, .4), xytext=(.6, .6), arrowprops={"arrowstyle": "->"})
ann.draggable(True, use_blit=True)

def handler(event):
    ann.remove()
    gcf().canvas.draw()

gcf().canvas.mpl_connect("pick_event", handler)

plt.show()

and click on the annotation and try to drag it. As of master, this cause the following exception to be printed:

Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/matplotlib/cbook/__init__.py", line 388, in process
    proxy(*args, **kwargs)
  File "/usr/lib/python3.6/site-packages/matplotlib/cbook/__init__.py", line 228, in __call__
    return mtd(*args, **kwargs)
  File "/usr/lib/python3.6/site-packages/matplotlib/offsetbox.py", line 1672, in on_motion_blit
    self.ref_artist.draw(self.ref_artist.figure._cachedRenderer)
AttributeError: 'NoneType' object has no attribute '_cachedRenderer'

and this is fixed by the PR. (Note that clicking a second time would cause a different exception, independently of this PR, due to the fact that an artist cannot be removed twice.)

This may seem to be a slightly obscure case, but I have a real use case in https://github.com/anntzer/mplcursors: there, clicking on an artist will create an annotation on that artist, removing a previously created annotation (on another artist); then, moving the mouse would try to drag the now deleted annotation.

PR Checklist

  • Has Pytest style unit tests
  • Code is PEP 8 compliant

Only touches private API.

Copy link
Member

@jklymak jklymak left a comment

Choose a reason for hiding this comment

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

This looks correct to me....

@tacaswell tacaswell added this to the v3.0 milestone Mar 28, 2018
@tacaswell
Copy link
Member

We can not rely on weakref to save us here because the user is holding a hard ref to the artist they just removed.

We don't have to worry about third party tools having used this because it is set by the Axes / Figure that the artist is added to (not by the class).

Do we want to add a a add_remove_callback / remove_remove_callback methods (and those names are awful)? I can see third party libraries wanting to add custom on-remove logic like draggable. Not going to hold the PR over this.

@anntzer
Copy link
Contributor Author

anntzer commented Mar 28, 2018

The problem is that this is not even a complete solution: calling cla(), for example, just does axes.lines = []; ... so the child artist object never actually get notified that they have been removed from the axes (#6982).

I have also thought for a while that the whole idea of CallbackRegistry relying on weakrefs is a bad idea: there are plenty of cases where we don't register a method, but a closure on the artist, and they don't get properly weakref'ed.

Now that I think of it, I'd prefer a solution where we just expect people to register WeakMethods (if they desire so) into the registry, callbacks to explicitly check whether the artists they care about have not been removed yet -- whether by looking for the .axes attribute, or, if you're really paranoid and care about the case where the artist was not properly deparented, check that the artist is still a child of the axes (https://github.com/anntzer/mplcursors/blob/master/lib/mplcursors/_mplcursors.py#L72))

Let me make a PR along these lines (for the specific case of draggable) before deciding on the best solution.

(Funny that one cannot put a review rejecting one's own PR :-))

@anntzer anntzer changed the title Replace _remove_method by _on_remove list of callbacks [wip] Replace _remove_method by _on_remove list of callbacks Mar 28, 2018
@anntzer
Copy link
Contributor Author

anntzer commented Mar 28, 2018

Closed in favor of #10908.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants