The goal is to create a continuous colormap from concrete pairs of values and RGB colors.
Example:
values = [1, 5, 10, 20]
colors = [(3, 40, 252), (252, 3, 20), (252, 223, 3), (35, 224, 13)]
Let's say I want to get the color for value 15, the retrieved color would be a faded mix of (252, 223, 3) and (35, 224, 13). In my case, the color would be (143, 223, 8). I want to get the correct color for values between 1 and 20.
You can run this code to get the calculated color:
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))
My idea was to generate multiple colormaps and norms and combine them to one. But this is just a broad idea.
Does someone have an idea how to solve the task? Any help appreciated
Everything I found so far, is using discrete colors, instead of continuous transitions.
CodePudding user response:
LinearSegmentedColormap.from_list(...)
accepts a list of tuples. The first component of the tuple is a value from 0 to 1, and the second the corresponding color. You can create these from the normalized values:
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)}')
Resulting values:
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]
Here is a visualization:
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()