- The difficulty arises from the requirement to use more than a single mask.
mask_array
, and a mask for A == 20
if the array is only int
, or 20 <= A < 21
if the array is float
.
matplotlib.colors.Colormap
offers only 3 methods for setting colors.
set_under
set_over
set_bad
- Set the color for masked values, which is already used for mask_array
.
with_extremes
- Does the three combined.
cmap = mpl.colormaps['viridis'].with_extremes(bad='orange', under='w', over='k')

- Using these methods doesn't effect the look of the colorbar.
Imports and Sample Data
import numpy as np
import seaborn as sns
import matplotlib as mpl
# set for repeatable sample
np.random.seed(2023)
# random 20 x 20 array
# A = np.random.randint(0, 100, size=(20, 20)) # random integers
A = np.random.random(size=(20, 20)) * 100 # random floats
1. Don't show the sliced columns
- This is the easiest option, because it frees up
mask
# remove the unneeded columns
A = A[:, 5:]
# create the value mask
mask = np.logical_and(A >= 20, A < 21)
# create the colormap with extremes
cmap = mpl.colormaps["viridis"].with_extremes(bad='orange', under='w', over='k')
# plot
g = sns.heatmap(A, vmin=10, vmax=90, cmap=cmap, mask=mask)
# reset the xticklabels to show the correct column labels
_ = g.set_xticks(ticks=g.get_xticks(), labels=range(5, 20))

2. Show all the columns
- This is the more cumbersome option because, like the answer provided by Ben, this requires manually adding a color to
cmap
, and adding a custom colorbar.
- Using
mask
, or any np.nan
values in the array, are colored by set_bad
.
- This reuses the colorbar creation method I previously added to Ben's answer, which came from Standalone colorbar.
- As demonstrated in Creating Colormaps in Matplotlib, a new color can be added into a slice of colors from a resampled colormap.
- This does not get the correct value if
vmin
and vmax
are used, because those options change the range of the colorbar.
# create the column mask
mask = np.zeros((20, 20), dtype=bool)
mask[:, :5] = True # A[:, :5] = np.nan has the same effect
# slice the colors into the range of values in the array
colors = mpl.colormaps["viridis"].resampled(100).colors
# map a specific value range to a color; use a range for floats, and / or set a hight number to resampled
colors[19:21] = mpl.colors.to_rgba('tab:orange')
# create the new colormap with extremes
cmap = mpl.colors.ListedColormap(colors).with_extremes(bad='lightgray', under='w', over='k')
# draw the heatmap
g = sns.heatmap(A, cmap=cmap, mask=mask, cbar=False)
# add a new axes of the desired shape
cb_ax = g.figure.add_axes([0.93, 0.11, 0.025, 0.77])
# attach a new colorbar to the axes without an outline
cb = mpl.colorbar.ColorbarBase(cb_ax, cmap='viridis', norm=mpl.colors.Normalize(10, 90), # vmax and vmin
label=None, ticks=range(10, 91, 10)).outline.set_visible(False)

3. Let the columns and bad values share the color
# create the value mask
mask = np.logical_and(A >= 20, A < 21)
# add the unwanted column to the mask as np.nan
mask[:, :5] = np.nan
# create the colormap with extremes
cmap = mpl.colormaps["viridis"].with_extremes(bad='orchid', under='w', over='k')
# plot
g = sns.heatmap(A, vmin=10, vmax=90, cmap=cmap, mask=mask)
