我正在使用matplotlib准备三维图,我对多个数据集有一个非常奇怪的行为。我有两个数据集,基本上描述了3d中的两个shell:一个内壳和一个外壳。要在3d中绘制它们,我会这样做:
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(outer_z[:n], outer_x[:n], outer_y[:n], c='black', marker='.', lw=0)
ax.scatter(inner_z[:n], inner_x[:n], inner_y[:n], c='red', marker='.', lw=0)
ax.set_xlabel("Z")
ax.set_ylabel("X")
ax.set_zlabel("Y")
ax.set_xlim([-5,5])
ax.set_ylim([5,-5])
ax.set_zlim([-5,5])
(轴的顺序仅用于透视目的)。但是,当我保存图形时,我没有得到两个炮弹:
我在另一层上面得到一层,后面明显的点出现在前面。你可以在图片上看到外壳后面应该在内壳后面的一些点被绘制在内壳的前面。这真的很烦人,因为它不追求“3D中的情节”的目的。有没有人知道为什么会发生这种情况以及如何解决这个问题? 非常感谢!
答案 0 :(得分:2)
我知道这不是解决问题的方法,但也许可以解释为什么它的行为方式如此。
这与Matplotlib实际上没有3D引擎的事实有关。 Mplot3D获取你的点并将它们投影到2D绘图上(对于每个对象)的样子,然后Matplotlib一次绘制一个对象; Matplotlib是一个2D绘图框架,Mplot3D可以让一些3D功能正常工作,而无需为Matplotlib编写成熟的3D引擎。
这意味着您绘制不同绘图的顺序(在本例中为红色和黑色点)很重要,如果您在红点后绘制黑点,它们将显示在红点前面,无论他们的位置如何。
让我用另一个例子说明这一点。
theta = np.linspace(0, 2*np.pi, 100, endpoint=True)
helix_x = np.cos(3*theta)
helix_y = np.sin(3*theta)
helix_z = theta
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
line_x = np.zeros(100)
line_y = np.zeros(100)
ax.plot(line_x, line_y, theta, lw='3', color='r')
ax.plot(helix_x, helix_y, helix_z, lw='2', color='k')
ax.set_xlabel("Z")
ax.set_ylabel("X")
ax.set_zlabel("Y")
ax.set_xlim([-1.5,1.5])
ax.set_ylim([-1.5,1.5])
ax.set_zlim([0,2*np.pi])
但从顶视图可以看出该线在螺旋线内:
但是,如果您交换绘制这些线的顺序:
ax.plot(line_x, line_y, theta, lw='3', color='r')
ax.plot(helix_x, helix_y, helix_z, lw='2', color='k')
然后,您会看到螺旋后绘制的线:
最终,这意味着您必须手动确定哪些点将位于其他点之前。然后,您可以使用zorder参数来确定哪些对象将位于其他对象的前面。但是你必须为每个视角(角度,高度)做到这一点。在这种情况下,您可能需要将内部线分解为“infront_of_helix”和“behind_helix”部分,然后分别在螺旋线的前面和后面绘制它们。
我希望有人能够对这个问题进行更详细的阐述,因为我自己对这个话题很感兴趣。我知道mplot3d有一些基本方法可以确保前点显示,我相信,当它使用着色算法时,我并不完全确定。
答案 1 :(得分:1)
非常感谢你的解释:)我认为它确实可能是这样的。但我忘了在我的问题中说,无论ax.scatter命令的顺序是什么都发生了,这很奇怪。在读到你的答案之前我发现了ax.plot命令不会发生这种情况。因此,我换了:
ax.scatter(outer_z[:n], outer_x[:n], outer_y[:n], c='black', marker='.', lw=0)
ax.scatter(inner_z[:n], inner_x[:n], inner_y[:n], c='red', marker='.', lw=0)
通过
ax.plot(outer_z[:n], outer_x[:n], outer_y[:n], '.', markersize=1, color='black')
ax.plot(inner_z[:n], inner_x[:n], inner_y[:n], '.', markersize=1, color='red')
我得到了以下图片:
对我有用。但是,我知道,如果我改变观点,我会将红色外壳出现在黑色外观之上。我后来发现的一个问题是.plot函数没有vmin和vmax参数(作为.scatter一个),这使得将颜色定义为以vmin和vmax开始的渐变更难...