1

How to create pgfplotstable confusion matrix ?

Situation

I want to create a confusion matrix (for example like this), reading data from a file and displaying it flexibly. Moreover, I found these two:

which have all features that only need to be combined. However, I was unable to do so (for MWE, where I tried to mingle the code together, see below). I would like to keep the pgfplotstable command for its options (colormaps, easy setup of min and max).

The MWE-Result:

Problem

The Problem is, that I don't know how to combine the two aforementioned MWEs. I don't really know how the colormap is applied in the first, the scaling is done or how the text is hidden in the second. The scale-method described there (\resizebox as well) does not allow for specific sizes, i.e. sx=2, sy=100 (mostly squares). I am aware of this post, but would prefer to use colormaps.

Question

How to create colormap-colored pgfplotstable confusion matrix with specifically set cell sizes (row heights together with column width) ?

MWE
% https://tex.stackexchange.com/a/83865/

\documentclass{standalone}
\usepackage[svgnames]{xcolor}
\usepackage{colortbl}
\usepackage{pgfplots}
\usepackage{pgfplotstable}

\usepackage{tikz}    

\usepgfplotslibrary{colormaps}

\pgfplotstableset{
    /color cells/min/.initial=0,
    /color cells/max/.initial=1000,
    /color cells/textcolor/.initial=,
    %
    % Usage: 'color cells={min=<value which is mapped to lowest color>, 
    %   max = <value which is mapped to largest>}
    color cells/.code={%
        \pgfqkeys{/color cells}{#1}%
        \pgfkeysalso{%
            postproc cell content/.code={%
                % inserted by me: https://tex.stackexchange.com/a/123728
                \pgfkeysalso{@cell content=\rule{0cm}{2.4ex}}
                %
                \begingroup
                %
                % acquire the value before any number printer changed
                % it:
                \pgfkeysgetvalue{/pgfplots/table/@preprocessed cell content}\value
                \ifx\value\empty
                    \endgroup
                \else
                \pgfmathfloatparsenumber{\value}%
                \pgfmathfloattofixed{\pgfmathresult}%
                \let\value=\pgfmathresult
                %
                % map that value:
                \pgfplotscolormapaccess
                    [\pgfkeysvalueof{/color cells/min}:\pgfkeysvalueof{/color cells/max}]
                    {\value}
                    {\pgfkeysvalueof{/pgfplots/colormap name}}%
                % now, \pgfmathresult contains {<R>,<G>,<B>}
                % 
                % acquire the value AFTER any preprocessor or
                % typesetter (like number printer) worked on it:
                \pgfkeysgetvalue{/pgfplots/table/@cell content}\typesetvalue
                \pgfkeysgetvalue{/color cells/textcolor}\textcolorvalue
                %
                % tex-expansion control
                % see https://tex.stackexchange.com/questions/12668/where-do-i-start-latex-programming/27589#27589
                \toks0=\expandafter{\typesetvalue}%
                \xdef\temp{%
                    \noexpand\pgfkeysalso{%
                        @cell content={%
                            \noexpand\cellcolor[rgb]{\pgfmathresult}%
                            \noexpand\definecolor{mapped color}{rgb}{\pgfmathresult}%
                            \ifx\textcolorvalue\empty
                            \else
                                \noexpand\color{\textcolorvalue}%
                            \fi
                            \the\toks0 %
                        }%
                    }%
                }%
                %
                \endgroup
                %
                \temp
                \fi
            }%
        }%
    }
}

% https://tex.stackexchange.com/a/148141
\pgfplotscreatecolormap{test}{
    [1pt] % colormap steps: 1pt
    color(-20pt)=(red);
    color(-10pt)=(red!10!white);
    color(0pt)=(white);
    color(10pt)=(green!10!white);
    color(20pt)=(green);
}

\begin{document}

\pgfplotstableread[col sep=comma]{
 50, -100, -70, -10
-20,    0, 100,  20
  5,   30,  40, 800
  3,   30,  50,  70
}\mymatrix

\pgfplotstabletypeset[
    col sep=comma,
    /pgfplots/colormap name=test,
    color cells={
        min=-100,
        max=100
    },
]\mymatrix

\end{document}
1

I do not tend to add multiple answers. However, since only under the comments to the original answer the question got redefined, here is a new one. It has a new way of transforming the data from a matrix of data values to a table that can be plotted with matrix plot. (Since pgfplots fpu has problems with integers, this post is used.) This answer is more on explaining how this works than producing a catchy confusion matrix. The steps are

  1. Read the matrix data.
  2. Create a new table with \pgfplotstablenew. An essential part is the function myentry that can be used in create col/expr.
  3. Use the new table in a matrix plot.

Here is the code, which also typesets the data in steps 1 and 2.

\documentclass{article}
\usepackage{subcaption}
\usepackage{xint}
\usepackage{pgfplots}
\usetikzlibrary{pgfplots.colormaps}
\pgfplotsset{compat=1.16}
\usepackage{pgfplotstable}
% https://tex.stackexchange.com/questions/34424/how-do-i-calculate-n-modulo-3-in-latex#comment993828_34449
\def\moduloop#1#2{\ifnum\numexpr(#1-(#1/#2)*(#2))\relax<0(#1-(#1/#2)*(#2)+#2)\else(#1-(#1/#2)*(#2))\fi}
\def\truncdiv#1#2{((#1-\moduloop{#1}{#2})/(#2))}
\begin{document}
\pgfplotstableread[col sep=comma]{
 50, -100, -70, -10
-20,    0, 100,  20
  5,   30,  40, 800
  3,   30,  50,  70
}\mymatrix
\pgfplotstablegetrowsof{\mymatrix}%
\pgfmathtruncatemacro{\numrows}{\pgfplotsretval}%
\pgfplotstablegetcolsof{\mymatrix}%
\pgfmathtruncatemacro{\numcols}{\pgfplotsretval}%
\pgfmathtruncatemacro{\numnew}{\numrows*\numcols}%
\pgfmathdeclarefunction{myentry}{2}{%
\begingroup
\pgfkeys{/pgf/fpu,/pgf/fpu/output format=fixed}%
\pgfmathtruncatemacro{\myx}{#1}%
\pgfmathtruncatemacro{\myy}{#2}%
\pgfplotstablegetelem{\myy}{[index]\myx}\of\mymatrix%
\let\pgfmathresult\pgfplotsretval%
\pgfmathsmuggle\pgfmathresult
\endgroup}%

\pgfplotstablenew[
    create on use/y/.style={create col/expr={\the\numexpr\moduloop{\pgfplotstablerow}{\numrows}}},
    create on use/x/.style={create col/expr={\the\numexpr\truncdiv{\pgfplotstablerow}{\numcols}}},
    create on use/C/.style={create col/expr={myentry(\the\numexpr\truncdiv{\pgfplotstablerow}{\numcols},\the\numexpr\moduloop{\pgfplotstablerow}{\numrows})}},
    columns={x,y,C}
  ]
  {\numnew}%
  \newtable

\begin{table}
\centering
\begin{subtable}{0.4\textwidth}
\centering\pgfplotstabletypeset\mymatrix
\caption{Input.}
\end{subtable}\quad
\begin{subtable}{0.4\textwidth}
\centering\pgfplotstabletypeset\newtable
\caption{Table computed from input.}
\end{subtable}
\caption{Data.}
\end{table}
\begin{figure}
\centering
\begin{tikzpicture} 
\begin{axis}[axis equal,width=8cm,tick align=outside,
    /pgfplots/colormap/hot,enlarge y limits=0.2,colorbar]
 \addplot [matrix plot,
        nodes near coords,
        nodes near coords style={anchor=center},
        mesh/cols=\numcols,
        point meta=explicit,
] table [meta=C] {\newtable};
\end{axis}
\end{tikzpicture}
\caption{Matrix plot.}
\end{figure}
\end{document}

enter image description here

| improve this answer | |
  • I gladly accept this answer, as it features everything asked for. Except for one thing: limits are a little different here. I needed to add ... point meta min=-100, point meta max=100,... to the \addplot[...] options. – BadAtLaTeXProgramming Apr 9 at 12:25
1

This uses basically the code from your first link and installs a color map. You need to specify meta min and meta max yourself (but this could be changed, if needed), and the various parameters, including the name of the color map, are stored in pgf keys.

\documentclass{article}
\usepackage[table]{xcolor}
\usepackage{pgfplotstable}
% https://tex.stackexchange.com/a/148141
\pgfplotscreatecolormap{test}{
    [1pt] % colormap steps: 1pt
    color(-20pt)=(red);
    color(-10pt)=(red!10!white);
    color(0pt)=(white);
    color(10pt)=(green!10!white);
    color(20pt)=(green);
}


\tikzset{confusion/.cd,
    color map/.initial=hot,
    meta min/.initial=0,
    meta max/.initial=1,
    cell wd/.initial=1ex,
    cell ht/.initial=1ex,
    cell size/.code=\tikzset{confusion/.cd,cell wd=#1,cell ht=#1}
}

\newcommand{\drawgrid}[2][]{%
\begin{tikzpicture}[confusion/.cd,#1]
  \def\pv##1{\pgfkeysvalueof{/tikz/confusion/##1}}%
  \pgfplotstableforeachcolumn#2\as\col{
    \pgfplotstableforeachcolumnelement{\col}\of#2\as\colcnt{%
      \pgfkeys{/pgf/fpu=true,/pgf/fpu/output format=fixed}%
      \pgfmathsetmacro{\mymeta}{min(\pv{meta max},
        max(0,\colcnt-\pv{meta min}))*1000/(\pv{meta max}-\pv{meta min})}%
      \fill[/pgfplots/color of colormap=\mymeta of \pv{color map}]
        (\col*\pv{cell wd},-\pgfplotstablerow*\pv{cell ht})
        rectangle +(\pv{cell wd},\pv{cell ht});
    }
  }
\end{tikzpicture}}

\begin{document}
% read the file
\pgfplotstableread[col sep=comma]{
 50, -100, -70, -10
-20,    0, 100,  20
  5,   30,  40, 800
  3,   30,  50,  70
}\mymatrix

\drawgrid[meta min=-100,meta max=800,cell size=2em]{\mymatrix}

\drawgrid[meta min=-100,meta max=800,cell size=2em,color map=test]{\mymatrix}

\end{document}

enter image description here

| improve this answer | |
  • Thank you for your answer. This looks really good for certain cases, though I can not understand the code well enough, to tell, whether there is an option to still print the entries and 'axis lables' (see this or also that). Could you give a hint how/where these would have to be included ? – BadAtLaTeXProgramming Apr 8 at 20:18
  • @gr4nt3d I was trying to address "how the text is hidden" and the main question "How to create colormap-colored pgfplotstable confusion matrix with specifically set cell sizes (row heights together with column width) ?". To me it seems to be mutually exclusive to have the cell size fixed and to print arbitrary entries since they may overshoot. It is very easy to add these features to the code above, but to design this properly one needs to know where the journey will go. – user194703 Apr 8 at 20:22
  • You are right, I have phrased that part a little ambiguous. I meant to say, that I do not know how to undo the text-hiding part (it happened to me by accident with \pgfkeysalso{@cell content=\rule{0cm}{2.4ex}} -- in hindsight this probably just covers the text). Let's assume we have 3 digits, e.g. at most 1.00 or 100 % as in the links provided in my previous comment, or that the user has to fiddle with the numbers that become larger. – BadAtLaTeXProgramming Apr 8 at 20:33
  • @gr4nt3d To me this seems no to become more and more like a matrix plot, see the pgfplots manual v1.16 pp. 171. This certainly can create the plots of the links of your first comments. Are you aware of this option? – user194703 Apr 8 at 20:38
  • 1
    @gr4nt3d There are various ways to transform the data such that you do not have to worry about that, e.g. tex.stackexchange.com/a/452788 or tex.stackexchange.com/a/516632. – user194703 Apr 8 at 20:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.