Pyplot 3d 散点图:后面的点与前面的重叠点

Pyplot 3d scatter: points at the back overlap points at the front

我正在使用 matplotlib 准备 3d 图,并且我对多个数据集的行为非常奇怪。我有两个数据集,基本上描述了 3d 中的两个 shell:一个内部 shell 和一个外部 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])

(轴的顺序只是为了透视目的)。但是,当我保存图形时,我没有得到两个 shells:

我把一层叠在另一层上,明显在后面的点出现在前面。你可以在图片上看到一些应该在内部 shell 后面的外部 shell 点被绘制在内部 shell 前面。这真的很烦人,因为它不追求 "plot in 3d" 的目的。有没有人知道为什么会发生这种情况以及如何解决? 非常感谢!

我知道这不是您问题的解决方案,但也许可以解释为什么会这样。

这与 Matplotlib 实际上没有 3D 引擎有关。 Mplot3D 获取你的点并将它们投影到 2D 图上的样子(对于每个对象),然后 Matplotlib 一次绘制每个对象; Matplotlib 是一个 2D 绘图框架,而 Mplot3D 是一种小技巧,无需为 Matplotlib 编写成熟的 3D 引擎即可获得一些 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 有一些基本方法可以确保前面的点首先显示,我相信,当它使用着色算法时,但我不确定。

非常感谢您的解释 :) 我认为它可能确实是这样的。但是我忘了在我的问题中说,无论 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') 

然后我得到了下面的图片:

这对我有用。但是,我知道,如果我改变视角,红色的 shell 会出现在黑色的上方。我后来发现的一个问题是 .plot 函数没有 vmin 和 vmax 参数(与 .scatter 一样),这使得将颜色定义为从 vmin 和 vmax 开始的渐变变得更加困难...