3

There is a similar question like mine, but I am not satisfied with the answer, because the axis labels there are coordinates, while I am looking to also have the column and index labels written as text as in seaborn.

This is the output of from seaborn which I want to reproduce (never mind the colormap).

enter image description here

Here's the python code I use to generate an output for pgfplots to use.

import pandas as pd
import seaborn as sns
data = [[3, 10], [2, 15]] 
df = pd.DataFrame(data, columns = ['foo', 'bar'],index = ["foo2","bar2"]) 
sns.heatmap(df,annot=True)

def generate_file(df):
    with open("mwe.dat","w") as f:
        for i in range(len(df.index)):
            for j in range(len(df.columns)):
                f.write("{} {} {}\n".format(j,i,df.values[i][j]))
            f.write("\n")
generate_file(df)

This create mwe.dat with the following content:

0 0 3
1 0 10

0 1 2
1 1 15

And this is my latex mwe for my current solution, lacking the text labels and the values written in the middle:

\documentclass[tikz]{standalone}
\usepackage{pgfplots}
\begin{document}

\begin{tikzpicture}
  \begin{axis}[view={0}{90},
               colorbar,
]
    \addplot3[matrix plot,point meta=explicit] file {mwe.dat};
  \end{axis}
\end{tikzpicture}

\end{document}

This currently outputs this:

enter image description here

So I have two questions:

  • how to add text labels to axes, instead of coordinates?
  • how to write the value in the middle of the cell?

Since I will be using python anyway to generate the original dataframes, it is okay if I need python to actually generate the entire latex code, but I would prefer a solution, where python only generates a data file containing all info needed for the plot (I want to avoid changing things by hand).

fbence
  • 1,585

2 Answers2

4

If you change the Python code to also print the column names and index values:

import pandas as pd
import seaborn as sns
data = [[3, 10], [2, 15]] 
df = pd.DataFrame(data, columns = ['foo', 'bar'],index = ["foo2","bar2"]) 
sns.heatmap(df,annot=True)

def generate_file(df):
    with open("mwe.dat","w") as f:
        f.write("x y z xl yl\n")
        for i,line in enumerate(df.values):
            for j,val in enumerate(line):
                f.write("{} {} {} {} {}\n".format(j,i,val, df.columns[j], df.index[j]))
            f.write("\n")
generate_file(df)

So mwe.dat becomes

x y z xl yl
0 0 3 foo foo2
1 0 10 bar bar2

0 1 2 foo foo2
1 1 15 bar bar2

Then you can set the tick locations and read the ticklabels from the file like in the code below. x/yticklabels from table seems to assume that the file has a header row, hence the addition of that.

nodes near coords, nodes near coords align=center can be used to place the values in the cells.

Note the use of \addplot ... table instead of \addplot ... file.

\documentclass[border=5mm,tikz]{standalone}
\usepackage{pgfplots}
\begin{document}

\begin{tikzpicture}
  \begin{axis}[
     view={0}{90},
     colorbar,
     xtick=data,
     ytick=data,
     xticklabels from table={mwe.dat}{xl},
     yticklabels from table={mwe.dat}{yl},
     yticklabel style={rotate=90}
]
    \addplot3[matrix plot, nodes near coords, nodes near coords align=center] table {mwe.dat};
  \end{axis}
\end{tikzpicture}

\end{document}

enter image description here

Torbjørn T.
  • 206,688
  • I removed point meta=explicit because that caused an error. – Torbjørn T. Jul 28 '19 at 16:27
  • @TorbjørnT. ok, thanks, I'll wait until you conclude this to accept the answer, to have it all rounded up, but this is already pretty cool, thanks – fbence Jul 28 '19 at 18:25
  • @fbence I think x/yticklabels from table assumes the presence of a header row, so the first row was basically skipped, and the second and third row was used. That explains why the order is reversed, as the file had foo, bar, foo, bar. – Torbjørn T. Jul 28 '19 at 19:20
  • @TorbjørnT. perfect, thanks! – fbence Jul 28 '19 at 20:59
3

Here's one way

\documentclass[tikz,border=20pt]{standalone}
\usepackage{pgfplots, filecontents}
\pgfplotsset{compat=1.13}
\begin{document}
\begin{filecontents*}{mwe.dat}
0 0 3
1 0 10

0 1 2
1 1 15
\end{filecontents*}
\begin{tikzpicture}
  \begin{axis}[view={0}{90}, colorbar,hide axis,nodes near coords = {\pgfmathprintnumber\pgfplotspointmeta}]
    \addplot [matrix plot*,point meta=explicit] file {mwe.dat};
    \node[] at (axis cs: -0.010,-.65) {foo};
    \node[] at (axis cs: 0.980,-.65) {bar};
    \node[rotate=90] at (axis cs: -0.59,.01) {bar2};
    \node[rotate=90] at (axis cs: -0.590,1.0) {foo2};
  \end{axis}
\end{tikzpicture}
\end{document}

The output from Gummi is: enter image description here

With respect to your question "how to add text labels to axes, instead of coordinates?" I did hide axis in setting the axis. Then I added nodes with the labels you wanted and positioned them and rotated them where you wanted. As for "how to write the value in the middle of the cell?", I added nodes near coords = {\pgfmathprintnumber\pgfplotspointmeta} in setting up the axis. I'm wondering about the data file matching up with your picture, though, as the numbers are in the wrong row. The colors are in different rows as well.

DJP
  • 12,451