Python中3D表面绘图的颜色

11

我正在使用以下代码绘制一个3D曲面:

surf = ax3.plot_surface(X, Y, Z, rstride=1, cstride=1, alpha=0.5, linewidth=0, cmap=cm.jet,antialiased=True)

现在颜色非常好,虽然有点鳞状外观,但很细腻。
但我想根据 list 存储的另一个数据来改变表面颜色:

m = [104.48, 111.73,109.93,139.95,95.05,150.49,136.96,157.75]

我试着使用:

norm = cls.Normalize() # Norm to map the 'm' values to [0,1]
norm.autoscale(m)
cmap = cm.ScalarMappable(norm, 'jet')
surf = ax3.plot_surface(X, Y, Z, rstride=5, cstride=5, alpha=0.5, linewidth=0, color=cmap.to_rgba(m), antialiased=True)

但是这会引发一个错误,因为cmap.to_rgba只接受1D数组。 如果有任何建议可以让我改变表面的colormap,将不胜感激。

3个回答

9
为了获得正确的颜色,请使用Z值从颜色图中选择值:
my_col = cm.jet(Z/np.amax(Z))

结果如下:

结果:

曲面图

使用与@Moritz相同的代码,除此之外没有其他区别。

from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import matplotlib.pyplot as plt
import numpy as np

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
my_col = cm.jet(Z/np.amax(Z))

surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors = my_col,
        linewidth=0, antialiased=False)
ax.set_zlim(-1.01, 1.01)

plt.show()

有没有办法去除图形的鳞状外观,使其变得光滑亮丽? - diffracteD
你需要将数据插值到一个更细的网格上。 - Moritz
@diffracteD 正如@Moritz所说,将np.arange(-5,5,0.25)中的0.25更改为较低的值。 - pingul
@pingul 我会回复你关于鳞状外观的问题。但更重要的是,我关注的是将m值用作XYZ表面上的颜色映射。请就此问题发表评论。 - diffracteD
@diffracteD,您需要为每个Z值赋予一个颜色值,即m将需要包含与Z相同的维度(检查Z.shape == m.shape)。如果是这种情况,只需更改代码为my_col = cm.jet(m/np.amax(m))以进行归一化。 - pingul

9

好的,看起来很糟糕,但我认为您可以适应它:

from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import matplotlib.pyplot as plt
import numpy as np

fig = plt.figure()
ax = fig.gca(projection='3d')
X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
my_col = cm.jet(np.random.rand(Z.shape[0],Z.shape[1]))

surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors = my_col,
        linewidth=0, antialiased=False)
ax.set_zlim(-1.01, 1.01)

结果图 我不会使用jet,而是使用像这样的线性色彩映射。你可以轻松地通过使用错误的颜色映射欺骗眼睛(关于此主题的文章之一:链接)。


如果我理解正确的话,您正在绘制 X,Y,Z 并根据 Z-array 给表面设置自定义颜色。但是我已经有了一个 (X,Y,Z) 的白色表面,现在我想根据 m-array 的值对表面进行着色。如果我误解了,请纠正我。 - diffracteD
你需要在经过缩放的m数组上使用meshgrid函数才能得到一个二维数组。 - Moritz
是的,在x,y,z拟合的情况下,我正在使用np.meshgrid,但它会给我一个矩阵数据(秩为3),需要传递给plot_surface(X,Y,Z,...)来生成表面。现在,如果我包括m,我该如何处理秩为4的矩阵进行绘图?关于您的想法的一点代码将会很好。 - diffracteD
只要您不提供数组m和一些可工作的最小示例,我只能猜测。 - Moritz
2
@diffracteD,m与X、Y和Z有什么关系?它们的元素数量是否相同?你希望如何将m映射到你的表面上? - Amy Teegarden
显示剩余5条评论

0

我认为之前的答案有些误导人。facecolors 应该比网格值小一列和一行!否则,面将根据面角中的一个值进行彩色偏移(对于许多值可能无关紧要)。这对于一些对称值变得明显(请参见下面的示例)。您可以计算面中间的新值或平均面角的值,这是我需要测量值的方法。同样,可以线性插值中间值并绘制更多面。以下是一个比较的示例:

import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np

x_lst = np.linspace(-5, 5, 4)
y_lst = np.linspace(-5, 5, 4)
x_grid, y_grid = np.meshgrid(x_lst, y_lst)
z_grid = x_grid + y_grid

# values at face corners (at the grid points)
c_grid = np.abs(x_grid + y_grid)  # same size like x_val, y_val, z_val
print(c_grid)

# averaged corner values for each face
c_faces = np.lib.stride_tricks.sliding_window_view(c_grid, (2,2))
c_faces = np.mean(c_faces, axis=(2, 3))  # size reduces by 1
print(c_faces)

# color map and normalization
c_min, c_max = np.min(c_grid), np.max(c_grid)  # could also be min and max of c_faces
norm = mpl.colors.Normalize(vmin=c_min, vmax=c_max)
cmap = mpl.cm.viridis

for c_vals in [c_grid,    # values at face corners
               c_faces]:  # averaged corner values
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    surf = ax.plot_surface(x_grid, y_grid, z_grid,
                           rstride=1, cstride=1,  # no downsampling
                           facecolors = cmap(norm(c_vals)), shade=False)
    cbar = plt.colorbar(mpl.cm.ScalarMappable(norm=norm, cmap=cmap), ax=ax, pad=0.2)
    ax.dist = 8
    plt.show()

带网格值的移动图: 输入图像描述 平均值的图: 输入图像描述


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