Search code examples
pythonmatplotlibcolorbarcolormapnorm

How to create a linear colormap with color defined at specific values with matplotlib?


I would like to create a colormap that fade linearly through colors defined for specific values. Below here is my Minimal Non Working Example.

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt

data = np.random.uniform(0, 10, (10, 10))

values = [0., 0.8, 1., 10.]
colors = ["#ff0000", "#00ff00", "#0000ff", "#cccccc"]

I have the feeling this can be solved by using cmap and norm switches when plotting with imshow but I could not succeed to have a smooth gradient of colors passing by defined colors at values.

cmap = mpl.colors.ListedColormap(colors, name="mycmap")
norm = mpl.colors.BoundaryNorm(values, len(colors))

fig, axe  = plt.subplots()
cmap_ = axe.imshow(data, aspect="auto", origin="upper", cmap=cmap, norm=norm)
cbar = fig.colorbar(cmap_, ax=axe)

Also the scale is then non linear.

enter image description here

How can I setup this colormap using the provided values and colors above?


Solution

  • Here is the current solution I have found to solve my problem:

    import numpy as np
    import matplotlib as mpl
    import matplotlib.pyplot as plt
        
    def get_colormap(values, colors, name="custom"):
        values = np.sort(np.array(values))
        values = np.interp(values, (values.min(), values.max()), (0., 1.))
        cmap = mpl.colors.LinearSegmentedColormap.from_list(name, list(zip(values, colors)))
        return cmap
    
    data = np.random.uniform(0, 10, (10, 10))
    values = np.array([0., 0.8, 1., 10.])
    colors = ["#ff0000", "#00ff00", "#0000ff", "#cccccc"]
    cmap_ = get_colormap(values, colors)
    
    fig, axe  = plt.subplots()
    cmap = axe.imshow(data, aspect="auto", origin="upper", cmap=cmap_)
    cbar = fig.colorbar(cmap, ax=axe)
    

    Not straightforward but functional. I'll keep the question unanswered to leave opportunity to best solution to come.

    enter image description here