48

Here is an example that shows a colorbar for each subplot:

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

df = pd.DataFrame(np.random.random((10,10,)))

fig,axn = plt.subplots(2, 2, sharex=True, sharey=True)

for ax in axn.flat:
    sns.heatmap(df, ax=ax)

enter image description here

How can I remove the colorbars for each subplot? I'd like to have only one colorbar that is either vertically or horizontally oriented. I know I have access to each colorbar axes via fig.get_axes()[:-4], but how can I remove it from them entirely from the plot? I don't think there is an option to opt out of drawing the colorbar when heatmap is called.

pbreach
  • 16,049
  • 27
  • 82
  • 120

2 Answers2

80

The cbar parameter controls whether a colorbar should be added, and the cbar_ax parameter can optionally specify the axes where the colorbar should go. So, you could do:

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

df = pd.DataFrame(np.random.random((10,10,)))

fig, axn = plt.subplots(2, 2, sharex=True, sharey=True)
cbar_ax = fig.add_axes([.91, .3, .03, .4])

for i, ax in enumerate(axn.flat):
    sns.heatmap(df, ax=ax,
                cbar=i == 0,
                vmin=0, vmax=1,
                cbar_ax=None if i else cbar_ax)

fig.tight_layout(rect=[0, 0, .9, 1])

(You'll get a warning about tight_layout here, but it actually is correct because we placed cbar_ax explicitly. If you don't like seeing the warning, you can also call tight_layout before plotting, but it won't be as tight).

mwaskom
  • 46,693
  • 16
  • 125
  • 127
  • 8
    Are you sure that this will also synchronize the colors? The way I see it it only will plot the colormap for the first axis, but the colormap will not necessarily be compatible to the other axes. – bayer Jan 25 '16 at 13:22
  • what does this part do `cbar=i == 0` ? Assigning and then comparing to 0 ? why? – Rotkiv May 17 '17 at 22:36
  • 1
    @Rotkiv, this is actually setting `cbar` as equal to `i == 0`, i.e. `cbar = True` if `i == 0`returns `True`. – KevL Nov 09 '17 at 16:19
  • How can I add x and y-axis label instead, 0,1,2---9. – jax Aug 28 '19 at 19:33
  • 6
    @bayer, yes it syncronizes the colors, `vmin=0` and `vmax=1` takes care of that – toto_tico Apr 17 '20 at 14:41
  • 1
    It would be nice to have a way to synchronise the colours automatically, for when you don't know the limits a priori (and e.g. want to use the `robust` option) – oulenz Feb 07 '21 at 12:15
  • This answer is so amazing! I came here to ask how to use tight_layout and this was already answered! Wish I can upvote again! – Yair Daon May 30 '23 at 19:39
6

It's actually not necessary to set cbar_ax to none for the first 3 subplots. You can set cbar_ax=cbar_ax for all 4 subplots and it will just paint the colorbar in the exact same spot 4 times, which dones't affect the look at all.

This works better for those using FacetGrid, e.g. given a dataframe df:

def draw_heatmap(*args, **kwargs):
    data = kwargs.pop('data')
    d = data.pivot(index=args[1], columns=args[0], values=args[2])
    sns.heatmap(d, **kwargs)

g = sns.FacetGrid(df, col='col_name', col_wrap=2, margin_titles=True, sharey=True)

cbar_ax = g.fig.add_axes([.91, .15, .03, .7])
g = g.map_dataframe(draw_heatmap, 'col_col', 'index_col', 'val_col', annot=True, 
                    cmap='Spectral', cbar_ax=cbar_ax, cbar_kws={'label': 'color_bar_label'})
Tim
  • 3,178
  • 1
  • 13
  • 26