Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Export seaborn heatmap to full pgf

I'm trying to plot a heatmap with seaborn and export it to pgf for easy import in Latex. This works more or less, the only thing that is bothering me is that the bar for the colours is exported as an extra png.

So if I run the export to pgf I get the following:

  • test.pgf
  • test-img0.png

This is definitely undesirably as a png is not scaling well. Some MWE:

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

df = pd.DataFrame.from_csv("test.csv", sep=',')

sns.set('paper', 'white', rc={'font.size': 10, 'axes.labelsize': 10, 'legend.fontsize': 8, 'axes.titlesize': 10,
                              'xtick.labelsize': 8,
                              'ytick.labelsize': 8, "pgf.rcfonts": False})
plt.rc('font', **{'family': 'serif', 'serif': ['Times']})
plt.rc('text', usetex=True)
fig = plt.figure()
ax = sns.heatmap(df, linewidths=.5)
fig.savefig('test.pdf')
fig.savefig('test.pgf')

And the content of test.csv:

0,1,2,3,4
1,1,1,1,1
2,2,2,2,2
3,3,3,3,3

Does anyone have a solution to include the colour bar into the pgf output?

like image 574
Patrick Avatar asked Jun 20 '17 10:06

Patrick


People also ask

How do I save a heatmap image?

To create a nice screenshot of your heatmap can be challenging especially on your mobile or small device. You can now click the 💾 button on the heatmap to save the map as an image. The map will scale to selected size using the center and zoom level. So you can create a larger screenshot then your screen.


1 Answers

I discovered some peculiarities in the libraries that export to pgf/tikz.

First, in matplotlib, the quadmesh (i.e. the heatmap) is exported correctly to pgf, but the colorbar is exported as png (what the op encountered).

I tried the same thing with the matplotlib2tikz library. in this case, the quadmesh is exported as a png, but the colormap can be exported correctly. However, If you suppress the heatmap, for example by plotting the colormap to a separate Axes and clearing the heatmap axes, the colorbar is exported as png.

So if you combine the output of two exports, you can have them both.

The heatmap:

import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
df = pd.DataFrame.from_csv("test.csv", sep=',')

sns.set('paper', 'white',
        rc={'font.size': 10, 'axes.labelsize': 10,
            'legend.fontsize': 8, 'axes.titlesize': 10,
            'xtick.labelsize': 8,'ytick.labelsize': 8, 
            "pgf.rcfonts": False,
           })
plt.rc('font', **{'family': 'serif', 'serif': ['Times']})
plt.rc('text', usetex=True)
fig, ax = plt.subplots(figsize=(6,6))
ax = sns.heatmap(df, linewidths=.5, ax=ax, cbar=False)
fig.savefig('heatmap_nocbar.pgf')

Note that I suppress the plotting of the colorbar with cbar=False

Then get the colorbar:

import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
from matplotlib2tikz import save as tikz_save

df = pd.DataFrame.from_csv("test.csv", sep=',')

sns.set('paper', 'white',
        rc={'font.size': 10, 'axes.labelsize': 10,
            'legend.fontsize': 8, 'axes.titlesize': 10,
            'xtick.labelsize': 8,'ytick.labelsize': 8, 
            "pgf.rcfonts": False,
           })
plt.rc('font', **{'family': 'serif', 'serif': ['Times']})
plt.rc('text', usetex=True)
fig, ax = plt.subplots()
ax = sns.heatmap(df, linewidths=.5, ax=ax, )
tikz_save('colormap.tex', figure=fig, strict=True)

The solution now requires some dirty work. I am aware that this is really not good practice, but this is the only way I could find.

In the colormap.tex file, you need to delete all the lines except the ones needed for the colormap.

The beginnings of colormap.tex:

\begin{tikzpicture}

\begin{axis}[

... % definition of axis: delete these lines

colorbar,
colormap={mymap}{[1pt]
...

So that you get this:

\begin{tikzpicture}

\begin{axis}[
hide axis,
colorbar,
colormap={mymap}{[1pt]
...

At the end of the file, delete everything between the closing of the square brackets and \end{axis}:

]
... %delete these lines
\end{axis}

This change in the file can be automatised, I included an example in the code on github

In your main tex file, you can add these two figures

\input{heatmap_nocbar.pgf}
\input{colorbar.tex}

If you want a full working example and full outputs, I have put everything from this answer on github.

This is probably far from a perfect answer for you, but I lack the python skills to dive deeper in the backends of matplotlib and matplotlib2tikz to give a nicer example.

like image 65
Daan Avatar answered Sep 30 '22 23:09

Daan