在Matplotlib动画中更新曲面图上的z数据

8

我希望创建一个面板动画。该动画具有固定的x和y数据(每个维度为1到64),并通过np数组读取z信息。代码概述如下:

import numpy as np
import matplotlib.pyplot as plt 
import matplotlib.animation as animation

def update_plot(frame_number, zarray, plot):
    #plot.set_3d_properties(zarray[:,:,frame_number])
    ax.collections.clear()
    plot = ax.plot_surface(x, y, zarray[:,:,frame_number], color='0.75')

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

N = 64
x = np.arange(N+1)
y = np.arange(N+1)
x, y = np.meshgrid(x, y)
zarray = np.zeros((N+1, N+1, nmax+1))

for i in range(nmax):
  #Generate the data in array z
  #store data into zarray
  #zarray[:,:,i] = np.copy(z)

plot = ax.plot_surface(x, y, zarray[:,:,0], color='0.75')

animate = animation.FuncAnimation(fig, update_plot, 25, fargs=(zarray, plot))
plt.show()

所以代码生成z数据并在FuncAnimation中更新绘图。然而这很慢,我怀疑是由于每个循环都重新绘制了绘图。
我尝试了该函数。
ax.set_3d_properties(zarray[:,:,frame_number])

但是它出现了错误。
AttributeError: 'Axes3DSubplot' object has no attribute 'set_3d_properties'

如何在不重新绘制整个图形的情况下仅更新Z方向上的数据?(或通过其他方式增加绘图过程的帧率)

2个回答

10
调用 plot_surface 时,实际上有很多工作在后台进行。如果尝试为 Poly3DCollection 设置新数据,则需要复制所有这些工作。可能可以通过一种比 matplotlib 代码更高效的方式来完成此操作。其想法是从网格点计算出所有顶点,并直接将它们提供给 Poly3DCollection._vec
但是,动画的速度主要由执行 3D 到 2D 投影所需的时间和绘制实际图形的时间决定。因此,在绘制速度方面,以上方法帮助不大。
最后,您可以简单地坚持当前的表面动画方式,即删除先前的图形并绘制新图形。然而,在表面上使用较少的点将显著增加绘制速度。
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D 
import matplotlib.animation as animation

def update_plot(frame_number, zarray, plot):
    plot[0].remove()
    plot[0] = ax.plot_surface(x, y, zarray[:,:,frame_number], cmap="magma")

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

N = 14
nmax=20
x = np.linspace(-4,4,N+1)
x, y = np.meshgrid(x, x)
zarray = np.zeros((N+1, N+1, nmax))

f = lambda x,y,sig : 1/np.sqrt(sig)*np.exp(-(x**2+y**2)/sig**2)

for i in range(nmax):
    zarray[:,:,i] = f(x,y,1.5+np.sin(i*2*np.pi/nmax))

plot = [ax.plot_surface(x, y, zarray[:,:,0], color='0.75', rstride=1, cstride=1)]
ax.set_zlim(0,1.5)
animate = animation.FuncAnimation(fig, update_plot, nmax, fargs=(zarray, plot))
plt.show()

请注意,动画本身的速度是由FuncAnimationinterval 参数确定的。在上面的例子中,没有指定它,因此默认为200毫秒。根据数据,您仍然可以在遇到帧延迟问题之前减小此值,例如尝试40毫秒,并根据您的需求进行调整。
animate = animation.FuncAnimation(fig, update_plot, ..., interval=40,  ...)

0

set_3d_properties()Poly3DCollection 类的一个函数,而不是 Axes3DSubplot

你应该运行

plot.set_3d_properties(zarray[:,:,frame_number])

正如你在更新函数中所注释的那样,而不是

ax.set_3d_properties(zarray[:,:,frame_number])

我不确定这是否能解决你的问题,因为函数set_3d_properties没有附带文档。也许你可以尝试使用plot.set_verts()


2
Poly3DCollection.set_3d_properties 不需要任何参数,不能用于更新数据。可以使用 Poly3DCollection.set_verts(),但您需要手动从数据点计算顶点。虽然这是可能的,但我回答中的论点是它不会显著增加更新速度,因此不值得努力。 - ImportanceOfBeingErnest
感谢您提供的详细信息。您的回答非常有启发性,您总是如此丰富多彩! - Diziet Asahi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接