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

Time:02-23

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()

sns.heatmap using LinearSegmentedColormap.from_list

  • Related