如何调整Matplotlib颜色映射,使含极值的z值颜色过渡更连续?
解决3D曲面图颜色离散、过渡不连续的问题
我想要创建颜色过渡连续的3D曲面图,但当前生成的图颜色呈现离散状态。以下是我编写的两段代码:
第一段代码:
import numpy as np import matplotlib.pyplot as plt from matplotlib import cm x = np.linspace(-90, 90, 181) y = np.linspace(-90, 90, 181) x_grid, y_grid = np.meshgrid(x, y) z = np.e**x_grid fig = plt.figure() ax = fig.add_subplot(1, 1, 1, projection="3d") ax.plot_surface(x_grid, y_grid, z, cmap=cm.rainbow)
我还尝试对z和颜色映射进行归一化,代码如下:
import numpy as np import matplotlib.pyplot as plt from matplotlib import cm import matplotlib as mpl x = np.linspace(-90, 90, 181) y = np.linspace(-90, 90, 181) x_grid, y_grid = np.meshgrid(x, y) z = np.e**x_grid cmap = mpl.cm.rainbow norm = mpl.colors.Normalize(vmin=0, vmax=1) fig = plt.figure() ax = fig.add_subplot(1, 1, 1, projection="3d") ax.plot_surface(x_grid, y_grid, z/np.max(z), norm=norm, cmap=cm.rainbow)
问题:如何调整颜色映射,让同时包含极小值和极大值的z值对应的颜色过渡更自然连续,而非离散状态?
问题根源
你的z值是指数函数e**x_grid,当x从-90到90时,z值的分布极度不均:x=-90时z几乎为0,x=90时z是一个极大的数,大部分z值集中在极小的区间,导致常规线性归一化的颜色映射被压缩,呈现出离散色块。
解决方法
可以通过适配z值分布的归一化方式,让颜色映射均匀覆盖z值区间,实现连续过渡:
方法1:使用对数归一化(LogNorm)
对数归一化能把指数分布的z值转换为近似线性的分布,让颜色过渡更均匀:
import numpy as np import matplotlib.pyplot as plt from matplotlib import cm import matplotlib as mpl x = np.linspace(-90, 90, 181) y = np.linspace(-90, 90, 181) x_grid, y_grid = np.meshgrid(x, y) z = np.e**x_grid # 给z最小值加极小值,避免log(0)报错 norm = mpl.colors.LogNorm(vmin=z.min() + 1e-10, vmax=z.max()) fig = plt.figure() ax = fig.add_subplot(1, 1, 1, projection="3d") surf = ax.plot_surface(x_grid, y_grid, z, cmap=cm.rainbow, norm=norm) fig.colorbar(surf) # 可选:添加颜色条直观观察映射效果 plt.show()
方法2:使用幂次归一化(PowerNorm)
如果对数归一化效果过强,可以尝试幂次归一化,通过调整gamma值控制映射曲线的陡峭程度:
import numpy as np import matplotlib.pyplot as plt from matplotlib import cm import matplotlib as mpl x = np.linspace(-90, 90, 181) y = np.linspace(-90, 90, 181) x_grid, y_grid = np.meshgrid(x, y) z = np.e**x_grid # gamma值越小,越放大低z值的颜色差异,可根据需求调整 norm = mpl.colors.PowerNorm(gamma=0.1, vmin=z.min(), vmax=z.max()) fig = plt.figure() ax = fig.add_subplot(1, 1, 1, projection="3d") surf = ax.plot_surface(x_grid, y_grid, z, cmap=cm.rainbow, norm=norm) fig.colorbar(surf) plt.show()
方法3:直接用x值映射颜色(针对当前场景)
由于你的z值完全由x决定,也可以直接用x值作为颜色映射的依据,让颜色随x线性变化,过渡自然:
import numpy as np import matplotlib.pyplot as plt from matplotlib import cm x = np.linspace(-90, 90, 181) y = np.linspace(-90, 90, 181) x_grid, y_grid = np.meshgrid(x, y) z = np.e**x_grid fig = plt.figure() ax = fig.add_subplot(1, 1, 1, projection="3d") # 将x_grid归一化后直接作为颜色输入 norm_x = (x_grid - x.min()) / (x.max() - x.min()) surf = ax.plot_surface(x_grid, y_grid, z, cmap=cm.rainbow, facecolors=cm.rainbow(norm_x)) fig.colorbar(surf) plt.show()
内容的提问来源于stack exchange,提问作者inception
相关产品推荐
相关产品推荐

