Search code examples
pythonmatplotlibseabornheatmapcolorbar

How to assign a color to a specific value on a heatmap


I am making a heatmap in seaborn. I am using 'viridis', but I modify it slightly so some of the values get particular colors. In my MWE, .set_over is used to set the values above 90 to 'black', and .set_under is used to set the values below 10 to 'white'. I also mask out part of the heatmap. This all works fine.

How can I also map a middle range value, 20, to 'orange', and without effecting the current colorbar appearance? As you can see, .set_over, and .set_under do not change the colorbar appearance.

import matplotlib
import seaborn as sns
import numpy as np
np.random.seed(7)
A = np.random.randint(0,100, size=(20,20))
mask_array = np.zeros((20, 20), dtype=bool)
mask_array[:, :5] = True
cmap = matplotlib.colormaps["viridis"]
# Set the under color to white
cmap.set_under("white")
# Set the voer color to white
cmap.set_over("black")
# Set the background color

g = sns.heatmap(A, vmin=10, vmax=90, cmap=cmap, mask=mask_array)
# Set color of masked region
g.set_facecolor('lightgrey')

enter image description here

I have seen Map value to specific color in seaborn heatmap, but I am not sure how I can use it to solve my problem.


Solution

  • Pulling from this answer, here is a solution that uses a mask rather than a custom colorbar:

    import matplotlib
    import seaborn as sns
    import numpy as np
    from matplotlib.colors import ListedColormap
    
    np.random.seed(7)
    A = np.random.randint(0,100, size=(20,20))
    mask_array = np.zeros((20, 20), dtype=bool)
    mask_array[:, :5] = True
    # cmap = matplotlib.colormaps["viridis"]
    cmap = matplotlib.cm.get_cmap('viridis')
    
    
    # Set the under color to white
    cmap.set_under("white")
    
    # Set the voer color to white
    cmap.set_over("black")
    
    # Set the background color
    
    g = sns.heatmap(A, vmin=10, vmax=90, cmap=cmap, mask=mask_array)
    # Set color of masked region
    g.set_facecolor('lightgrey')
    
    special_data = np.ma.masked_where(A==20, A)
    sns.heatmap(special_data, cmap=ListedColormap(['orange']), 
                mask=(special_data != 1), cbar=False)