0

After coming across this: Combining two heat maps in seaborn I did the following:

df = pd.DataFrame(np.random.rand(8,1), columns=list("A"))
df2 = pd.DataFrame(np.random.rand(8,1), columns=list("B"))
df3 = pd.DataFrame(np.random.rand(8,4), columns=list("CDEF"))
df4 = pd.DataFrame(np.random.rand(8,1), columns=list("G"))
df5 = pd.DataFrame(np.random.rand(8,1), columns=list("H"))

fig, (ax, ax2, ax3, ax4, ax5) = plt.subplots(figsize=(30, 10), ncols=5)
fig.subplots_adjust(wspace=0.01)

sb.heatmap(df,  ax=ax, cbar=False, cmap = 'coolwarm_r', vmax = 30, vmin = 10, annot = True, fmt = '.2f', annot_kws = {'size':12})
sb.heatmap(df2, ax=ax2, cbar=False, cmap = 'coolwarm_r', vmax = 20, vmin = -10, annot = True, fmt = '.2f', annot_kws = {'size':12})
sb.heatmap(df3, ax=ax3, cbar=False, cmap = 'coolwarm_r', vmax = 50, vmin = 30, annot = True, fmt = '.2f', annot_kws = {'size':12})
sb.heatmap(df4, ax=ax4, cbar=False, cmap = 'coolwarm_r', vmax = 10, vmin = 5, annot = True, fmt = '.2f', annot_kws = {'size':12})
sb.heatmap(df5, ax=ax5, cbar=False, cmap = 'coolwarm_r', vmax = 8, vmin = 2, annot = True, fmt = '.2f', annot_kws = {'size':12})

ax2.set_yticks([])
ax3.set_yticks([])
ax4.set_yticks([])
ax5.set_yticks([])

ax.xaxis.tick_top()  # Put x axis on top
ax2.xaxis.tick_top()  # Put x axis on top
ax3.xaxis.tick_top()  # Put x axis on top
ax4.xaxis.tick_top()  # Put x axis on top
ax5.xaxis.tick_top()  # Put x axis on top

fig.colorbar(ax5.collections[0], ax=ax5, location="right", use_gridspec=False, pad=0.2)
ax.tick_params(rotation=0)  # Do not rotate y tick labels

plt.show()

But I get the following output where the width of each column of the heatmap is not the same:

enter image description here

Is there any way to resize each column (including those 4 columns from that one df in the middle) so that they're all of the same width?

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
user356
  • 303
  • 2
  • 10

2 Answers2

0

Maybe I don't fully understand your question, but what about combining all the data frames and drawing a heat map?enter image description here

df_new = pd.concat([df,df2,df3,df4,df5],axis=1)

sb.heatmap(df_new,  ax=ax, cbar=True, cmap = 'coolwarm_r', annot = True, fmt = '.2f', annot_kws = {'size':12})
r-beginners
  • 31,170
  • 3
  • 14
  • 32
  • Hi, sorry I edited my answer taking out some details thinking it was irrelevant but it's actually pretty relevant - basically for each df I want to define a different vmax and vmin, which is why I wanted to do the separate subplots in the first place – user356 Aug 11 '20 at 09:51
0

The 'width_ratios' of plt.subplot's gridspec_kw sets the ratios between the axes. Note that adding the colorbar to ax5 will take away some of its space which would make it smaller. Therefore, it's easier to create an additional ax for the colorbar. As the axes are very close to each other, a dummy ax can be added to create some padding. As the colorbar ticks only refer to ax5, an idea is to remove them with fig.colorbar(..., ticks=[]).

The code can be a bit easier to maintain using loops.

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

df = pd.DataFrame(np.random.rand(8, 1) * 50, columns=list("A"))
df2 = pd.DataFrame(np.random.rand(8, 1) * 50, columns=list("B"))
df3 = pd.DataFrame(np.random.rand(8, 4) * 50, columns=list("CDEF"))
df4 = pd.DataFrame(np.random.rand(8, 1) * 50, columns=list("G"))
df5 = pd.DataFrame(np.random.rand(8, 1) * 50, columns=list("H"))

dfs = [df, df2, df3, df4, df5]
widths = [len(d.columns) for d in dfs]
fig, axes = plt.subplots(figsize=(20, 7), ncols=7,
                         gridspec_kw={'wspace': 0.01, 'width_ratios': widths + [0.2, 0.1]})

for ax, dfi, vmin, vmax in zip(axes[:len(dfs)], dfs, [10, -10, 30, 5, 2], [30, 20, 50, 10, 8]):
    sns.heatmap(dfi, ax=ax, cbar=False, cmap='coolwarm_r', vmax=vmax, vmin=vmin, annot=True, fmt='.2f',
                annot_kws={'size': 12})
    ax.xaxis.tick_top()  # Put x axis on top
    ax.tick_params(rotation=0)  # Do not rotate y tick labels
    if ax != axes[0]:
        ax.set_yticks([])

fig.colorbar(ax5.collections[0], cax=axes[-1])
axes[-2].axis('off')  # turn dummy as off

plt.show()

example plot

JohanC
  • 71,591
  • 8
  • 33
  • 66
  • Thanks for your answer it helped my with something else, but shouldn't it be `gridspec_kws`, not `gridspec_kw`? That's what worked for me. – Onur Ece Mar 10 '21 at 16:30
  • Well, the [official doc](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.subplots.html) only mentions `gridspec_kw`. Not to be confused with seaborn's [FacetGrid](https://seaborn.pydata.org/generated/seaborn.FacetGrid.html), which does use `gridspec_kws`. – JohanC Mar 10 '21 at 16:41
  • That explains it. I was using FacetGrid. – Onur Ece Mar 10 '21 at 20:48