0

I have tried to plot four subplots with seaborn from pandas dataframes. My dataframes hold integer values between 1 and 9 and their inverses, so 1/9, 1/8, etc... Therefore I am trying to use a logarithmic color scale, which I have gotten from this question #36898008. I create the lognorm using:

from matplotlib.colors import LogNorm

lognorm = LogNorm(vmin=1.0/9.0,vmax=9.0)

and apply it to my axes with:

axes[i] = sns.heatmap(ldf, ax=axes[i], annot=True, mask=mask, linewidths=.5, norm=lognorm, cbar=None) 

which works fine, unless all values in my dataframe are 1.0, upon which my formatting is just thrown overboard. I am using python 3.6.9, seaborn 0.10.1, matplotlib 3.2.2 and pandas 1.0.5. The image shows the issue pretty well: Image of the issue I have tried including the center=1.0 keyword, which threw all other colorschemes off. Weirdly enough, when i leave out the cbar=None keyword, the color scheme is applied correctly. However, I have a colorbar next to each subplot and cannot get rid of it neatly (so that no ugly empty spaces show up).

Any help would be greatly appreciated.

Cheers

Nico_Mond
  • 33
  • 1
  • 9

1 Answers1

4

It seems that for this to work with Seaborn's heatmap, vmin and vmax need to be set explicitly as parameter to sns.heatmap. Also for the other heatmaps, seaborn seems to recalculate vmin and vmax from the data. When drawing a colorbar these limits are also recalculated, which by accident in this case gives the desired result when vmin and vmax are equal.

from matplotlib import pyplot as plt
from matplotlib.colors import LogNorm
import seaborn as sns
import numpy as np

lognorm = LogNorm(vmin=1.0 / 9.0, vmax=9.0)

fig, axs = plt.subplots(ncols=4, figsize=(12,4))
for i, ldf in enumerate([np.eye(4), np.random.uniform(0, 2, (4, 4))]):
    sns.heatmap(ldf, annot=True, mask=ldf < 1 / 9, linewidths=.5,
                norm=lognorm, cbar=None,
                xticklabels=list('abcd'), yticklabels=list('abcd'), ax=axs[2*i])
    axs[2*i].set_title('without vmin, vmax')
    sns.heatmap(ldf, annot=True, mask=ldf < 1 / 9, linewidths=.5,
                norm=lognorm, vmin=1.0 / 9.0, vmax=9.0, cbar=None,
                xticklabels=list('abcd'), yticklabels=list('abcd'), ax=axs[2*i+1])
    axs[2*i+1].set_title('setting vmin, vmax')
plt.show()

example plot

When adding a colorbar, the limits for the LogNorm are also recalculated if they are not explicitly set again:

plot with colorbars

JohanC
  • 71,591
  • 8
  • 33
  • 66