9

I'm trying to color a cell using its data value. However, when I try to compute some value (using the content of the cell) then the definition of the color color!\somemacro in the \cellcolor does not work. Where the \somemacro stores the result of the computation.

The error I got is:

! Undefined control sequence. blue!\y

Why is this happening? I guess that the problem has to do with the expansion part of the macros, but I don't know how this works. Can someone also explain how/why this happens and how to avoid it?

\documentclass{article}
\usepackage[table]{xcolor}
\usepackage{pgfplotstable}

\pgfplotstableset{
    color cells/.style={
        col sep=comma,
        string type,
        postproc cell content/.code={%
                \pgfkeysalso{@cell content=\rule{0cm}{2.4ex}%
                \pgfmathsetmacro\y{round(##1 * 0.5)}\cellcolor{blue!\y}%
                ##1}%
                }
    }
}

\begin{document}
\begin{table}\caption{Colors}
\centering
\pgfplotstabletypeset[color cells]{
a,b,c,d
50,300,200,100
20,0,100,200
}
\end{table}
\end{document}

1 Answer 1

10

The command \cellcolor doesn't actually set the cell colour there and then, it squirrels it away for later processing. Although my style-file parsing skills were not up to figuring out exactly where it is finally used, a clue as to why your code breaks is that the squirrelling process defines a global macro \CT@cell@color. As it is global, I suspect it will get processed outside the current group. This global macro saves the colour definition as-is: putting \show\CT@cell@color after the \cellcolor declaration (with suitable \makeatletter ... \makeatother) we get the following in the log file:

\CT@cell@color=macro:
->\CT@color {blue!\y }\global \let \CT@cell@color \relax .

So the \CT@cell@color macro saves its argument with the \y intact. But (probably) processes it outside the group in which \y has been set. One might try to make \y global, but I found that that caused problems. The other usual way to avoid these issues is to force \y to be expanded before it is passed to \cellcolor. The simplest way to do that is with an \edef and a temporary macro.

\documentclass{article}
%\url{http://tex.stackexchange.com/q/54872/86}
\usepackage[table]{xcolor}
\usepackage{pgfplotstable}


\pgfplotstableset{
    color cells/.style={
        col sep=comma,
        string type,
        postproc cell content/.code={%
                \pgfkeysalso{@cell content=\rule{0cm}{2.4ex}%
                \pgfmathsetmacro\y{min(100,max(0,round(##1 * 0.5)))}\edef\temp{\noexpand\cellcolor{blue!\y}}\temp%
                ##1}%
                }
    }
}

\begin{document}
\begin{table}\caption{Colors}
\centering
\pgfplotstabletypeset[color cells]{
a,b,c,d
50,300,200,100
20,0,100,200
}
\end{table}
\end{document}

(Note: once I'd gotten that working, it complained about numbers being out of range so I truncated the possible values for \y to within the range [0,100])

table with colours set by contents

1
  • Sorry to ask, but I'm kind of new to this. So the \edef makes the \temp macro to expand to what's inside it when call it, and the \noexpand makes it print the \cellcolor into the global macro, and the \y macro will expand as expected. Did I get it right? I was trying to achieve that behavior but didn't know how. I try putting a naive \expand but didn't work.
    – adn
    May 8, 2012 at 12:15

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .