【问题标题】:Updating z data on a surface_plot in Matplotlib animation在 Matplotlib 动画中更新 surface_plot 上的 z 数据
【发布时间】:2017-08-16 11:16:47
【问题描述】:

我希望在曲面图中创建动画。动画有固定的 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 方向的数据? (或者以其他方式增加绘图过程的帧率)

【问题讨论】:

    标签: python matplotlib


    【解决方案1】:

    当调用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()
    

    请注意,动画本身的速度是由interval 参数FuncAnimation 决定的。在上面没有指定它,因此默认为 200 毫秒。根据数据,您仍然可以在遇到滞后帧问题之前减小此值,例如尝试 40 毫秒,然后根据您的需要进行调整。

    animate = animation.FuncAnimation(fig, update_plot, ..., interval=40,  ...)
    

    【讨论】:

      【解决方案2】:

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

      你应该跑

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

      正如您在更新功能 BTW 中评论的那样,而不是

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

      我不知道这是否能解决您的问题,但我不确定,因为函数 set_3d_properties 没有附加文档。我想知道你是否最好改用plot.set_verts()

      【讨论】:

      • Poly3DCollection.set_3d_properties 不需要任何参数,也不能用于更新数据。 Poly3DCollection.set_verts()可以用,可以。然后,您将需要手动计算数据点的顶点。虽然这是可能的,但我的回答中的论点是它不会显着提高更新速度,因此不值得付出努力。
      • 感谢您的精确。您的回答信息量很大,您的信息总是如此丰富!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-09-12
      • 1970-01-01
      • 2023-03-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多