Search code examples
pythoncolorbar

Create a common colorbar for multiple subplots in python


I have divided a pandas dataframe in several subplots, as it is described in the following code. Every subplot has a specific colorbar. I want to make a common colorbar for all the subplots. The dataframe comes directly from an exel csv file.

Table_1_pos=df_pos.iloc[0:4,0:13]
Table_2_pos=df_pos.iloc[4:8,0:13]
Table_3_pos=df_pos.iloc[8:12,0:13]        
Table_4_pos=df_pos.iloc[12:16,0:13]        
[![enter image description here][1]][1]fig, axs = plt.subplots(nrows=4, gridspec_kw=dict(width_ratios=[4]),figsize=(15,8))  

ax1=sns.heatmap(Table_1_neg, annot=True, yticklabels=True, xticklabels=False, cbar=True, ax=axs[0], linewidths=1)
ax1.set_yticklabels(ax1.get_yticklabels(), rotation=0)
ax1.tick_params(right=True, left=False, labelright=True, labelleft=False)
bottom_1, top_1 = ax1.get_ylim()
ax1.set_ylim(bottom_1 + 0.5, top_1 - 0.5)
ax1.set_ylabel('Table 4')
ax1.set_ylabel(ax1.get_ylabel(),labelpad=20, rotation=0)        


ax2=sns.heatmap(Table_2_neg, annot=True, yticklabels=True, xticklabels=False, cbar=True, ax=axs[1], linewidths=1)
ax2.set_yticklabels(ax2.get_yticklabels(), rotation=0)
ax2.tick_params(right=True, left=False, labelright=True, labelleft=False)
bottom_2, top_2 = ax2.get_ylim()
ax2.set_ylim(bottom_2 + 0.5, top_2 - 0.5)
ax2.set_ylabel('Table 3')
ax2.set_ylabel(ax2.get_ylabel(),labelpad=20, rotation=0)         

ax3=sns.heatmap(Table_3_neg, annot=True, yticklabels=True, xticklabels=False, cbar=True, ax=axs[2], linewidths=1)
ax3.set_yticklabels(ax3.get_yticklabels(), rotation=0)
ax3.tick_params(right=True, left=False, labelright=True, labelleft=False)
bottom_3, top_3 = ax3.get_ylim()
ax3.set_ylim(bottom_3 + 0.5, top_3 - 0.5)
ax3.set_ylabel('Table 2')
ax3.set_ylabel(ax3.get_ylabel(),labelpad=20, rotation=0) 

ax4=sns.heatmap(Table_4_neg, annot=True, yticklabels=True, xticklabels=True, cbar=True, ax=axs[3], linewidths=1)
ax4.set_yticklabels(ax4.get_yticklabels(), rotation=0)
ax4.tick_params(right=True, left=False, labelright=True, labelleft=False)
bottom_4, top_4 = ax4.get_ylim()
ax4.set_ylim(bottom_1 + 0.5, top_1 - 0.5)        
ax4.set_ylabel('Table 1')
ax4.set_ylabel(ax4.get_ylabel(),labelpad=20, rotation=0) 


cbaxes = fig.add_axes([0.95, 0.1, 0.01, 0.8])     
mappable = axs.get_children()[0]         
plt.colorbar(mappable, ax = [ax1,ax2,ax3,ax4],orientation = 'vertical',cax = cbaxes)

plt.title("Tilt = {tilt}    -     WindDir = {winddir} (neg)  -   Cpnet,comparison".format(tilt=x, winddir=y),horizontalalignment='right',x=-30,y=1, verticalalignment='top')

out_fp_neg_1 = os.path.join(image_dirn, outpattern_neg.format(tilt=x, dir=y))

Subplots with multiple colorbars


Solution

  • If all your subplots use the same range of values, you can use the solution presented by Joe Kington.

    However, from the image, it seems that all subplots do not have the same range. Hopefully, seaborn allow you to define your heatmap minimum and maximum, as well as the axes on which to draw the colorbar.

    Here is a working example:

    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    import seaborn as sns
    
    def main():
        df_pos = pd.DataFrame(
            np.random.random((16,13)) * 2 - 1
        )
        vmin = df_pos.min().min()
        vmax = df_pos.max().max()
    
        fig, axes = plt.subplots(nrows=4, ncols=1, figsize=(15,8))
        fig.subplots_adjust(right=0.8)
        cbar_ax = fig.add_axes([0.85, 0.15, 0.05, 0.7])
        for i, ax in enumerate(axes.flat):
            sns.heatmap(
                data=df_pos.iloc[4*i:4*(i+1), 0:13], ax=ax, vmin=vmin, vmax=vmax, cbar_ax=cbar_ax,
                xticklabels=False, yticklabels=False, annot=True, linewidths=1)
    
        plt.show()
    
    
    if __name__ == '__main__':
        main()
    

    enter image description here