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

Skip to content

[Bug]: unavoidable DeprecationWarning when using Patch3D #21740

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
jakelishman opened this issue Nov 24, 2021 · 2 comments · Fixed by #21741
Closed

[Bug]: unavoidable DeprecationWarning when using Patch3D #21740

jakelishman opened this issue Nov 24, 2021 · 2 comments · Fixed by #21741

Comments

@jakelishman
Copy link
Contributor

Bug summary

There's currently no nice way to avoid having a deprecation warning issued when using a custom subclass of Patch3D during drawing, caused by this helper function:

def do_3d_projection(artist):
"""
Call `do_3d_projection` on an *artist*, and warn if passing
*renderer*.
For our Artists, never pass *renderer*. For external Artists,
in lieu of more complicated signature parsing, always pass
*renderer* and raise a warning.
"""
if artist.__module__ == 'mpl_toolkits.mplot3d.art3d':
# Our 3D Artists have deprecated the renderer parameter, so
# avoid passing it to them; call this directly once the
# deprecation has expired.
return artist.do_3d_projection()
_api.warn_deprecated(
"3.4",
message="The 'renderer' parameter of "
"do_3d_projection() was deprecated in Matplotlib "
"%(since)s and will be removed %(removal)s.")
return artist.do_3d_projection(renderer)

added in #18302.

The deprecation is only triggered when axes are drawn, so within library code we can't locally suppress the warning, and have to modify global filters (or lie about our patches' __module__) to suppress the warning, even if we comply with the new calling convention (see for example Qiskit/qiskit#7301).

Code for reproduction

from matplotlib import pyplot
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.art3d import Patch3D


class DummyPatch(Patch3D):
    def do_3d_projection(self, renderer=None):
        # This supports both 3.4 and 3.5 calling conventions.
        return 0

    def draw(self, renderer):
        pass

figure = pyplot.figure()
axes = Axes3D(figure, auto_add_to_figure=False)
figure.add_axes(axes)
axes.add_artist(DummyPatch())
axes.add_artist(DummyPatch())

pyplot.show()

Actual outcome

Running causes this warning to be emitted:

/Users/jake/tmp.py:20: MatplotlibDeprecationWarning: The 'renderer' parameter of do_3d_projection() was deprecated in Matplotlib 3.4 and will be removed two minor releases later.
  pyplot.show()

Expected outcome

It would be good to have a way to indicate that we support the new calling convention, so we can avoid triggering the warning - since it only happens when the figure is drawn, we can't reliably suppress the warning in library code without overriding the user's warning filters, which we very much don't want to do.

At the moment we're lying about our __module__ to avoid leaking this to users, but that's not ideal for us. Perhaps matplotlib could check for some other "magic" attribute on the class (like _matplotlib_new_do_3d_projection), or provide a "registration" function in mplot3d which we can call to add our class to, so the z-order sorting knows it can call us with the new convention?

Additional information

This appeared on our CI, so runs the gamut of OSs, Python versions, etc.

Operating system

No response

Matplotlib Version

3.5.0

Matplotlib Backend

No response

Python version

No response

Jupyter version

No response

Installation

pip

@anntzer
Copy link
Contributor

anntzer commented Nov 24, 2021

Would something the following (with an adjustment of the docstring immediately above) work? If so, feel free to post the patch as PR.

diff --git i/lib/mpl_toolkits/mplot3d/axes3d.py w/lib/mpl_toolkits/mplot3d/axes3d.py
index 3aaf31610d..0f82996359 100644
--- i/lib/mpl_toolkits/mplot3d/axes3d.py
+++ w/lib/mpl_toolkits/mplot3d/axes3d.py
@@ -417,19 +417,19 @@ class Axes3D(Axes):
                 *renderer* and raise a warning.
                 """
 
-                if artist.__module__ == 'mpl_toolkits.mplot3d.art3d':
-                    # Our 3D Artists have deprecated the renderer parameter, so
-                    # avoid passing it to them; call this directly once the
-                    # deprecation has expired.
+                sig = inspect.signature(artisy.do_3d_projection)
+                try:
+                    sig.bind()
+                except TypeError:
+                    _api.warn_deprecated(
+                        "3.4",
+                        message="The 'renderer' parameter of "
+                        "do_3d_projection() was deprecated in Matplotlib "
+                        "%(since)s and will be removed %(removal)s.")
+                    return artist.do_3d_projection(renderer)
+                else:  # Call this directly once the deprecation has expired.
                     return artist.do_3d_projection()
 
-                _api.warn_deprecated(
-                    "3.4",
-                    message="The 'renderer' parameter of "
-                    "do_3d_projection() was deprecated in Matplotlib "
-                    "%(since)s and will be removed %(removal)s.")
-                return artist.do_3d_projection(renderer)
-
             collections_and_patches = (
                 artist for artist in self._children
                 if isinstance(artist, (mcoll.Collection, mpatches.Patch))

@jakelishman
Copy link
Contributor Author

Thanks! I made the PR in #21741.

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

Successfully merging a pull request may close this issue.

3 participants