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

Skip to content

Documentation and bug report: mplot3d and blitting #27830

Closed
@Fcp-GitHub

Description

@Fcp-GitHub

Bug summary

Summary

Problem with 3d animation using FuncAnimation and the mplot3d toolkit. Maybe this problem comes from not enough clarifications in the documentation. Following this it is presented a simplified version of the program that led me to these conclusions.

Explanation

Looking through the documentation regarding animation and blitting, it is possible to see two different approaches:

  • The first one (see here) is presented at the first explanation page about creating animations with the animation module. Here it is explained that in the function passed to FuncAnimation there has to be some method that updates the data in each artist in order to generate the new frame. It is written that "the update function uses the set_* function for different artists to modify the data".
  • However, the second approach (presented here, where blitting is actually explained) tells the user to use the draw_artist() method in order to update/redraw efficiently the artists in the function of the render loop. I haven't found many low-level details (except some look directly at the source code) about the functioning of FuncAnimation or plt.show(), so I couldn't make real assumptions about their involvement in this.

Mixing the informations, I have encountered many problems that I will try to replicate and explain in the following code.

Code for reproduction

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.art3d import Line3D
from matplotlib.animation import FuncAnimation

fig = plt.figure()
ax = fig.add_subplot(projection='3d', xlim=(0,100), ylim=(0,100), zlim=(0,100))

line = Line3D( [0], [0], [0], marker="o", markersize=15, color='r', animated=True)

def update(t):
    line.set_data_3d([t],[t],[t])
    ax.draw_artist(line)
    
    return line,

anim = FuncAnimation(fig=fig, func=update, frames=None, blit=True, cache_frame_data=False)

plt.show()

Actual outcome

File "C:\Users\user\Desktop...\axes3d_issue.py", line 13, in update
ax.draw_artist(line)
File "C:\Users\user\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\LocalCache\local-packages\Python312\site-packages\matplotlib\axes_base.py", line 3080, in draw_artist
a.draw(self.figure.canvas.get_renderer())
File "C:\Users\user\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\LocalCache\local-packages\Python312\site-packages\matplotlib\artist.py", line 72, in draw_wrapper
return draw(artist, renderer)
^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\user\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\LocalCache\local-packages\Python312\site-packages\mpl_toolkits\mplot3d\art3d.py", line 270, in draw
xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, self.axes.M)
^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'M'

Expected outcome

The rendering of the image.

Additional information

Some considerations:

  1. Maybe the draw_artist() method should be used in combination with plt.pause() or by API developers, but neither is specified in the documentation. Removing the ax.draw_artist(line) (following thus the first approach described at the beginning) is indeed a solution to the problem.
  2. Using Visual Studio Code Data inspection debug tool along with debugpy, I've noticed that in the update() function the Line3D artist seems to lose all the references to the parent classes Axes3D and Figure, hence some error messages. However, trying to add something like line.axes = ax leads directly to an exception raised due to the next problem.
  3. It seems that without calling the 'Axes3D.draw()' method first, the projection matrix variable M of the same class is never updated from None to some value. Actually, calling the Axes3D.get_proj() method for M and computing the inverse matrix also for the invM attribute seems to work. This appears to be a flaw in every case, but maybe it corroborates the hypothesis of some kind of "reservedness" of the method for some special cases.
    If this is the case, it is not specified neither in the already cited documentation, neither in the (quite short, for some reason) mplot3d documentation (see here).

I think the documentation about this topic should be a bit clearer. Some more explanation about the inner working of some ubiquitous functions like plt.show() or the clear methods, another set of functions that is presentend unclearly, could help users understand and resolve their problems, along with using them more consciously.

Operating system

Microsoft Windows 11 Home

Matplotlib Version

3.8.2

Matplotlib Backend

TkAgg

Python version

3.12.2

Jupyter version

No response

Installation

pip

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