首页 > 解决方案 > Matplotlib 中非线性颜色条的统一刻度标签

问题描述

我正在寻找一种解决方案来创建具有统一刻度标签(沿颜色条等间距)的颜色条,即使边界是非线性的。目前,由于刻度是根据边界值按比例间隔开的,所以颜色条的顶部被拉伸得很厉害,而底部被压缩得如此之快,以至于无法看到哪些颜色对应于哪个值。我想保持相同的颜色/值组合,但带有使颜色条清晰易读的刻度标签间距。

我使用当前代码获得的颜色条:
1

这是我使用的代码:

import matplotlib as mpl
from matplotlib.backends.backend_agg import FigureCanvasAgg
from matplotlib.colors import LinearSegmentedColormap
from matplotlib.figure import Figure

# data
bounds = [0.1, 0.25, 0.5, 1, 2.5, 5, 7.5, 10, 15, 20, 25, 50, 100]
style_color = [[0, 0, 127],
               [0, 0, 197],
               [0, 21, 254],
               [0, 126, 254],
               [0, 231, 254],
               [68, 253, 186],
               [153, 254, 101],
               [238, 254, 16],
               [254, 187, 0],
               [254, 101, 0],
               [254, 16, 0],
               [197, 0, 0],
               [127, 0, 0],
               [127, 0, 0]]

# transform color rgb value to 0-1 range
color_arr = []
for color in style_color:
    rgb = [float(value)/255 for value in color]
    color_arr.append(rgb)

# normalize bound values
norm = mpl.colors.Normalize(vmin=min(bounds), vmax=max(bounds))
normed_vals = norm(bounds)

# create a colormap
cmap = LinearSegmentedColormap.from_list(
    'my_palette',
    list(zip(normed_vals, color_arr[:-1])),
    N=256
    )
cmap.set_over([color for color in color_arr[-1]])
cmap.set_under([color for color in color_arr[0]])

# create a figure
fig = Figure(figsize=(2, 5))
canvas = FigureCanvasAgg(fig)
ax = fig.add_subplot(121)

# create the colorbar
cb = mpl.colorbar.ColorbarBase(ax,
                               cmap=cmap,
                               norm=norm,
                               extend='max',
                               ticks=bounds)

fig.savefig('non-linear_colorbar')

标签: pythonmatplotlibcolorbar

解决方案


ABoundaryNorm似乎是您正在寻找的东西:

import matplotlib as mpl
from matplotlib.colors import LinearSegmentedColormap, BoundaryNorm
from matplotlib import pyplot as plt

# data
bounds = [0.1, 0.25, 0.5, 1, 2.5, 5, 7.5, 10, 15, 20, 25, 50, 100]
style_color = [[0, 0, 127],
               [0, 0, 197],
               [0, 21, 254],
               [0, 126, 254],
               [0, 231, 254],
               [68, 253, 186],
               [153, 254, 101],
               [238, 254, 16],
               [254, 187, 0],
               [254, 101, 0],
               [254, 16, 0],
               [197, 0, 0],
               [127, 0, 0],
               [127, 0, 0]]

# transform color rgb value to 0-1 range
color_arr = []
for color in style_color:
    rgb = [float(value) / 255 for value in color]
    color_arr.append(rgb)

# normalize bound values
norm = mpl.colors.BoundaryNorm(bounds, ncolors=256)

# create a colormap
cmap = LinearSegmentedColormap.from_list('my_palette', color_arr, N=256)

# create a figure
fig, ax = plt.subplots(figsize=(2, 5), gridspec_kw={'left': 0.4, 'right': 0.5})

# create the colorbar
cb = mpl.colorbar.ColorbarBase(ax, cmap=cmap, norm=norm, extend='max', ticks=bounds)
plt.show()

结果图

PS:如果你需要一个平滑的颜色条,你可以拉伸边界:

import numpy as np

bounds = [0.1, 0.25, 0.5, 1, 2.5, 5, 7.5, 10, 15, 20, 25, 50, 100]
stretched_bounds = np.interp(np.linspace(0, 1, 257), np.linspace(0, 1, len(bounds)), bounds)

# normalize stretched bound values
norm = mpl.colors.BoundaryNorm(stretched_bounds, ncolors=256)

# ....
cb = mpl.colorbar.ColorbarBase(ax, cmap=cmap, norm=norm, extend='max', ticks=bounds)

延伸的界限

PS:new_y = np.interp(new_x, old_x, old_y)通过首先在旧 x 的数组中查找 x,并找到对应的旧 y,为 y 插入新值。当新 x 位于两个旧 x 之间时,新 y 将按比例位于旧 y 之间。

对于BoundaryNorm,np.interp计算所有中间值以获得 256 个不同的级别,而不是原来的 13 个。


推荐阅读