Search code examples
python-3.xmatplotlibcolorbarimshow

Matplotlib- Add a color bar below a multi-colored line subplot as shown in the image


I am having a multicolored line plot and I want to add a color bar under it in the same figure like as shown in the image below, Is it possible?

I have attached a color bar image as a reference which I took from another code. My intention here is to use the color bar like a legend for each segment of the line in the plot.

Edit-1: I want to have the color bar using a mappable object such as an image, So don't want to create a new subplot for the sole purpose of the color bar.

Any suggestion is welcome. Thanks in Advance.

Multicoloredline plot Required Colorbar

This is the code for multicolored line plot

import numpy as np    
import matplotlib.pyplot as plt    
from matplotlib.collections import LineCollection
Segments=[[[3,1],[6,1]],[[6,2],[9,2]],[[9,3],[12,3]],[[12,4],[15,4]], [[12,4],[15,4]]]         
Points_1 = np.concatenate([Segments[:-1], Segments[1:]], axis=1) 
lc = LineCollection(Points_1, colors=['r','g','b','y'], linewidths=2)
fig, ax = plt.subplots() 
ax.add_collection(lc)   
ax.autoscale()
plt.show()

Solution

  • This is a workaround I'am using:

    import numpy as np    
    import matplotlib.pyplot as plt    
    from matplotlib.collections import LineCollection
    import matplotlib.colorbar as mcolorbar
    import matplotlib.colors as mcolors
    
    
    
    Segments=[[[3,1],[6,1]],[[6,2],[9,2]],[[9,3],[12,3]],[[12,4],[15,4]], [[12,4],[15,4]]]         
    Points_1 = np.concatenate([Segments[:-1], Segments[1:]], axis=1) 
    lc = LineCollection(Points_1, colors=['r','g','b','y'], linewidths=2)
    
    fig, ax = plt.subplots(2, 1, gridspec_kw={'height_ratios' : [5,1]}) 
    ax[0].add_collection(lc)
    
    bounds = np.linspace(0, 1, 5)[:-1]
    labels = ['Action1', 'Action2', 'Action3', 'Action4']
    ax[0].set_xlim([0, 15])
    ax[0].set_ylim([0, 10])
    cb2 = mcolorbar.ColorbarBase(ax = ax[1], cmap = cmap, orientation = 'horizontal', extendfrac='auto')
    cb2.set_ticks(bounds)
    cb2.set_ticklabels(labels)
    plt.tight_layout()
    plt.show()
    

    enter image description here

    If you specifically want to avoid subplots, you can use a scalar mappable:

    fig, ax = plt.subplots() 
    ax.add_collection(lc)   
    ax.autoscale()
    cmap = mcolors.ListedColormap(['r','g','b','y'])
    sm = plt.cm.ScalarMappable(cmap=cmap) 
    sm.set_array([]) # this line may be ommitted for matplotlib >= 3.1 
    cbar = fig.colorbar(sm, ax=ax, orientation='horizontal',aspect=90)
    bounds = np.linspace(0, 1, 5)[:-1]
    labels = ['Action1', 'Action2', 'Action3', 'Action4']
    ax.set_xlim([0, 15])
    ax.set_ylim([0, 10])
    cbar.set_ticks(bounds)
    cbar.set_ticklabels(labels)
    plt.tight_layout()
    plt.show()
    

    enter image description here