Search code examples
pythonmatplotlibcolorbar

Custom binned colorbar: can't set tick labels


I'am trying to create my own binned colorbar, but I can't set my own tick labels, that remain fixed.

plt.figure(figsize = (10, 1))

cmapor = plt.get_cmap('jet')
cmap = mcolors.ListedColormap([ i for i in cmapor(np.linspace(0, 1, 5))])
bounds = np.linspace(0, 1, 6)[:-1]
labels = ['0', '2.5', '5', '7.5', '10']
cb2 = mcolorbar.ColorbarBase(plt.gca(), cmap = cmap, orientation = 'horizontal', spacing='proportional', extendfrac='auto')
cb2.ax.set_xticks = bounds
cb2.ax.set_xticklabels = labels

plt.tight_layout()
plt.show()

gives enter image description here

I would like to have no tick label on the last one, and the other ones labeled as mentioned in labels.

Note also that the ticks for 0.2 and 0.4 are not perfectly centered on the separation between the colors .. ?


Solution

  • The main problem is that in cb2.ax.set_xticks = bounds, set_xticks is a function. By executing the equal assignment, you replace that function with an array. But what you really want to do, is to call the function, so you need cb2.ax.set_xticks(bounds). The same happens with set_xticklabels.

    For colorbars, instead of cb2.ax.set_xticks(bounds), recent versions of matplotlib prefer that you'd call cb2.set_ticks(bounds) (although the old way still keeps functioning). Similarly, cb2.set_ticklabels(labels) is now preferred to set the labels.

    About "the ticks for 0.2 and 0.4 are not perfectly centered on the separation": this seems to be some rounding error. Leaving out spacing='proportional' helps here.

    The adapted code, including importing the libraries would look like:

    import numpy as np
    import matplotlib.pyplot as plt
    from matplotlib import colors as mcolors
    from matplotlib import colorbar as mcolorbar
    
    plt.figure(figsize=(10, 1))
    
    cmapor = plt.get_cmap('jet')
    cmap = mcolors.ListedColormap([i for i in cmapor(np.linspace(0, 1, 5))])
    cb2 = mcolorbar.ColorbarBase(plt.gca(), cmap=cmap, orientation='horizontal', extendfrac='auto')
    bounds = np.linspace(0, 1, 6)[:-1]
    
    labels = ['0', '2.5', '5', '7.5', '10']
    cb2.set_ticks(bounds)
    cb2.set_ticklabels(labels)
    plt.tight_layout()
    plt.show()
    

    resulting plot