Python &引用;设置“UVC”;matplotlib中三维箭图的等效

Python &引用;设置“UVC”;matplotlib中三维箭图的等效,python,matplotlib,Python,Matplotlib,要更新常规二维箭图,可以使用.set_UVC()直接设置x和y数据 与箭袋等效的3D是Axes3D.quiver(),但它似乎没有与.set\UVC()等效的3D。如何更新数据?段似乎包含来自箭袋箭头的数据,但我看不到输入数据和段之间的关联 我可以删除箭袋图,然后重新绘制一个新的箭袋图,但是这会影响性能,我想知道是否有直接设置数据的方法。如果您查看Line3DCollection代码,您会发现LineCollection类中没有太多方法过载。对您来说,重要的一点是set_segments(),如

要更新常规二维箭图,可以使用
.set_UVC()
直接设置
x
y
数据

与箭袋等效的3D是
Axes3D.quiver()
,但它似乎没有与
.set\UVC()
等效的3D。如何更新数据?
似乎包含来自箭袋箭头的数据,但我看不到输入数据和段之间的关联


我可以删除箭袋图,然后重新绘制一个新的箭袋图,但是这会影响性能,我想知道是否有直接设置数据的方法。

如果您查看
Line3DCollection
代码,您会发现
LineCollection
类中没有太多方法过载。对您来说,重要的一点是
set_segments()
,如下所示:

def set_segments(self, segments):
    '''                                                                                                                
    Set 3D segments                                                                                                    
    '''
    self._segments3d = np.asanyarray(segments)
    LineCollection.set_segments(self, [])
因此,当调用
set_segments()
时,这些段实际上存储在
self.\u segments3d
中,并使用空列表调用
LineCollection
set_segments()
方法
Line3DCollection
然后在重载的
draw()
方法中处理自己的段列表。有两件事需要注意:

  • 即使您遵循matplotlib示例并使用
    numpy.meshgrids
    定义箭图坐标,在
    \u段3d
    中,坐标存储在形状
    (N,2,3)
    的数组中,其中N是点的数量,其内容基本上是
    [[x0,y0,z0],[x1,y1,z1],[u1,w1],…][/code>,,因此,您可能必须对数据进行操作以适应该格式
  • 显然,您不能将新值直接分配给
    \u段3d
    。至少对我来说,这导致图形没有正确更新——你必须通过
    set\u segments()
    。但是,如果您只想更改某些坐标,可以通过读取
    \u segments3d
    来访问以前的值
  • 这里还有一些任意的例子,我用它来测试我刚才解释的所有东西:

    from matplotlib import pyplot as plt
    from mpl_toolkits.mplot3d import axes3d
    from matplotlib.animation import FuncAnimation
    import numpy as np
    
    fig = plt.figure()
    ax = fig.gca(projection='3d')
    
    num_frames = 50
    theta = np.linspace(0,2*np.pi, 10, endpoint=False)
    r = np.arange(1,2.1)
    z = np.arange(-2,2.1,1)
    
    
    def compute_segs(i):
        offset = 2*i*np.pi/num_frames
        theta2,r2, z2 = np.meshgrid(theta+offset,r,z)
    
        x = r2*np.cos(theta2)
        y = r2*np.sin(theta2)
    
        u = x+0.2*np.cos(4*theta2)
        v = y
        w = z2+0.2*np.sign(z2)*np.sin(4*theta2)
    
        return x,y,z2,u,v,w
    
    
    segs = compute_segs(0)
    cols = ['b' for x in segs[0].ravel()]
    cols[0] = 'r'
    quivers = ax.quiver(*segs, length=0.1, colors = cols, normalize=True)
    
    
    ax.set_xlim([-3,3])
    ax.set_ylim([-3,3])
    ax.set_zlim([-3,3])
    def animate(i):
    
        segs = np.array(compute_segs(i)).reshape(6,-1)
    
        new_segs = [[[x,y,z],[u,v,w]] for x,y,z,u,v,w in zip(*segs.tolist())]
        quivers.set_segments(new_segs)
        return quivers
    
    
    ani = FuncAnimation(fig, animate, frames = num_frames, interval = 30, blit=False)
    ani.save('update_3d_quiver.gif', writer='imagemagick')
    
    plt.show()
    
    …结果如下所示:

    def set_segments(self, segments):
        '''                                                                                                                
        Set 3D segments                                                                                                    
        '''
        self._segments3d = np.asanyarray(segments)
        LineCollection.set_segments(self, [])
    


    希望这有帮助。

    要详细说明我接受的Thomas Kühn的答案,如果您有网格点和要转换为段的箭袋数据,可以使用以下函数

    def quiver_data_to_segments(X, Y, Z, u, v, w, length=1):
        segments = (X, Y, Z, X+v*length, Y+u*length, Z+w*length)
        segments = np.array(segments).reshape(6,-1)
        return [[[x, y, z], [u, v, w]] for x, y, z, u, v, w in zip(*list(segments))]
    
    然后,您可以使用输出更新绘图段,这种方式还允许您使用长度指定箭头的归一化长度,通常最好将其设置为输入数据平均值或最大值的倍数(
    np.sqrt(vv**2+uu**2+ww**2)


    我刚刚意识到我的例子只对了一半——过一会儿我会发布一篇编辑文章。