Matplotlib:从具体值和相应的颜色创建一个连续的颜色条

Matplotlib: Create a continous colorbar from concrete values and corresponding colors

目标是根据具体的值和 RGB 颜色对创建连续的颜色图。

示例:

values = [1, 5, 10, 20]
colors = [(3, 40, 252), (252, 3, 20), (252, 223, 3), (35, 224, 13)]

假设我想获取值 15 的颜色,检索到的颜色将是 (252, 223, 3) 和 (35, 224, 13) 的混合色。在我的例子中,颜色是 (143, 223, 8)。我想为 1 到 20 之间的值获取正确的颜色。

您可以运行此代码获取计算颜色:

import matplotlib as mpl
import numpy as np 

colors_zero_one = np.array([[252, 223, 3], [35, 224, 13]]) / 255
cmap = mpl.colors.LinearSegmentedColormap.from_list('custom', colors_zero_one, N=256)
norm = mpl.colors.Normalize(vmin=10, vmax=20)

print((np.array(cmap(norm(15))) * 255).astype(int))

我的想法是生成多个颜色图和规范并将它们合并为一个。但这只是一个广泛的想法。

有人知道如何解决这个任务吗?任何帮助表示赞赏

到目前为止我发现的所有内容都使用离散颜色,而不是连续过渡。

LinearSegmentedColormap.from_list(...) 接受元组列表。元组的第一个组件是从 0 到 1 的值,第二个组件是相应的颜色。您可以从标准化值创建这些:

from matplotlib import pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
import numpy as np

values = [1, 5, 10, 20]
colors = [(3, 40, 252), (252, 3, 20), (252, 223, 3), (35, 224, 13)]
norm = plt.Normalize(min(values), max(values))
cmap = LinearSegmentedColormap.from_list(
    '', [(norm(value), tuple(np.array(color) / 255)) for value, color in zip(values, colors)])

all_values = np.arange(values[0], values[-1] + 1)
for val in all_values:
    print(f'{val}: {np.round(np.array(cmap(norm(val))) * 255).astype(int)}')

结果值:

1: [  3  40 252 255]
2: [ 63  31 196 255]
3: [124  22 140 255]
4: [189  12  79 255]
5: [249   3  23 255]
6: [252  47  17 255]
7: [252  89  13 255]
8: [252 135  10 255]
9: [252 178   6 255]
10: [252 223   3 255]
11: [231 223   4 255]
12: [208 223   5 255]
13: [187 223   6 255]
14: [164 223   7 255]
15: [143 224   8 255]
16: [121 224   9 255]
17: [100 224  10 255]
18: [ 77 224  11 255]
19: [ 56 224  12 255]
20: [ 35 224  13 255]

这是一个可视化:

import seaborn as sns

plt.figure(figsize=(5, 12))
ax = sns.heatmap(all_values.reshape(-1, 1), xticklabels=[], yticklabels=all_values,
                 annot=[[f'{tuple(np.round(np.array(cmap(norm(val))) * 255)[:3].astype(int))}'] for val in all_values],
                 fmt='', cmap=cmap, norm=norm, lw=2,
                 cbar_kws={'ticks': range(values[0], values[-1] + 1)})
ax.invert_yaxis()
ax.tick_params(labelrotation=0)
plt.show()