Is it possible to set the lower and/or upper parts of a colorbar based on ranges of values? For example, given the ROYGBIV colormap below and optionally an offset
and a range
value, I'd like to change the colors below offset
and/or above range
. In other words, suppose offset = 20
and range = 72
, I'd like to color all the values less than or equal to 20 in black and all values greater than or equal to 72 in white. I'm aware of the methods set_under
and set_over
, but they require changing the parameters vmin
and vmax
(as far as I know), which is not what I want. I want to keep the original minimum and maximum values (e.g., vmin = 0
and vmax = 100
), and only (optionally) change the colors of the extremities.
ROYGBIV = {
"blue": ((0.0, 1.0, 1.0),
(0.167, 1.0, 1.0),
(0.333, 1.0, 1.0),
(0.5, 0.0, 0.0),
(0.667, 0.0, 0.0),
(0.833, 0.0, 0.0),
(1.0, 0.0, 0.0)),
"green": ((0.0, 0.0, 0.0),
(0.167, 0.0, 0.0),
(0.333, 0.0, 0.0),
(0.5, 1.0, 1.0),
(0.667, 1.0, 1.0),
(0.833, 0.498, 0.498),
(1.0, 0.0, 0.0)),
"red": ((0.0, 0.5608, 0.5608),
(0.167, 0.4353, 0.4353),
(0.333, 0.0, 0.0),
(0.5, 0.0, 0.0),
(0.667, 1.0, 1.0),
(0.833, 1.0, 1.0),
(1.0, 1.0, 1.0))
}
rainbow_mod = matplotlib.colors.LinearSegmentedColormap("rainbow_mod", ROYGBIV, 256)
I found one way to do it using ListedColormap
as explained here. The basic idea is to obtain the RGBA lists/tuples of the colors in the LinearSegmentedColormap
object (numpy
array) and replace the first or last few lists with replicates of the desired color.
It looks something like this:
under_color = [0.0, 0.0, 0.0, 1.0] # black (alpha = 1.0)
over_color = [1.0, 1.0, 1.0, 1.0] # white (alpha = 1.0)
all_colors = rainbow_mod(np.linspace(0, 1, 256))
vmin = 0.0
vmax = 100.0
all_colors[:int(np.round((20.0 - vmin) / (vmax - vmin) * 256)), :] = under_color
all_colors[int(np.round((72.0 - vmin) / (vmax - vmin) * 256)):, :] = over_color
rainbow_mod_list = matplotlib.colors.ListedColormap(all_colors.tolist())