Search code examples
seabornheatmapaxes

How to change seaborn heatmap tick_params text orientation on some axes and make it fit in the picture completely


I have a seaborn heatmap plot as shown below:

import pandas as pd
from matplotlib import pyplot as plt
import seaborn as sns

results_changed = [['equal','equal','smaller','smaller or equal','greater or equal'],
              ['equal','equal','smaller','smaller','greater or equal'],
              ['greater or equal','equal','smaller or equal','smaller','smaller'],
              ['equal','smaller or equal','greater or equal','greater or equal','equal'],
              ['equal','equal','smaller','equal','equal']]

index = ['axc123abc', 'org567def', 'cf5010wer', 'cm1235ert', 'ext447tyu']
columns = ['axc123abc', 'org567def', 'cf5010wer', 'cm1235ert', 'ext447tyu']

# create a dataframe
res_df = pd.DataFrame(results_changed, columns, index) 

#construct dictionary from ordered list
category_order = ['greater', 'greater or equal', 'equal', 'smaller or equal', 'smaller']    
value_to_int = {j:i for i,j in enumerate(category_order)}    
n = len(value_to_int)  

# discrete colormap (n samples from a given cmap)
cmap = sns.color_palette("flare", n) 
ax = sns.heatmap(res_df.replace(value_to_int), cmap=cmap, vmin=0, vmax=n) 

#modify colorbar:
colorbar = ax.collections[0].colorbar 
colorbar.set_ticks([0.5 + i for i in range(n)])
colorbar.set_ticklabels(category_order)  
ax.tick_params(right=True, top=True, labelright=True, labeltop=True)
plt.tight_layout()
plt.show()  

heatmap_with_left_and_down_tick_descriptions

I would like to make it more readable by adding tick descriptions for axes from each side of the figure (not just bottom and left). I've managed to do that by adding one more line of code as shown below:

import pandas as pd
from matplotlib import pyplot as plt
import seaborn as sns

results_changed = [['equal','equal','smaller','smaller or equal','greater or equal'],
              ['equal','equal','smaller','smaller','greater or equal'],
              ['greater or equal','equal','smaller or equal','smaller','smaller'],
              ['equal','smaller or equal','greater or equal','greater or equal','equal'],
              ['equal','equal','smaller','equal','equal']]

index = ['axc123abc', 'org567def', 'cf5010wer', 'cm1235ert', 'ext447tyu']
columns = ['axc123abc', 'org567def', 'cf5010wer', 'cm1235ert', 'ext447tyu']

# create a dataframe
res_df = pd.DataFrame(results_changed, columns, index) 

#construct dictionary from ordered list
category_order = ['greater', 'greater or equal', 'equal', 'smaller or equal', 'smaller']    
value_to_int = {j:i for i,j in enumerate(category_order)}    
n = len(value_to_int)  

# discrete colormap (n samples from a given cmap)
cmap = sns.color_palette("flare", n) 
ax = sns.heatmap(res_df.replace(value_to_int), cmap=cmap, vmin=0, vmax=n) 

#modify colorbar:
colorbar = ax.collections[0].colorbar 
colorbar.set_ticks([0.5 + i for i in range(n)])
colorbar.set_ticklabels(category_order)  

# newly added code line
ax.tick_params(right=True, top=True, labelright=True, labeltop=True)

plt.tight_layout()
plt.show()  

heatmap_with_all_tick_descriptions

The problem is, these added tick descriptions are not fully visible (due to their length). I'm not sure how to rotate ticks descriptions on particular axes. I would like to have ticks on the upper part positioned vertically (just as those at the bottom are) and ticks on the right side positioned horizontally (just as those on the left are). How can I achieve this and fit the heatmap, axes' tick descriptions and the color bar nicely in the figure? I would appreciate any suggestions.


Solution

  • You can do it like this:

    import pandas as pd
    from matplotlib import pyplot as plt
    import seaborn as sns
    
    results_changed = [['equal','equal','smaller','smaller or equal','greater or equal'],
                  ['equal','equal','smaller','smaller','greater or equal'],
                  ['greater or equal','equal','smaller or equal','smaller','smaller'],
                  ['equal','smaller or equal','greater or equal','greater or equal','equal'],
                  ['equal','equal','smaller','equal','equal']]
    
    index = ['axc123abc', 'org567def', 'cf5010wer', 'cm1235ert', 'ext447tyu']
    columns = ['axc123abc', 'org567def', 'cf5010wer', 'cm1235ert', 'ext447tyu']
    
    # create a dataframe
    res_df = pd.DataFrame(results_changed, columns, index)
    
    # construct dictionary from ordered list
    category_order = ['greater', 'greater or equal', 'equal', 'smaller or equal', 'smaller']
    value_to_int = {j: i for i,j in enumerate(category_order)}
    n = len(value_to_int)
    
    # discrete colormap (n samples from a given cmap)
    cmap = sns.color_palette("flare", n)
    ax = sns.heatmap(res_df.replace(value_to_int), cmap=cmap, vmin=0, vmax=n, cbar_kws=dict(pad=0.2))
    
    # modify colorbar:
    colorbar = ax.collections[0].colorbar
    colorbar.set_ticks([0.5 + i for i in range(n)])
    colorbar.set_ticklabels(category_order)
    
    # newly added code line
    ax.tick_params(right=True, top=True, labelright=True, labeltop=True)
    
    plt.xticks(rotation=90)
    plt.yticks(rotation=0)
    
    plt.tight_layout()
    plt.show()
    

    Output:

    Seaborn heatmap with customised ticks