FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

[Bug]: AttributeError: 'Arrow3D' object has no attribute 'do_3d_projection' · Issue #21688 · matplotlib/matplotlib · GitHub

Repository navigation

[Bug]: AttributeError: 'Arrow3D' object has no attribute 'do_3d_projection' #21688

Description

Bug summary

New (appears in matplotlib=3.5) an AttributeError is thrown stating 'Arrow3D' object has no attribute 'do_3d_projection'.

The error appears when running, e.g., the nice example https://stackoverflow.com/a/29188796 by @tacaswell . Below I extracted a MWE from the stackoverflow code.

Code for reproduction

# MWE extracted from https://stackoverflow.com/a/29188796 by @tacaswell 

import numpy as np
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.patches import FancyArrowPatch
from mpl_toolkits.mplot3d import proj3d

class Arrow3D(FancyArrowPatch):
    def __init__(self, xs, ys, zs, *args, **kwargs):
        FancyArrowPatch.__init__(self, (0,0), (0,0), *args, **kwargs)
        self._verts3d = xs, ys, zs

    def draw(self, renderer):
        xs3d, ys3d, zs3d = self._verts3d
        xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, renderer.M)
        self.set_positions((xs[0],ys[0]),(xs[1],ys[1]))
        FancyArrowPatch.draw(self, renderer)

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
arrow_prop_dict = dict(mutation_scale=20, arrowstyle='-|>', color='k', shrinkA=0, shrinkB=0)
a = Arrow3D([0, 10], [0, 0], [0, 0], **arrow_prop_dict)
ax.add_artist(a)

Actual outcome

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
~/anaconda3/lib/python3.8/site-packages/IPython/core/formatters.py in __call__(self, obj)
    339                 pass
    340             else:
--> 341                 return printer(obj)
    342             # Finally look for special method names
    343             method = get_real_method(obj, self.print_method)

~/anaconda3/lib/python3.8/site-packages/IPython/core/pylabtools.py in <lambda>(fig)
    248 
    249     if 'png' in formats:
--> 250         png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png', **kwargs))
    251     if 'retina' in formats or 'png2x' in formats:
    252         png_formatter.for_type(Figure, lambda fig: retina_figure(fig, **kwargs))

~/anaconda3/lib/python3.8/site-packages/IPython/core/pylabtools.py in print_figure(fig, fmt, bbox_inches, **kwargs)
    132         FigureCanvasBase(fig)
    133 
--> 134     fig.canvas.print_figure(bytes_io, **kw)
    135     data = bytes_io.getvalue()
    136     if fmt == 'svg':

~/anaconda3/lib/python3.8/site-packages/matplotlib/backend_bases.py in print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, pad_inches, bbox_extra_artists, backend, **kwargs)
   2288                 )
   2289                 with getattr(renderer, "_draw_disabled", nullcontext)():
-> 2290                     self.figure.draw(renderer)
   2291 
   2292             if bbox_inches:

~/anaconda3/lib/python3.8/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
     71     @wraps(draw)
     72     def draw_wrapper(artist, renderer, *args, **kwargs):
---> 73         result = draw(artist, renderer, *args, **kwargs)
     74         if renderer._rasterizing:
     75             renderer.stop_rasterizing()

~/anaconda3/lib/python3.8/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer)
     48                 renderer.start_filter()
     49 
---> 50             return draw(artist, renderer)
     51         finally:
     52             if artist.get_agg_filter() is not None:

~/anaconda3/lib/python3.8/site-packages/matplotlib/figure.py in draw(self, renderer)
   2801 
   2802             self.patch.draw(renderer)
-> 2803             mimage._draw_list_compositing_images(
   2804                 renderer, self, artists, self.suppressComposite)
   2805 

~/anaconda3/lib/python3.8/site-packages/matplotlib/image.py in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
    130     if not_composite or not has_images:
    131         for a in artists:
--> 132             a.draw(renderer)
    133     else:
    134         # Composite any adjacent images together

~/anaconda3/lib/python3.8/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer)
     48                 renderer.start_filter()
     49 
---> 50             return draw(artist, renderer)
     51         finally:
     52             if artist.get_agg_filter() is not None:

~/anaconda3/lib/python3.8/site-packages/mpl_toolkits/mplot3d/axes3d.py in draw(self, renderer)
    445                                     for axis in self._get_axis_list()) + 1
    446                 collection_zorder = patch_zorder = zorder_offset
--> 447                 for artist in sorted(collections_and_patches,
    448                                      key=do_3d_projection,
    449                                      reverse=True):

~/anaconda3/lib/python3.8/site-packages/mpl_toolkits/mplot3d/axes3d.py in do_3d_projection(artist)
    434                     "do_3d_projection() was deprecated in Matplotlib "
    435                     "%(since)s and will be removed %(removal)s.")
--> 436                 return artist.do_3d_projection(renderer)
    437 
    438             collections_and_patches = (

AttributeError: 'Arrow3D' object has no attribute 'do_3d_projection'

[@tacaswell edited to add markup]

Expected outcome

Should draw the fancy arrow.

Additional information

This worked before matplotlib 3.5; error appears in different Python versions and different backends.

Operating system

Linux

Matplotlib Version

3.5.0

Matplotlib Backend

module://ipykernel.pylab.backend_inline

Python version

No response

Jupyter version

No response

Installation

conda

Activity

  1. jklymak commented on Nov 20, 2021

    Member

    Do you know what version of Matplotlib this last worked with? Thanks!

  2. prisae commented on Nov 20, 2021

    Author

    It starts to fail with v3.5.0. v3.4.3 is still fine.

  3. tacaswell commented on Nov 21, 2021

    Member

    I think this is another bit of fallout from merging the internal representation of axes children from any lists to 1 list. Previously, the Arrow3D here would be in a list that was did not participate in the z-order sorting, and hence that it was missing one of the methods from the 3D api was missed. However, now that we have them merged, we reconstruct the old lists (which were nominally sorted by type) by picking out all of the children of the right type.

    The fix here is to correct Arrow3D to have the missing method:

    import numpy as np
    from matplotlib import pyplot as plt
    from mpl_toolkits.mplot3d import Axes3D
    from matplotlib.patches import FancyArrowPatch
    from mpl_toolkits.mplot3d import proj3d
    
    class Arrow3D(FancyArrowPatch):
        def __init__(self, xs, ys, zs, *args, **kwargs):
            super().__init__((0,0), (0,0), *args, **kwargs)
            self._verts3d = xs, ys, zs
    
        def do_3d_projection(self, renderer=None):
            xs3d, ys3d, zs3d = self._verts3d
            xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, self.axes.M)
            self.set_positions((xs[0],ys[0]),(xs[1],ys[1]))
    
            return np.min(zs)
    
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    arrow_prop_dict = dict(mutation_scale=20, arrowstyle='-|>', color='k', shrinkA=0, shrinkB=0)
    a = Arrow3D([0, 10], [0, 0], [0, 0], **arrow_prop_dict)
    ax.add_artist(a)
    
    plt.show()
  4. prisae commented on Nov 22, 2021

    Author

    This works fine, thanks @tacaswell !

  5. QuLogic commented on Nov 22, 2021

    Member
        def do_3d_projection(self, render=None):

    That should be renderer, not render, though I don't believe anything calls it with the name explicitly.

  6. added a commit that references this issue on Aug 9, 2022
  7. Siddhartha082 commented on Aug 26, 2022

    Exact Code .. here

    %pylab inline

    from matplotlib import pyplot as plt
    from mpl_toolkits.mplot3d import Axes3D
    from mpl_toolkits.mplot3d import proj3d
    from matplotlib.patches import FancyArrowPatch
    %matplotlib inline

    class Arrow3D(FancyArrowPatch):
    def init(self, xs, ys, zs, *args, **kwargs):
    FancyArrowPatch.init(self, (0,0), (0,0), *args, **kwargs)
    self._verts3d = xs, ys, zs

    def  do_3d_projection(self, renderer):
        xs3d, ys3d, zs3d = self._verts3d
        xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, self.axes.M)
        self.set_positions((xs[0],ys[0]),(xs[1],ys[1]))
        FancyArrowPatch.draw(self, renderer)
    
        return np.min(zs)
    

    fig = plt.figure(figsize=(7,7))
    ax = fig.add_subplot(111, projection='3d')

    ax.plot(df['feature1'], df['feature2'], df['feature3'], 'o', markersize=8, color='blue', alpha=0.2)
    ax.plot([df['feature1'].mean()], [df['feature2'].mean()], [df['feature3'].mean()], 'o', markersize=10, color='red', alpha=0.5)
    for v in eigen_vectors.T:
    a = Arrow3D([df['feature1'].mean(), v[0]], [df['feature2'].mean(), v[1]], [df['feature3'].mean(), v[2]], mutation_scale=20, lw=3, arrowstyle="-|>", color="r")
    ax.add_artist(a)
    ax.set_xlabel('x_values')
    ax.set_ylabel('y_values')
    ax.set_zlabel('z_values')

    plt.title('Eigenvectors')

    plt.show()

  8. tacaswell commented on Aug 26, 2022

    Member

    @Siddhartha082 I do not understand what you are trying to say.

  9. aimlwithgautam commented on Nov 8, 2022

    Thanks you @tacaswell !

  10. Neombpure commented on Mar 5, 2023

    I think this is another bit of fallout from merging the internal representation of axes children from any lists to 1 list. Previously, the Arrow3D here would be in a list that was did not participate in the z-order sorting, and hence that it was missing one of the methods from the 3D api was missed. However, now that we have them merged, we reconstruct the old lists (which were nominally sorted by type) by picking out all of the children of the right type.

    The fix here is to correct Arrow3D to have the missing method:

    import numpy as np
    from matplotlib import pyplot as plt
    from mpl_toolkits.mplot3d import Axes3D
    from matplotlib.patches import FancyArrowPatch
    from mpl_toolkits.mplot3d import proj3d
    
    class Arrow3D(FancyArrowPatch):
        def __init__(self, xs, ys, zs, *args, **kwargs):
            super().__init__((0,0), (0,0), *args, **kwargs)
            self._verts3d = xs, ys, zs
    
        def do_3d_projection(self, renderer=None):
            xs3d, ys3d, zs3d = self._verts3d
            xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, self.axes.M)
            self.set_positions((xs[0],ys[0]),(xs[1],ys[1]))
    
            return np.min(zs)
    
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    arrow_prop_dict = dict(mutation_scale=20, arrowstyle='-|>', color='k', shrinkA=0, shrinkB=0)
    a = Arrow3D([0, 10], [0, 0], [0, 0], **arrow_prop_dict)
    ax.add_artist(a)
    
    plt.show()

    NB,NB,NB

  11. gabemorris12 commented on Mar 22, 2024

    Can this class just be added to the library?

  12. added a commit that references this issue on Jul 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions


      Back | FazBrowse Home | New Git URL