I would like to plot some values and highlight in specific colors values outside a certain range. In order to do that I do the following:
- use the method
set_under
andset_over
to specify what color to use for the out of range values. - specify
vmin
andvmax
when plotting the data
This works fine, data outside the acceptance range is marked with the correct color.
Now I would like to add a text on the plot, to specify the value in that point. Since the colors are different, I need to specify different text colors, depending on the value. To do that I read the RGB values from the colormap, calculate the luminance value of the color and choose a white or black text color. The issue is that it seems the colormap values I get are not correct. Here is an example code:
min_data = -1.1
max_data = 3.5
test_array = np.random.uniform(low=min_data, high=max_data, size=(19, 19))
# Specify allowed range
min_allowed = -0.9
max_allowed = 2.9
fig, ax = plt.subplots(1, 1)
palette = copy(plt.cm.get_cmap("gray"))
palette.set_over('yellow', 1.0)
palette.set_under('blue', 1.0)
im = ax.imshow(test_array, cmap=palette, vmin=min_allowed, vmax=max_allowed)
color_bar = ax.figure.colorbar(im, ax=ax)
for i in range(test_array.shape[0]):
for j in range(test_array.shape[1]):
data_val = (test_array[i, j] * 255).astype(np.uint8)
cmap_value = im.cmap(data_val, bytes=True)
luminance = (0.299 * cmap_value[0] 0.587 * cmap_value[1] 0.114 * cmap_value[2]) / 255
if luminance > 0.45:
color = "black"
else:
color = "white"
text = im.axes.text(j, i, "{:.2f}".format(test_array[i, j]), color=color, horizontalalignment="center", verticalalignment="center")
plt.show()
The result is the following:
Some values that are above the max allowed range are correctly displayed in yellow, but the text is for some reason white (thus unreadable). If I check the colormap value that I get for example for a value of 3.055 (i.e. outside the range) I get cmap_value (11, 11, 11, 255)
, whereas I would expect the yellow RGB values, i.e. (255, 255, 0, 255)
.
I am a bit lost at this point as for what is going wrong, any tips?
CodePudding user response:
First, note that matplotlib's colormaps work in two different ways:
- If called with an integer type as argument, the argument is used as an index into an array of colors (depends on the colormap, typical colormaps have 256 colors). When the argument is lower than
0
, theunder
color is returned. When the argument is higher or equal than the number of colors, theover
color is returned. Otherwise, the color at the given index is returned. - If called with a float type as argument,
0.0
is considered the lowest color in the array,1.0
the highest color. Inside that range, the value is interpolated. Outside the range, either theunder
orover
color is returned (forNaN
values thebad
color is returned (typically pure transparent, or'none'
.)).
When called via a function such as imshow
, the given value is