【问题标题】:Pyplot 3d scatter: points at the back overlap points at the frontPyplot 3d scatter:后面的点在前面的重叠点
【发布时间】:2016-01-14 01:35:39
【问题描述】:

我正在使用 matplotlib 准备 3d 图,并且我对多个数据集的行为非常奇怪。我有两个数据集,它们基本上描述了 3d 中的两个壳:一个内壳和一个外壳。要在 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 情节”的目的。有没有人知道为什么会发生这种情况以及如何解决? 非常感谢!

【问题讨论】:

  • 我在想,如果您决定手动进行操作,我有一个如何操作的想法。您必须选择一个点作为您的视角(相机所在的位置)和相机指向的方向。然后从这里有一个公式可以确定该点在该方向上的距离(使用点到平面的距离公式),您可以将其用于您的 zorder 参数。如果您对此感到好奇,请告诉我,我们可以试一试。但说实话,您可能想为这个项目寻找其他工具(带有真正的 3d 引擎)。

标签: python matplotlib 3d scatter


【解决方案1】:

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

这与 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 有一些基本方法可以确保在使用着色算法时首先显示前点,但我不确定。

【讨论】:

    【解决方案2】:

    非常感谢您的解释 :) 我认为确实可能是这样的。但是我忘了在我的问题中说,无论 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 开始的渐变变得更加困难......

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-17
      • 2020-11-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多