matplotlib 3D 表面的半透明和颜色渐变?
Translucency and color gradients of matplotlib 3D surfaces?
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
X = np.arange(1, 4, 0.2)
Y = np.copy(X)
X, Y = np.meshgrid(X, Y)
Z1 = np.copy(X)
Z2 = 2/X
fig = plt.figure()
ax = fig.gca(projection='3d')
surf1 = ax.plot_surface(X, Y, Z1, rstride=1, cstride=1, color='b')
surf2 = ax.plot_surface(X, Y, Z2, rstride=1, cstride=1, color='r')
plt.show()
当我 运行 上面的代码时,我得到以下内容。注意,为了便于说明,我从底部设置了视点。
两个问题:
为什么红色平面有漂亮的渐变色,而蓝色平面有这种不规则的图案?如何使蓝色的图案像红色的图案或使着色统一?
我想让这两个平面从观察者的角度来看,另一个平面的 "in front" 部分是可见的。例如,在上图中,显示的大部分红色平面都是可见的,但在 z = sqrt(2) ~= 1.41 的交线上方,它会隐藏在蓝色平面后面。我怎样才能让 Matplotlib 做到这一点?
您的示例暴露了 matplotlib 的着色算法中的错误。底纹
算法计算表面每个面的法线,使用颜色
和它的法向量来遮蔽小平面:
colset = self._shade_colors(color, normals)
虽然理论上一个平面的法线都是相同的,但实际上,有
由于变幻莫测的变化,数值的变化很小
浮点运算。这些非常微小的变化被放大了
normalization since this stretches the minimum and maximum shades 介于 0 和 1 之间。
因此所有完全平面的表面都容易出现此着色错误。
当颜色均匀(例如color='b'
)且法线完全相同(如
飞机的情况),每个面的阴影应该相同。归一化应该使阴影为零。所以对于飞机来说,阴影不应该
完全改变颜色。
因此,要解决此错误,请使用 shade=False
:
关闭阴影
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
X = np.arange(1, 4, 0.2)
Y = np.copy(X)
X, Y = np.meshgrid(X, Y)
Z1 = np.copy(X)
Z2 = 2/X
fig = plt.figure()
ax = fig.gca(projection='3d')
surf1 = ax.plot_surface(
X, Y, Z1, rstride=1, cstride=1, color='b',
shade=False, alpha=1.0)
surf2 = ax.plot_surface(
X, Y, Z2, rstride=1, cstride=1, color='r',
shade=True, alpha=1.0)
ax.view_init(elev=-45, azim=-30)
plt.show()
PS。如果您想查看规范化出错的确切位置,请将上面代码中的 shade=False
更改为 shade=True
,然后将这些 print
语句放入安装的 matplotlib/colors.py
:
resdat = result.data
resdat -= vmin
print(resdat[0, :10])
resdat /= (vmax - vmin)
print(resdat[0, :10])
result = np.ma.array(resdat, mask=result.mask, copy=False)
运行 上面的脚本然后打印
[ 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 2.22044605e-16 0.00000000e+00
0.00000000e+00 2.22044605e-16]
[ 0. 0. 0. 0. 0. 0. 1. 0. 0. 1.]
如果 resdat
一致不变,则 resdat
中的所有值在归一化后都将为零。相反,resdat
中的微小错误被放大到等于 1。这会导致您在蓝色表面上看到有趣的阴影。
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
X = np.arange(1, 4, 0.2)
Y = np.copy(X)
X, Y = np.meshgrid(X, Y)
Z1 = np.copy(X)
Z2 = 2/X
fig = plt.figure()
ax = fig.gca(projection='3d')
surf1 = ax.plot_surface(X, Y, Z1, rstride=1, cstride=1, color='b')
surf2 = ax.plot_surface(X, Y, Z2, rstride=1, cstride=1, color='r')
plt.show()
当我 运行 上面的代码时,我得到以下内容。注意,为了便于说明,我从底部设置了视点。
两个问题:
为什么红色平面有漂亮的渐变色,而蓝色平面有这种不规则的图案?如何使蓝色的图案像红色的图案或使着色统一?
我想让这两个平面从观察者的角度来看,另一个平面的 "in front" 部分是可见的。例如,在上图中,显示的大部分红色平面都是可见的,但在 z = sqrt(2) ~= 1.41 的交线上方,它会隐藏在蓝色平面后面。我怎样才能让 Matplotlib 做到这一点?
您的示例暴露了 matplotlib 的着色算法中的错误。底纹 算法计算表面每个面的法线,使用颜色 和它的法向量来遮蔽小平面:
colset = self._shade_colors(color, normals)
虽然理论上一个平面的法线都是相同的,但实际上,有 由于变幻莫测的变化,数值的变化很小 浮点运算。这些非常微小的变化被放大了 normalization since this stretches the minimum and maximum shades 介于 0 和 1 之间。
因此所有完全平面的表面都容易出现此着色错误。
当颜色均匀(例如color='b'
)且法线完全相同(如
飞机的情况),每个面的阴影应该相同。归一化应该使阴影为零。所以对于飞机来说,阴影不应该
完全改变颜色。
因此,要解决此错误,请使用 shade=False
:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
X = np.arange(1, 4, 0.2)
Y = np.copy(X)
X, Y = np.meshgrid(X, Y)
Z1 = np.copy(X)
Z2 = 2/X
fig = plt.figure()
ax = fig.gca(projection='3d')
surf1 = ax.plot_surface(
X, Y, Z1, rstride=1, cstride=1, color='b',
shade=False, alpha=1.0)
surf2 = ax.plot_surface(
X, Y, Z2, rstride=1, cstride=1, color='r',
shade=True, alpha=1.0)
ax.view_init(elev=-45, azim=-30)
plt.show()
PS。如果您想查看规范化出错的确切位置,请将上面代码中的 shade=False
更改为 shade=True
,然后将这些 print
语句放入安装的 matplotlib/colors.py
:
resdat = result.data
resdat -= vmin
print(resdat[0, :10])
resdat /= (vmax - vmin)
print(resdat[0, :10])
result = np.ma.array(resdat, mask=result.mask, copy=False)
运行 上面的脚本然后打印
[ 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00
0.00000000e+00 0.00000000e+00 2.22044605e-16 0.00000000e+00
0.00000000e+00 2.22044605e-16]
[ 0. 0. 0. 0. 0. 0. 1. 0. 0. 1.]
如果 resdat
一致不变,则 resdat
中的所有值在归一化后都将为零。相反,resdat
中的微小错误被放大到等于 1。这会导致您在蓝色表面上看到有趣的阴影。