【问题标题】:Updating a pyplot 3d scatter plot in a loop, grid lines overlap points在循环中更新 pyplot 3d 散点图,网格线重叠点
【发布时间】:2014-02-06 22:34:32
【问题描述】:

我在循环的每次迭代中更新一个 3d 散点图。重新绘制绘图时,网格线“穿过”或“覆盖”这些点,这使我的数据更难以可视化。如果我构建一个 3d 图(没有循环更新),这不会发生。下面的代码演示了最简单的情况:

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

X = np.random.rand(100, 3)*10
Y = np.random.rand(100, 3)*5

plt.ion()

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(X[:, 0], X[:, 1], X[:, 2])
plt.draw()

for i in range(0, 20):
    time.sleep(3)   #make changes more apparent/easy to see

    Y = np.random.rand(100, 3)*5
    ax.cla()    
    ax.scatter(Y[:, 0], Y[:, 1], Y[:, 2])
    plt.draw()

还有其他人遇到过这个问题吗?

【问题讨论】:

  • 我没有得到 pb 是什么,你能澄清一下吗?你想做什么?
  • 如果您在循环中更新 matplotlib3d 轴,例如当使用 Funcanimation 时,通常位于背景中的网格会覆盖绘制的表面。我更新了问题。
  • 但编辑需要经过同行评审

标签: python loops matplotlib scatter


【解决方案1】:

看起来MaxNoe 是正确的,因为问题出在ax.cla()plt.cla() 调用中。实际上,它似乎类似于known issue

然后有一个问题,因为清除轴方法在 3D 绘图中不起作用,并且对于 3D 散点图,没有干净的方法来更改数据点的坐标(a la sc.set_data(new_values)),正如 @987654323 所讨论的那样@(我没有找到任何更新的内容)。

然而,在邮件列表中,Ben Roon 指出了一个可能对您也有用的解决方法。

解决方法:

您需要在scatter 函数返回的Line3DCollectionobject 的内部_ofsets3d 变量中设置数据点的新坐标。

改编后的示例如下所示:

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

X = np.random.rand(100, 3)*10
Y = np.random.rand(100, 3)*5

plt.ion()

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
sc = ax.scatter(X[:, 0], X[:, 1], X[:, 2])
fig.show()

for i in range(0, 20):
    plt.pause(1)

    Y = np.random.rand(100, 3)*5

    sc._offsets3d = (Y[:,0], Y[:,1], Y[:,2])
    plt.draw()

【讨论】:

  • 如果有人想知道,也可以在循环的每次迭代中更改要绘制的元素数量:Y = np.random.rand(np.random.randint(200), 3)*5 工作正常
【解决方案2】:

我可以把它缩小到使用 cla():

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

x, y = np.meshgrid(np.linspace(-2,2), np.linspace(-2,2))

ax.plot_surface(x,y, x**2+y**2)
fig.savefig("fig_a.png")

ax.cla()
ax.plot_surface(x,y, x**2+y**2)

fig.savefig("fig_b.png")

这些是结果图:

【讨论】:

    【解决方案3】:

    这只是一种解决方法,因为它不能解决MaxNoe 指出的ax.cla() 的问题。它也不是特别漂亮,因为它清除了整个图形,但是它完成了所需的任务:

    import numpy as np
    import matplotlib.pyplot as plt
    from mpl_toolkits.mplot3d import Axes3D
    fig1 = plt.figure()
    ax1 = fig1.add_subplot(111, projection='3d')
    
    x, y = np.meshgrid(np.linspace(-2,2), np.linspace(-2,2))
    
    ax1.plot_surface(x,y, x**2+y**2)
    fig1.savefig("fig_a.png")
    
    fig1.clf()
    ax1 = fig1.add_subplot(111, projection='3d')
    ax1.plot_surface(x,y, x**2+y**2)
    
    fig1.savefig("fig_b.png")
    

    【讨论】:

    • 嗯,问题是你需要再次渲染整个图形,生成轴,然后绘制数据。更新图比直接修改当前散点图的数据要长三倍左右……(我的电脑差不多0.1s,已经很明显了)
    • @mgab 我完全同意你的看法。这不是一个好的解决方案。但正如ax.cla() 所显示的那样 - 至少现在 - 不是所需的行为。使用 fig.clf() 需要很长时间,但至少显示了所需的行为。
    【解决方案4】:

    我建议使用ax = fig.gca(projection='3d') 而不是ax = fig.add_subplot(111, projection='3d')

    【讨论】:

    • 这两者之间到底有什么区别?
    • 同样的结果,网格在绘制的对象上方。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-02-20
    • 1970-01-01
    • 2016-01-14
    • 2016-06-19
    • 1970-01-01
    • 1970-01-01
    • 2016-07-31
    相关资源
    最近更新 更多