Search code examples
pythonmatplotlibplotcolorbar

Matplotlib Colorbar - Non-Linear


I have created a diverging colorbar with it's midpoint normalised at the median value of the data. I would like to extend the midpoint color ('white') and apply it to the range (+- 15%) from the midpoint, and then have the diverging colorbar continue normally from that point.

My current colorbar is created using the following code:

#Initial ZValues contour plot
Colorbar_min = np.around(ZValues.min()*0.9,0)
Colorbar_max = np.around(ZValues.max()*1.1,0)
Colorbar_mid = np.median(ZValues)


#Colormap
cmap = plt.cm.seismic  # define the colormap
cmaplist = [cmap(i) for i in range(cmap.N)]  # extract all colors from the .seismic map

# create the new colourmap
cmap = mpl.colors.LinearSegmentedColormap.from_list('Custom cmap', cmaplist, cmap.N)

# define the bins and normalize
bounds = np.linspace(Colorbar_min, Colorbar_max, 30)
norm = mpl.colors.BoundaryNorm(bounds, cmap.N)

Chosen_CS = ax.tricontourf(Chosen_tri_refi, Chosen_Z_refi, cmap=cmap, levels=bounds,
                           norm=MidpointNormalize(midpoint=Colorbar_mid, vmin=Colorbar_min, vmax=Colorbar_max))

#Create a second axis for the colorbar
ax2 = fig.add_axes([0.87, 0.12, 0.04, 0.75]) #The numbers in the square brackets of add_axes refer to [left, bottom, width, height], where the coordinates are just fractions that go from 0 to 1 of the plotting area.
cb = mpl.colorbar.ColorbarBase(ax2, cmap=cmap, norm=MidpointNormalize(midpoint=Colorbar_mid, vmin=Colorbar_min, vmax=Colorbar_max),spacing='uniform', ticks=bounds, boundaries=bounds, format='%1i')
cb.set_label('ZValues', fontsize=7, weight="bold", rotation=270, labelpad=14)

Example


Solution

  • You can create your custom colormap with a white midrange color at 50 ± 15 % by inserting a white section (i.e. 1. for all three colors) from .5 - .15 to .5 + .15 like so:

    import matplotlib.pyplot as plt
    import matplotlib as mpl
    
    seismic_cdict = plt.cm.seismic._segmentdata
    cdict = dict()
    for c in seismic_cdict:
        cdict[c] = [t for t in seismic_cdict[c] if t[0] < .35] + \
                       [(.35,1.,1.), (.65,1.,1.)] + \
                       [t for t in seismic_cdict[c] if t[0] > .65]
    custom_cmap = mpl.colors.LinearSegmentedColormap('Custom cmap', cdict)
    
    fig, ax = plt.subplots(figsize=(8, 1))
    mpl.colorbar.ColorbarBase(ax, cmap=custom_cmap, orientation='horizontal')
    

    enter image description here