[Python] 'Arrow3D' object has no attribute 'do_3d_projection'; set up X, Y, Z axis on 3D plane

Discussão em 'Python' iniciado por Stack, Dezembro 6, 2024.

  1. Stack

    Stack Membro Participativo

    The purpose of the code is to use arrow3D to initiate X, Y, Z axis on a 3D plane. The parameters of arrow3D are x, y, z, which default to zero; and dx, dy, dz, which is the length of X, Y, Z axis. That way, I could setup my window on 3D plane. So in the code below, arrow3D inherits FancyArrowPatch and has its attributes _xyz and _dxdydz.

    import matplotlib.pyplot as plt
    from mpl_toolkits.mplot3d.proj3d import proj_transform
    from mpl_toolkits.mplot3d.axes3d import Axes3D
    from matplotlib.text import Annotation

    from matplotlib.patches import FancyArrowPatch

    # X axis, Y axis, and Z axis should be added into axes like other artists
    # class Arrow3D is created for them
    # Arrow3D inherits FancyArrowPatch, since those axes are like arrows
    class Arrow3D(FancyArrowPatch):
    def __init__(self, x, y, z, dx, dy, dz, *args, **kwargs):
    super().__init__((0,0), (0,0), *args, **kwargs)
    self._xyz = (x,y,z)
    self._dxdydz = (dx,dy,dz)

    def draw(self, renderer):
    x1,y1,z1 = self._xyz
    dx,dy,dz = self._dxdydz
    x2,y2,z2 = (x1+dx,y1+dy,z1+dz)

    xs, ys, zs = proj_transform((x1,x2),(y1,y2),(z1,z2), renderer.M)
    self.set_positions((xs[0],ys[0]),(xs[1],ys[1]))
    super().draw(renderer)


    def _arrow3D(ax, x, y, z, dx, dy, dz, *args, **kwargs):
    '''Add an 3d arrow to an `Axes3D` instance.'''

    arrow = Arrow3D(x, y, z, dx, dy, dz, *args, **kwargs)
    ax.add_artist(arrow)

    # an object of class Axes3D will have an attribute-'arrow3D', which is the function _arrow3D
    # this object could be axes, when it is created by passing the projection='3d' keyword argument to Figure.add_subplot
    setattr(Axes3D,'arrow3D',_arrow3D)

    # an object of class Axes3D will have an attribute-'arrow3D', which is the function _arrow3D
    # this object could be axes, when it is created by passing the projection='3d' keyword argument to Figure.add_subplot
    setattr(Axes3D,'arrow3D',_arrow3D)


    class Annotation3D(Annotation):
    def __init__(self, text, xyz, *args, **kwargs):
    super().__init__(text, xy=(0,0), *args, **kwargs)
    self._xyz = xyz

    def draw(self, renderer):
    x2, y2, z2 = proj_transform(*self._xyz, renderer.M)
    self.xy=(x2,y2)
    super().draw(renderer)



    def _annotate3D(ax,text, xyz, *args, **kwargs):
    '''Add anotation `text` to an `Axes3d` instance.'''

    annotation= Annotation3D(text, xyz, *args, **kwargs)
    ax.add_artist(annotation)

    setattr(Axes3D,'annotate3D',_annotate3D)




    With arrow3D defined, I then define the _axesSetup so that my 3D background could be set.


    import arrow3d
    from mpl_toolkits.mplot3d.axes3d import Axes3D
    from matplotlib.text import Annotation
    from matplotlib.patches import FancyArrowPatch
    import numpy as np

    def _axesSetup(ax, lX, uX, lY, uY, lZ, uZ):
    # set xlimit, draw x axis, annotate x axis
    # x axis
    ax.set_xlim(lX, uX)
    ax.arrow3D(lX, 0, 0, uX - lX, 0, 0, mutation_scale=15, arrowstyle="-|>", color='red')
    ax.annotate3D('X', (uX, 0, 0), xytext=(0, 0), textcoords=('offset points'), color = 'xkcd:eggplant', weight="bold")

    # y axis
    ax.set_ylim(lY, uY)
    ax.arrow3D(0, lY, 0, 0, uY - lY, 0, mutation_scale=15, arrowstyle="-|>", color='red')
    ax.annotate3D('Y', (0, uY, 0), xytext=(0, 0), textcoords=('offset points'), color = 'xkcd:eggplant', weight="bold")


    # z axis
    ax.set_zlim(lZ, uZ)
    ax.arrow3D(0, 0, lZ, 0, 0, uZ - lZ, mutation_scale=15, arrowstyle="-|>", color='red')
    ax.annotate3D('Z', (0, 0, uZ), xytext=(0, 0), textcoords=('offset points'), color = 'xkcd:eggplant', weight="bold")



    setattr(Axes3D, 'axesSetup', _axesSetup )
    # setattr create 'axesSetup' attribute for class Axes3D if 'axesSetup' is not found
    # an object of class Axes3D is the axes projected in 3D




    It used to work, but now it shows nothing. Some other post already figured out it's due to Matplotlib's upgrade. Could someone help me to modify my code to make it work?

    Continue reading...

Compartilhe esta Página