Matplotlib 3D散点图重绘后颜色丢失

14 投票
1 回答
4272 浏览
提问于 2025-04-17 10:53

这个问题相关,我想要一个3D散点图,每个点都有指定的颜色。问题中提供的例子在我的系统上可以运行,但在第一次重新绘制后(比如保存图像或者旋转图像),颜色似乎就消失了,也就是说,所有的点都变成了蓝色,只有深度信息还在。请看下面修改过的例子。

我的系统是Python 2.6.7,安装了matplotlib 1.1.0,使用的是macports,运行在mac 10.8.0上。我使用的是MacOSX后端。

有没有人知道怎么解决这个问题?

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

# Create Map
cm = plt.get_cmap("RdYlGn")

x = np.random.rand(30)
y = np.random.rand(30)
z = np.random.rand(30)

col = np.arange(30)

fig = plt.figure()
ax3D = fig.add_subplot(111, projection='3d')
ax3D.scatter(x, y, z, s=30, c=col, marker='o', cmap=cm)

plt.savefig('image1.png')
plt.savefig('image2.png')

这是我得到的两张图片:

第一张图片 第二张图片

1 个回答

11

现在还不太清楚为什么会出现这个问题,这肯定是个bug。不过,我这里提供一个解决方法,虽然它没有那么自动化。

出于某种原因,表示散点的 Patch3DCollection 在第一次渲染后并没有更新。这个更新是很重要的,因为它是为每个集合的补丁设置独特颜色的地方。为了强制它重新初始化,你可以在 Patch3DCollection 上使用 changed 方法(其实这是 ScalarMappable 的一个方法),这个方法只是用来记录发生了变化。当图形被绘制时,它会检查是否发生了更新,如果有,就会重新定义颜色。如果没有,这个过程就会被跳过。

为了让这个更新自动发生,最好是在每次“绘制”事件时都这样做。要实现这一点,需要使用 canvasmpl_connect 方法来 注册一个方法(可以参考链接中的教程)。

这个例子展示了保存图形两次可以保持颜色映射,但如果你取消注释 plt.show() 这一行,它仍然会正常工作(比如在旋转时)。

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

# Create Map
cm = plt.get_cmap("RdYlGn")

# added a seed so consistant plotting of points
np.random.seed(101)
x = np.random.rand(30)
y = np.random.rand(30)
z = np.random.rand(30)

col = np.arange(30)

fig = plt.figure()
#ax = fig.add_subplot(111)
#scatCollection = ax.scatter(x,y,
ax3D = fig.add_subplot(111, projection='3d')
# keep track of the Patch3DCollection:
scatCollection = ax3D.scatter(x, y, z, s=30, 
                            c=col, 
                            marker='o',
                            cmap=cm
                            )
def forceUpdate(event):
    global scatCollection
    scatCollection.changed()

fig.canvas.mpl_connect('draw_event',forceUpdate)

#plt.show()

plt.savefig('image1.png')

plt.savefig('image2.png')

理想情况下,不应该需要这样做,应该可以通过其他方法访问全局的 scatCollection(我正在努力实现这一点)。不过现在这样也能用……

撰写回答