"管" Python中的箭头

时间:2018-02-02 16:35:51

标签: python matplotlib 3d visualization

我正在寻找一种用python绘制一些(O(1))3D箭头的方法,这些箭头是"正确的3D",我的意思是Mathematica产生的东西,即箭杆看起来像一根管子。

我在matplotlib文档中找不到任何内容,但肯定有办法吗?

3D Arrow as generated by mathematica

1 个答案:

答案 0 :(得分:2)

您可以从2D中定义的某个路径创建旋转实体以创建3D箭头。以下代码将其包装到一个函数中,该函数允许指定一些箭头参数。这允许创建要使用的路径。然后围绕z轴旋转,创建3D箭头。为了允许箭头在空间中的任意取向,可以围绕x轴旋转完整箭头,然后绕z轴旋转(theta_xtheta_z)。最后,使用plot_surface绘制箭头。请注意,箭头所在的轴应具有相同的宽高比,这样箭头不会倾斜。

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D


def arrow3d(ax, length=1, width=0.05, head=0.2, headwidth=2,
                theta_x=0, theta_z=0, offset=(0,0,0), **kw):
    w = width
    h = head
    hw = headwidth
    theta_x = np.deg2rad(theta_x)
    theta_z = np.deg2rad(theta_z)

    a = [[0,0],[w,0],[w,(1-h)*length],[hw*w,(1-h)*length],[0,length]]
    a = np.array(a)

    r, theta = np.meshgrid(a[:,0], np.linspace(0,2*np.pi,30))
    z = np.tile(a[:,1],r.shape[0]).reshape(r.shape)
    x = r*np.sin(theta)
    y = r*np.cos(theta)

    rot_x = np.array([[1,0,0],[0,np.cos(theta_x),-np.sin(theta_x) ],
                      [0,np.sin(theta_x) ,np.cos(theta_x) ]])
    rot_z = np.array([[np.cos(theta_z),-np.sin(theta_z),0 ],
                      [np.sin(theta_z) ,np.cos(theta_z),0 ],[0,0,1]])

    b1 = np.dot(rot_x, np.c_[x.flatten(),y.flatten(),z.flatten()].T)
    b2 = np.dot(rot_z, b1)
    b2 = b2.T+np.array(offset)
    x = b2[:,0].reshape(r.shape); 
    y = b2[:,1].reshape(r.shape); 
    z = b2[:,2].reshape(r.shape); 
    ax.plot_surface(x,y,z, **kw)

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

arrow3d(ax)

arrow3d(ax, length=2, width=0.02, head=0.1, headwidth=1.5, offset=[1,1,0], 
        theta_x=40,  color="crimson")

arrow3d(ax, length=1.4, width=0.03, head=0.15, headwidth=1.8, offset=[1,0.1,0], 
        theta_x=-60, theta_z = 60,  color="limegreen")

ax.set_xlim(0,1)
ax.set_ylim(0,1)
ax.set_zlim(0,1)
plt.show()

enter image description here