3

This is a follow-up question to: Heatmap of a triangular matrix (or a sparse matrix) (where also the code is taken from)

What I want to achieve (Excel draft):

What I want to achieve

What I got so far (see code at bottom):

What I got so far

What is missing:

  • Axis description with "Some Text"
  • Removing the "xxx" hack to get the first column being recognized as strings

Possible solution for removing the "xxx" hack: I found that "automatic column numbering" was done here: Diverging color scale for a table heatmap and my dream solution would be not only incorporating it to my heatmap but also extending it with "automatic row numbering".

Current Code:

\documentclass{standalone}
\usepackage{colortbl}
\usepackage{pgfplots}
\usepackage{pgfplotstable}

\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={%
                %
                \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 http://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
            }%
        }%
    }
}

\begin{document}


    \vrule\pgfplotstabletypeset[%
    color cells={min=365,max=375,textcolor=black},
    /pgfplots/colormap={orangewhiteorange}{rgb255=(255,170,0) color=(white) rgb255=(255,170,0)},
    /pgf/number format/fixed,
    /pgf/number format/precision=0,
    col sep=comma,
    columns/xxx/.style={reset styles,string type}%
    ]{%%%%%%%
        xxx, 0, 1, 2, 3, 4, 5, 6
        0, 370.8, 371.2, 371.1, 370.9, 371.2, 371.6, 372.0
        1, 370.4, 370.3, 370.4, 370.7, 370.8, 371.4, 371.5
        2, 370.9, , 370.7, 370.9, 370.8, 371.2, 372.1
        3, 371.0, , , 368.1, 371.1, 368.8, 371.3
        4, 370.9, , , , 371.1, 371.4, 371.4
        5, 371.7, , , , , 371.1, 371.4
        6, 372.0, , , , , , 371.2
    }\vrule
\end{document}

Any help is appreciated!

3

Here is a way to do this by extending my code from How to interpolate two colors in a cell? to produce:

enter image description here

Here is the code:

  \documentclass{article}
  \usepackage[table,x11names]{xcolor}
  \usepackage{collcell}
  \usepackage{array}
  \usepackage{tikz}
  \usepackage{pgfkeys}
  \usepackage{graphicx}

  % set up pgfkeys for controlling heat specifications
  \pgfkeys{/heat/.is family, /heat,
      Max colour/.initial = Green4,
      Min colour/.initial = Red1,
      max colour/.initial = SpringGreen3,
      min colour/.initial = Yellow1,
      text colour/.initial = black,
      Min color/.style = {Min colour=#1},% for our friends who can't spell
      Max color/.style = {Max colour=#1},
      min color/.style = {min colour=#1},
      max color/.style = {max colour=#1},
      text color/.style = {text colour=#1},
      min/.initial = -1,
      max/.initial = 1,
      slider/.code={%
         \tikz{\shade[left color=\HVal{min colour},%
                      right color=\HVal{max colour}]%
            (current page.south west) rectangle ++(#1,12pt);
         }%
      }%
  }
  \newcommand\Heatset[1]{\pgfkeys{/heat, #1}}
  \newcommand\HVal[1]{\pgfkeysvalueof{/heat/#1}}

  \newcolumntype{H}{>{\collectcell\Heat}r<{\endcollectcell}}
  \newcommand\Heat[1]{% \Heat{number in the interval [min, max] }
    \if\relax\detokenize{#1}\relax% empty cell
    \else%
      \pgfmathparse{int(100*(#1-\HVal{min})/(\HVal{max}-\HVal{min}))}% map number to [0,100]
      \ifnum\pgfmathresult>100% too big
        \edef\HeatCell{\noexpand\cellcolor{\HVal{Max colour}}}%
      \else\ifnum\pgfmathresult<0% too small
          \edef\HeatCell{\noexpand\cellcolor{\HVal{Min colour}}}%
        \else% between min and max
          \edef\HeatCell{\noexpand\cellcolor{\HVal{max colour}!\pgfmathresult!\HVal{min colour}}}%
        \fi%
      \fi%
      \HeatCell\textcolor{\HVal{text colour}}{$#1$}%
    \fi%
  }

  \begin{document}

  \Heatset{min=370,   % maximum value
           max=372,   % minimum value
           max colour=Burlywood2, % colour at maximum
           min colour=Snow1,      % colour at minimum
           Min colour=OrangeRed1, % colour for values below min
           Max colour=SeaGreen3   % colour for values above max
  }

  \begin{tabular}{ cc *7H }
          &  \multicolumn8c{\textsf{Some text}}\\
          & &\multicolumn1c{0}&\multicolumn1c{1}&\multicolumn1c{2}&\multicolumn1c{3}
            &\multicolumn1c{4}&\multicolumn1c{5}&\multicolumn1c{6}\\
          & 0& 370.8& 371.2& 371.1& 370.9& 371.2& 371.6& 372.0\\
          & 1& 370.4& 370.3& 370.4& 370.7& 370.8& 371.4& 371.5\\
          & 2& 370.9& & 370.7& 370.9& 370.8& 371.2& 372.1\\
          \rotatebox{90}{\makebox[0pt]{\textsf{Some text}}}
          & 3& 371.0& & & 368.1& 371.1& 368.8& 371.3\\
          & 4& 370.9& & & & 371.1& 371.4& 371.4\\
          & 5& 371.7& & & & & 371.1& 371.4\\
          & 6& 372.0& & & & & & 371.2\\
  \end{tabular}

  \end{document}

Some comments:

  • In the code from How to interpolate two colors in a cell?, the colours etc can be set using the \Heatset command. The relevant lines in the MWE are:

    \Heatset{min=370,   % maximum value 
           max=372,   % minimum value
           max colour=Burlywood2, % colour at maximum
           min colour=Snow1,      % colour at minimum
           Min colour=OrangeRed1, % colour for values below min
           Max colour=SeaGreen3   % colour for values above max
    }
    
  • The text along the top is easy: just put it inside a \multicolumn

  • The side at the side is slightly trickier. The \rotatebox command from the graphicx package lets you rotate text but if you do this naively then the fourth row of the table with have the same height as some text. To get around this I have used \makebox to put the text in a box of width zero.
  • The code \if\relax\detokenize{#1}\relax is a standard way to test if #1 is empty
  • If the number is above max or below min then the corresponding Max/Min colour is printed...there's no shading here

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.