matplotlib 中 Poly3DCollection 图的透明度

Posted

技术标签:

【中文标题】matplotlib 中 Poly3DCollection 图的透明度【英文标题】:Transparency for Poly3DCollection plot in matplotlib 【发布时间】:2013-09-24 17:18:36 【问题描述】:

我正在尝试使用用于 Python 的神话般的 Matplotlib 包绘制一些对象。这些对象由plt.scatter() 实现的点和Poly3DCollection 实现的补丁组成。我希望补丁具有轻微的透明度,以便可以看到补丁后面的点和边缘。

这里是我已经生成的代码和绘图。似乎我快到了,只是缺少透明度的功能。有趣的是,如果我先绘制Ploy3DCollection,然后绘制scatter 点,则可以看到点,但看不到边缘。

有人对我有建议吗?

from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d.art3d import Poly3DCollection

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

x = [0, 2, 1, 1]
y = [0, 0, 1, 0]
z = [0, 0, 0, 1]

vertices = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]]

tupleList = list(zip(x, y, z))

poly3d = [[tupleList[vertices[ix][iy]] for iy in range(len(vertices[0]))] for ix in range(len(vertices))]
ax.scatter(x,y,z)
ax.add_collection3d(Poly3DCollection(poly3d, facecolors='w', linewidths=1, alpha=0.5))

plt.show()

【问题讨论】:

【参考方案1】:

我找到了一个很好的解决方法:绘制数据后,在顶部使用相同的颜色和较浅的线条样式绘制另一个图。而不是Poly3DCollection 我使用Line3DCollection,所以没有绘制任何面孔。结果看起来非常符合预期。

请参阅下面的新情节和创建它的脚本。

from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d.art3d import Poly3DCollection, Line3DCollection

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

x = [0, 2, 1, 1]
y = [0, 0, 1, 0]
z = [0, 0, 0, 1]

vertices = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]]

tupleList = list(zip(x, y, z))

poly3d = [[tupleList[vertices[ix][iy]] for iy in range(len(vertices[0]))] for ix in range(len(vertices))]
ax.scatter(x,y,z)
ax.add_collection3d(Poly3DCollection(poly3d, facecolors='w', linewidths=1, alpha=0.5))
ax.add_collection3d(Line3DCollection(poly3d, colors='k', linewidths=0.2, linestyles=':'))

plt.show()

【讨论】:

一般来说Line3DCollection 的补丁必须关闭(不像Poly3DCollection)。在这个例子中没关系,但通常我们应该以重复第一个顶点结束,即vertices = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3], [0, 1, 2]] 对于后代,xyzvertices 的索引。这有点令人困惑,因为它们都是小的正整数。 Poly3DCollection 的参数是 [[v1, v2, v3], [v2, v3, v4], [v3, v4, v5]],其中 v1 是 x、y、z 位置值的元组。【参考方案2】:

我对 OP 代码稍作修改,让透明度工作正常。 Poly3DCollection 的 facecolors 参数似乎覆盖了透明度参数,因此解决方案是在对 Poly3DCollection.set_colorPoly3DCollection.set_facecolor 的单独调用中设置颜色:

from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d.art3d import Poly3DCollection

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

x = [0, 2, 1, 1]
y = [0, 0, 1, 0]
z = [0, 0, 0, 1]

vertices = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]]

tupleList = zip(x, y, z)

poly3d = [[tupleList[vertices[ix][iy]] for iy in range(len(vertices[0]))] for ix in range(len(vertices))]
ax.scatter(x,y,z)
collection = Poly3DCollection(poly3d, linewidths=1, alpha=0.2)
face_color = [0.5, 0.5, 1] # alternative: matplotlib.colors.rgb2hex([0.5, 0.5, 1])
collection.set_facecolor(face_color)
ax.add_collection3d(collection)

plt.show()

有趣的是,如果您使用collection.set_edgecolor('k') 明确设置边缘颜色,则边缘也将遵循透明度设置。

【讨论】:

【参考方案3】:

非常感谢 Chilichiller 和 Julian。您的示例目前对我非常有用,因为我正在做一个关于使用 matplotlib 进行矩阵 3D 表示的小项目,而 Poly3DCollection 似乎适合这项任务。

一个小笔记,也许对未来的读者有用。 在 Python 3 中运行您的示例会给出 TypeError: 'zip' object is not subscriptable。

最简单的解决方案是将 zip 的返回值包装在对 list() 的调用中(如“深入 Python 3”所示:http://www.diveintopython3.net/porting-code-to-python-3-with-2to3.html)。

【讨论】:

很高兴它对你有用。我现在在原始的 sn-p 中添加了 list() 命令,以使示例代码与 python3 兼容。【参考方案4】:

此错误已在新的 matplotlib 中修复。我正在运行 1.5.1 版。

你可以通过运行python查看你的版本,然后执行:

import matplotlib
matplotlib.__version__

您可以使用 pip 获取 matplotlib。如果您使用的是 Ubuntu,请从终端运行:

sudo apt-get install python-pip
sudo pip install matplotlib

【讨论】:

【参考方案5】:

这是一个仅使用一次调用Poly3DCollection 的版本,其中edgecolors='k' 控制线条的颜色,facecolors='w' 控制面的颜色。请注意 Matplotlib 如何将多边形后面的边缘用浅灰色着色。

from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d.art3d import Poly3DCollection, Line3DCollection

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

x = [0, 2, 1, 1]
y = [0, 0, 1, 0]
z = [0, 0, 0, 1]

vertices = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]]

tupleList = list(zip(x, y, z))

poly3d = [[tupleList[vertices[ix][iy]] for iy in range(len(vertices[0]))] for ix in range(len(vertices))]
ax.scatter(x,y,z)
ax.add_collection3d(Poly3DCollection(poly3d, edgecolors='k', facecolors='w', linewidths=1, alpha=0.5))

plt.show()

注意Poly3DCollection 的 API 相当混乱:接受的关键字参数都是 colorsedgecoloredgecolorsfacecolorfacecolors(使用别名和装饰器来定义多个 kwargs 来表示同一件事,其中“s”对于facecoloredgecolor 是可选的)。

【讨论】:

以上是关于matplotlib 中 Poly3DCollection 图的透明度的主要内容,如果未能解决你的问题,请参考以下文章

为何学习matplotlib-老鱼学matplotlib

matplotlib-legend()中loc的用法

Python中使用matplotlib 如何绘制折线图?

matplotlib绘图入门详解

如何从 matplotlib 中删除框架(pyplot.figure vs matplotlib.figure)(frameon=False 在 matplotlib 中有问题)

python--Matplotlib中显示负号问题