在 matplotlib 的 3d 图中将箭头放在矢量上

我绘制了一些 3D 数据的特征向量,想知道目前(已经)是否有一种方法可以将箭头放在线上?如果有人给我小费,那就太棒了。在 matplotlib 的 3d 图中将箭头放在矢量上

 import numpy as np

from matplotlib import pyplot as plt

from mpl_toolkits.mplot3d import Axes3D

####################################################

# This part is just for reference if

# you are interested where the data is

# coming from

# The plot is at the bottom

#####################################################

# Generate some example data

mu_vec1 = np.array([0,0,0])

cov_mat1 = np.array([[1,0,0],[0,1,0],[0,0,1]])

class1_sample = np.random.multivariate_normal(mu_vec1, cov_mat1, 20)

mu_vec2 = np.array([1,1,1])

cov_mat2 = np.array([[1,0,0],[0,1,0],[0,0,1]])

class2_sample = np.random.multivariate_normal(mu_vec2, cov_mat2, 20)

# concatenate data for PCA

samples = np.concatenate((class1_sample, class2_sample), axis=0)

# mean values

mean_x = mean(samples[:,0])

mean_y = mean(samples[:,1])

mean_z = mean(samples[:,2])

#eigenvectors and eigenvalues

eig_val, eig_vec = np.linalg.eig(cov_mat)

################################

#plotting eigenvectors

################################

fig = plt.figure(figsize=(15,15))

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

ax.plot(samples[:,0], samples[:,1], samples[:,2], 'o', markersize=10, color='green', alpha=0.2)

ax.plot([mean_x], [mean_y], [mean_z], 'o', markersize=10, color='red', alpha=0.5)

for v in eig_vec:

ax.plot([mean_x, v[0]], [mean_y, v[1]], [mean_z, v[2]], color='red', alpha=0.8, lw=3)

ax.set_xlabel('x_values')

ax.set_ylabel('y_values')

ax.set_zlabel('z_values')

plt.title('Eigenvectors')

plt.draw()

plt.show()

原文由 user2489252 发布,翻译遵循 CC BY-SA 4.0 许可协议


回答:

要向 3D 图添加箭头补丁,简单的解决方案是使用 FancyArrowPatch 中定义的类 /matplotlib/patches.py 。但是,它仅适用于 2D 图(在撰写本文时),因为它的 posAposB 应该是长度为 2 的元组。

因此我们创建一个新的箭头补丁类,命名为 Arrow3D ,它继承自 FancyArrowPatch 。我们唯一需要覆盖它的 posAposB 。为此,我们启动 Arrow3dposB(0,0)posA The 3D coordinates xs, ys, zs was then projected from 3D to 2D using proj3d.proj_transform() , and the resultant 2D coordinates get assigned to posA and posB using .set_position() 方法,替换 (0,0) s。这样我们就可以让 3D 箭头起作用了。

投影步骤进入 .draw 方法,它覆盖 FancyArrowPatch 对象的 .draw 方法。

这可能看起来像黑客攻击。然而, mplot3d 目前仅通过提供 3D-2D 投影提供(再次,仅)简单的 3D 绘图能力,并且基本上以 2D 进行所有绘图,这不是真正的 3D。

 import numpy as np

from numpy import *

from matplotlib import pyplot as plt

from mpl_toolkits.mplot3d import Axes3D

from matplotlib.patches import FancyArrowPatch

from mpl_toolkits.mplot3d import proj3d

class Arrow3D(FancyArrowPatch):

def __init__(self, xs, ys, zs, *args, **kwargs):

FancyArrowPatch.__init__(self, (0,0), (0,0), *args, **kwargs)

self._verts3d = xs, ys, zs

def draw(self, renderer):

xs3d, ys3d, zs3d = self._verts3d

xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, renderer.M)

self.set_positions((xs[0],ys[0]),(xs[1],ys[1]))

FancyArrowPatch.draw(self, renderer)

####################################################

# This part is just for reference if

# you are interested where the data is

# coming from

# The plot is at the bottom

#####################################################

# Generate some example data

mu_vec1 = np.array([0,0,0])

cov_mat1 = np.array([[1,0,0],[0,1,0],[0,0,1]])

class1_sample = np.random.multivariate_normal(mu_vec1, cov_mat1, 20)

mu_vec2 = np.array([1,1,1])

cov_mat2 = np.array([[1,0,0],[0,1,0],[0,0,1]])

class2_sample = np.random.multivariate_normal(mu_vec2, cov_mat2, 20)

实际绘图。请注意,我们只需要更改一行代码,即添加一个新的箭头艺术家:

 # concatenate data for PCA

samples = np.concatenate((class1_sample, class2_sample), axis=0)

# mean values

mean_x = mean(samples[:,0])

mean_y = mean(samples[:,1])

mean_z = mean(samples[:,2])

#eigenvectors and eigenvalues

eig_val, eig_vec = np.linalg.eig(cov_mat1)

################################

#plotting eigenvectors

################################

fig = plt.figure(figsize=(15,15))

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

ax.plot(samples[:,0], samples[:,1], samples[:,2], 'o', markersize=10, color='g', alpha=0.2)

ax.plot([mean_x], [mean_y], [mean_z], 'o', markersize=10, color='red', alpha=0.5)

for v in eig_vec:

#ax.plot([mean_x,v[0]], [mean_y,v[1]], [mean_z,v[2]], color='red', alpha=0.8, lw=3)

#I will replace this line with:

a = Arrow3D([mean_x, v[0]], [mean_y, v[1]],

[mean_z, v[2]], mutation_scale=20,

lw=3, arrowstyle="-|>", color="r")

ax.add_artist(a)

ax.set_xlabel('x_values')

ax.set_ylabel('y_values')

ax.set_zlabel('z_values')

plt.title('Eigenvectors')

plt.draw()

plt.show()

在 matplotlib 的 3d 图中将箭头放在矢量上

请查看启发此问题的 这篇文章,了解更多详细信息。

原文由 CT Zhu 发布,翻译遵循 CC BY-SA 4.0 许可协议


回答:

另一种选择:您还可以使用 plt.quiver 函数,它允许您非常轻松地生成箭头向量,而无需任何额外的导入或类。

要复制您的示例,您将替换:

 for v in eig_vec:

ax.plot([mean_x, v[0]], [mean_y, v[1]], [mean_z, v[2]], color='red', alpha=0.8, lw=3)

和:

 for v in eig_vec:

ax.quiver(

mean_x, mean_y, mean_z, # <-- starting point of vector

v[0] - mean_x, v[1] - mean_y, v[2] - mean_z, # <-- directions of vector

color = 'red', alpha = .8, lw = 3,

)

原文由 Matt 发布,翻译遵循 CC BY-SA 4.0 许可协议

以上是 在 matplotlib 的 3d 图中将箭头放在矢量上 的全部内容, 来源链接: utcz.com/p/938712.html

回到顶部