配置matplotlib颜色条以匹配3D表面值

时间:2019-05-13 12:26:10

标签: python matplotlib colorbar

我试图将快速傅立叶变换的结果显示为2D矩阵(形状:2048x1024)的3D曲面,并在其一侧带有一个色条,以与我的值匹配。 显示器工作正常,但颜色栏的“颜色”与图表的颜色不匹配。我应该如何配置颜色条和图形以使其匹配?

我尝试根据我的FFT结果设置vminvmax的值,但是图形的颜色完全错误。 我也尝试过函数clim(vmin, vmax)或方法.set_clim(vmin, vmax),但问题仍然相同。

这是我的代码: rp是2048x1024的矩阵。

import numpy as np
from pylab import *
from mpl_toolkits.mplot3d import Axes3D


figure(2, figsize=(9.6, 7.2))
ax1 = gca(projection='3d')
X = np.arange(0, 1024)
Y = np.arange(0, 2048)
X, Y = np.meshgrid(X, Y)
Z = 20 * np.log10(abs(rp))
# Plot the surface.
surf1 = ax1.plot_surface(X, Y, Z, cmap='jet', antialiased=False, vmin=np.min(Z), vmax=np.max(Z))
# Add a color bar which maps values to colors.
colorbar(surf1)
title('3D frequency profile')

show()

这就是我没有为色条配置vminvmax值的情况。最大颜色(红色)与最大值派克不匹配,并且颜色栏的最大值和最小值与我的图形中的最小值和最大值不匹配(注意:min = -24和max = 145)。

first_figure

这是设置vminvmax时得到的结果。所有图表的阴影大致相同,而我应该有两个红色的长矛。

second_figure

有什么想法吗?

2 个答案:

答案 0 :(得分:0)

我认为您只想在Matplotlib中使用Mappable,例如:

import matplotlib.pyplot as plt

mappable = plt.cm.ScalarMappable()
mappable.set_array(Z)

,然后使用该映射对象中的plot_surfacecmap调用norm,例如:

ax.plot_surface(X, Y, Z, cmap=mappable.cmap, norm=mappable.norm, linewidth=0, antialiased=False)

然后您可以将此可映射对象用于colorbar

plt.colorbar(mappable)

这应使用默认的viridis colormap颜色图,但可以手动将其指定为:

mappable = plt.cm.ScalarMappable(cmap=plt.cm.viridis)

Viridis是一个很好的“感知上统一的”颜色图,请参见上面的视频,了解为什么Matlab的jet几乎总是一个不好的选择,以及为什么它比更现代的默认parula更好

这似乎只是针对“垂直”高度和颜色重用了Z中的数据,因此我建议使用imshow,例如:

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

X, Y = np.meshgrid(
    np.linspace(-2, 2, 128),
    np.linspace(-2, 2, 128),
)
Z = np.exp(-(X ** 2 + Y ** 2)) * 3 + 5

mappable = plt.cm.ScalarMappable(cmap=plt.cm.viridis)
mappable.set_array(Z)
mappable.set_clim(5, 8) # optional

fig = plt.figure(figsize=(10,4))

ax1 = fig.add_subplot(121, projection='3d')
ax1.plot_surface(X, Y, Z, cmap=mappable.cmap, norm=mappable.norm, linewidth=0, antialiased=False)

ax2 = fig.add_subplot(122)
ax2.imshow(Z, cmap=mappable.cmap, norm=mappable.norm, extent=(
    np.min(X), np.max(X), np.min(Y), np.max(Y)), interpolation='none')

plt.colorbar(mappable)
plt.tight_layout()

给我:

plot_surface vs imshow

我发现第二个非3D绘图使我可以更轻松地了解正在发生的事情

答案 1 :(得分:0)

我终于找到了问题的原因。问题在于图表的colormap的步幅(如果我理解得很好,那就是它的分辨率-cstride and rstride documentation)。更准确地说,它使用cstride * rstride的表面来平均表面上信号的能量,并使图的颜色与此平均值相对应。我的长矛真的很稀,这就是为什么它们的阴影不好。 我必须用较小的值指定参数cstriderstride。由于其默认值为10。

现在我有:

figure(1, figsize=(12, 6))
X = np.arange(0, 1024)
Y = np.arange(0, 2048)
X, Y = np.meshgrid(X, Y)
Z = 20 * np.log10(abs(rp))
mappable = cm.ScalarMappable()
mappable.set_array(Z)
suptitle('3D-plot and 2D-plot of frequency profile')
ax1 = subplot(121, projection='3d')
ax1.plot_surface(X, Y, Z, cmap=mappable.cmap, norm=mappable.norm, linewidth=0,
                 antialiased=False, cstride=10, rstride=1)
ax2 = subplot(122)
ax2.imshow(Z, cmap=mappable.cmap, norm=mappable.norm,
           extent=(np.min(X), np.max(X), np.min(Y), np.max(Y)),
           interpolation=None)
colorbar(mappable)

show()

NB:我本可以为cstride保留默认值,因为我只需要更改row步幅即可。但这可能对其他人有帮助。

这是我得到的结果,它与我想要的相对应。 enter image description here

NB2:请注意减小步幅,输入数据越大,脚本越慢。