“set_UVC”相当于 matplotlib 中的 3D 颤动图

Ace*_*wis 5 python matplotlib

要更新常规 2D 箭袋图,您可以使用.set_UVC()直接设置xy数据。

与箭袋等效的 3D 是Axes3D.quiver(),但这似乎没有等效的.set_UVC()。数据如何更新?确实segments似乎包含来自箭袋箭头的数据,但是我不知道输入数据和段是如何关联的。

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

Tho*_*ühn 5

如果您查看代码,您会发现该类中并没有重载Line3DCollection太多方法。LineCollection对你来说最重要的是set_segments(),它看起来像这样:

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

因此,当set_segments()调用 时,段实际上存储在 中self._segments3d,并且使用空列表调用 的方法LineCollection。then 在重载方法中处理自己的段列表。需要注意两点:set_segments()Line3DCollectiondraw()

  1. 即使您遵循 matplotlib 示例并使用numpy.meshgrids它来定义箭袋坐标,_segments3d坐标也存储在 shape 数组中(N,2,3),其中 N 是点的数量,其内容基本上是[[[x0,y0,z0],[u0,v0,w0]],[[x1,y1,z1],[u1,v1,w1]],...],所以您可能必须操作数据以适应该情况格式。
  2. 显然您不能将新值直接分配给_segments3d. 至少对我来说,这导致数字无法正确更新 - 你必须经历set_segments()。但是,如果您只想更改某些坐标,则可以通过读取 来访问以前的值。_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()
Run Code Online (Sandbox Code Playgroud)

...结果如下所示:

上述代码的结果

希望这可以帮助。


Ace*_*wis 5

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

\n\n
def quiver_data_to_segments(X, Y, Z, u, v, w, length=1):\n    segments = (X, Y, Z, X+v*length, Y+u*length, Z+w*length)\n    segments = np.array(segments).reshape(6,-1)\n    return [[[x, y, z], [u, v, w]] for x, y, z, u, v, w in zip(*list(segments))]\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后,您可以使用输出更新绘图的各个部分,这种方式还允许您使用长度来指定箭头的归一化长度,通常最好将其设置为输入数据的平均值或最大值的倍数( np.sqrt(vv**2 + uu**2 + ww**2))。

\n\n
segments = quiver_data_to_segments(X, Y, Z, uu, vv, ww, length=5)\nquiver_plot.set_segments(segments)\n
Run Code Online (Sandbox Code Playgroud)\n