Matplotlib绘制三维图形时出现透明度问题的处理方法

10

我正在尝试从指定z值的数据集中绘制3D表面。但是我遇到了一些奇怪的透明度伪影,即使我将alpha设置为1.0。

这种伪影在绘图和保存为文件(png和pdf)时都会出现:

enter image description here

我尝试过更改线宽以及将步幅数量从1更改为10(在后一种情况下,由于分辨率太低,表面不可见)。

问题:如何消除此透明度?

以下是我的代码:

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

y_label = r'x'
x_label = r'y'
z_label = r'z'

x_scale = 2.0*np.pi
y_scale = 2.0*np.pi

y_numPoints = 250
x_numPoints = 250

def quasiCrystal(x, y):
    z = 0
    for i in range(0,5):
        z += np.sin(x * np.cos(float(i)*np.pi/5.0) +
                    y * np.sin(float(i)*np.pi/5.0))
    return z

x = np.linspace(-x_scale, x_scale, x_numPoints)
y = np.linspace(-y_scale, y_scale, y_numPoints)
X,Y = np.meshgrid(x,y)

Z = quasiCrystal(X, Y)


f = plt.figure()
ax = f.gca(projection='3d')

surf = ax.plot_surface( X, Y, Z,
                        rstride=5, cstride=5,
                        cmap='seismic',
                        alpha=1,
                        linewidth=0,
                        antialiased=True,
                        vmin=np.min(Z),
                        vmax=np.max(Z)
                      )

ax.set_zlim3d(np.min(Z), np.max(Z))

f.colorbar(surf, label=z_label)

ax.set_xlabel(x_label)
ax.set_ylabel(y_label)
ax.set_zlabel(z_label)

plt.show()

这里是我实际数据的另一张图片,更容易看到伪影:

输入图像描述

1
请提供您的数据样本,以便我们能够重现您的问题。 - jrjc
更新了示例数据。 - fromGiants
2个回答

9

Matplotlib不是一个“真正的”3D引擎。这是一个非常著名的问题,偶尔会出现类似于你的问题(参见thisthis)。问题在于相同的产物可能导致看似不同的问题。我相信你的情况就是如此。

在继续给出我的建议之前,请允许我引用一下matplotlib官网上的这段信息

我的3D图在某些视角下看起来不对劲。
这可能是mplot3d最常见的问题。问题在于,从某些视角下,一个3D物体会出现在另一个物体的前面,即使它实际上在后面。这可能导致绘图看起来“物理上不正确”。
不幸的是,虽然已经在减少这种现象的工作,但目前这是一个棘手的问题,只有当matplotlib在其核心支持3D图形渲染时,才能完全解决。
这个问题是由于将3D数据缩减为2D + z-order标量引起的。一个值代表了集合中所有3D对象的第三个维度。因此,当两个集合的边界框相交时,就有可能出现这种现象。此外,两个3D对象(如多边形或补丁)的相交在matplotlib的2D渲染引擎中无法正确呈现。
在所有后端添加OpenGL支持之前,这个问题可能不会得到解决(欢迎提供补丁)。在那之前,如果您需要复杂的3D场景,我们建议使用MayaVi。

似乎Mayavi最终转向了Python 3},所以这当然是可能的。如果你想在这种情况下坚持使用matplotlib进行绘图,我的建议是你尝试不同的rstride和cstride值,看看哪些值可以产生令你满意的绘图。

surf = ax.plot_surface( X, Y, Z,
                        rstride=5, cstride=5,
                        cmap='jet',
                        alpha=1,
                        linewidth=0,
                        antialiased=True,
                        vmin=0,
                        rstride=10,
                        cstride=10,
                        vmax=z_scale
                      )

另一种可能性是尝试看看其他类型的3D图能否更好。请检查plot_trisurfcontourcontourf。我知道这不是理想的解决办法,但在过去,我也成功地使用3D多边形来绕过其他类型的伪影问题

很抱歉没有给出更令人满意的答案。也许其他Stack Overflow用户对此有更好的解决方案。祝你好运。


1
另请参见https://dev59.com/2mUq5IYBdhLWcg3wEcNY#14825951。 - tacaswell

8

我遇到了一些类似的问题,发现它们是抗锯齿伪影,可以通过在plot_surface中设置antialiased=False来解决。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接