142

When plotting heatmaps with seaborn (and correlation matrices with matplotlib) the first and the last row is cut in halve. This happens also when I run this minimal code example which I found online.

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

data = pd.read_csv('https://raw.githubusercontent.com/resbaz/r-novice-gapminder-files/master/data/gapminder-FiveYearData.csv')
plt.figure(figsize=(10,5))
sns.heatmap(data.corr())
plt.show()

And get this result (I am not allowed to embed images yet) The labels at the y axis are on the correct spot, but the rows aren't completely there.

A few days ago, it work as intended. Since then, I installed texlive-xetex so I removed it again but it didn't solve my problem.

Any ideas what I could be missing?

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
Flops
  • 1,523
  • 2
  • 11
  • 5

10 Answers10

121

Unfortunately matplotlib 3.1.1 broke seaborn heatmaps; and in general inverted axes with fixed ticks.
This is fixed in the current development version; you may hence

  • revert to matplotlib 3.1.0
  • use matplotlib 3.1.2 or higher
  • set the heatmap limits manually (ax.set_ylim(bottom, top) # set the ylim to bottom, top)
Giovani
  • 175
  • 1
  • 7
ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
  • I have seen this question around but am unfamiliar how to revert back to matplotlib 3.1.0 or set the heatmap limits manually (tried this but still truncated) and can't wait for 3.1.2. How could I revert back to matplotlib 3.1.0? – SozDaneron Aug 06 '19 at 15:17
  • It depends on how you installed matplotlib. E.g. via pip see [this](https://stackoverflow.com/questions/5226311/installing-specific-package-versions-with-pip). – ImportanceOfBeingErnest Aug 06 '19 at 15:20
  • Right, I am still new to PyCharm. Figured it out now, thanks. – SozDaneron Aug 06 '19 at 15:24
  • @ImportanceOfBeingErnest I think you mean setting the plot size by the third option "set the heatmap limits manually". I have tried several sizes of figures empirically, none of them has displayed the heatmap properly. – talha06 Aug 15 '19 at 02:04
  • 1
    @talha06 No I mean the plot limits. If `ax = sns.heatmap(...)`, set `ax.set_ylim(...)` to whatever you need your limits to be. – ImportanceOfBeingErnest Aug 15 '19 at 02:09
  • Did not work for me, the first row is still partially (~half of it) displayed. @ImportanceOfBeingErnest – talha06 Aug 15 '19 at 02:13
  • @talha06 I do not know your limits, but it should work. – ImportanceOfBeingErnest Aug 15 '19 at 02:17
  • I have 7 target classes, so I set the `y` limit to 7. – talha06 Aug 15 '19 at 02:18
  • Edit: Worked when I set a `colormap` explicitly. Thanks for your help, @ImportanceOfBeingErnest. – talha06 Aug 15 '19 at 02:43
  • 3
    For 7 levels I had to use `ax.set_ylim(0 ,7)`. Using just ax.set_ylim(7) left one row halved. – Dzamo Norton Oct 16 '19 at 03:29
  • For those looking to revert the version of matplotlib, use ```pip install 'matplotlib<=3.1.0'```. (of course assuming you use pip). – Sidak Nov 04 '19 at 14:34
  • Setting the heatmap limits manually is good general advice; the answer by Nikhil P below shows a concrete example of how to do this in a more automated way – Quetzalcoatl Oct 20 '21 at 18:05
98

Its a bug in the matplotlib regression between 3.1.0 and 3.1.1 You can correct this by:

import seaborn as sns
df_corr = someDataFrame.corr()
ax = sns.heatmap(df_corr, annot=True) #notation: "annot" not "annote"
bottom, top = ax.get_ylim()
ax.set_ylim(bottom + 0.5, top - 0.5)
liangli
  • 1,151
  • 9
  • 11
Nikhil Pakki
  • 981
  • 6
  • 2
  • This, for instance, did not work me. But to be fair, my problem was different in that an entire row of the heatmap was missing. For me reverting the version, as I mentioned in a comment above, was the only way out. – Sidak Nov 04 '19 at 14:36
  • It works, even though it seems illogical. Why should `bottom` be larger than `top`? – Eric Duminil Jan 19 '20 at 14:18
  • Worked for me. plt.figure(figsize=(5,3)) ax = sn.heatmap(cm, annot=True, fmt='') bottom, top = ax.get_ylim() ax.set_ylim(bottom + 0.5, top - 0.5) plt.xlabel('Prediction') plt.ylabel('Truth') plt.title('Confusion Matrix') – MPJ567 Feb 07 '20 at 20:32
25

Fixed using the above and setting the heatmap limits manually.

First

ax = sns.heatmap(...

checked the current axes with

ax.get_ylim()
(5.5, 0.5)

Fixed with

ax.set_ylim(6.0, 0)
georgeawg
  • 48,608
  • 13
  • 72
  • 95
lbarbus
  • 259
  • 3
  • 2
6

I solved it by adding this line in my code, with matplotlib==3.1.1:

ax.set_ylim(sorted(ax.get_xlim(), reverse=True))

NB. The only reason this works is because the x-axis isn't changed, so use at your own risk with future mpl versions

3

matplotlib 3.1.2 is out - It is available in the Anaconda cloud via conda-forge but I was not able to install it via conda install. The manual alternative worked: Download matplotlib 3.1.2 from github and install via pip

 % curl https://codeload.github.com/matplotlib/matplotlib/tar.gz/v3.1.2 --output matplotlib-3.1.2.tar.gz
 % pip install matplotlib-3.1.2.tar.gz
rustyDev
  • 187
  • 1
  • 12
  • I am not able to update the package. I received this error: `ERROR: Could not install packages due to an EnvironmentError: [WinError 5] Access is denied: 'c:\\users\\w-book\\anaconda3\\lib\\site-packages\\matplotlib\\backends\\_backend_agg.cp37-win_amd64.pyd' Consider using the --user option or check the permissions.` – Jade Cacho Dec 17 '19 at 08:21
  • The above was tried in MacOS. Not familiar with Windows scenario but seems it is a local permission problem. – rustyDev Dec 18 '19 at 15:21
  • Thank you for the response. I ended up installing the older version (matplotlib-3.1.0). – Jade Cacho Dec 19 '19 at 04:25
1

Worked for me:

b, t = plt.ylim()
b += 0.5
t -= 0.5
custom_ylim = (b, t)
plt.setp(axes, ylim=custom_ylim)
Super Mario
  • 923
  • 10
  • 16
1

Downgrade your matplotlib

!pip install matplotlib==3.1.0

and add this line to your plot code :

ax[i].set_ylim(sorted(ax[i].get_xlim(), reverse=True))
 
0

It happens with matplotlib version 3.1.1 as suggested by importanceofbeingernest

Following solved my problem

pip install matplotlib==3.1.0

0

rustyDev is right about conda-forge, but I did not need to do a manual pip install from a github download. For me, on Windows, it worked directly. And the plots are all nice again.

https://anaconda.org/conda-forge/matplotlib

conda install -c conda-forge matplotlib

optional points, not needed for the answer:

Afterwards, I tried other steps, but they are not needed: In conda prompt: conda search matplotlib --info showed no new version info, the most recent info was for 3.1.1. Thus I tried pip using pip install matplotlib==3.1.2 But pip says "Requirement already satisfied"

Then getting the version according to medium.com/@rakshithvasudev/… python - import matplotlib - matplotlib.__version__ shows that 3.1.2 was successfully installed

Btw, I had this error directly after updating Spyder to v4.0.0. The error was in a plot of a confusion matrix. This was mentioned already some months ago. stackoverflow.com/questions/57225685/… which is already linked to this seaborn question.

questionto42
  • 7,175
  • 4
  • 57
  • 90
-2

As @ImportanceOfBeingErnest mentioned, this issue is due to broken seaborn heatmaps in a specific version of matplotlib so simple solution to this problem is to upgrade matplotlib as follows:

pip install --upgrade matplotlib
  • 1
    How does this add anything to the thread? – BigBen Apr 22 '21 at 20:43
  • 1
    I don't see what's unclear about "use matplotlib 3.1.2 or higher," and I disagree with "people don't want to read long explanations here, they just want to skip to the solution/code part." Also, the accepted answer is quite short. This thread has too many answers already as is. – BigBen Apr 23 '21 at 21:34