8

I am trying to give a table cell a grayscale color value based on it's numeric value. So far I have the following code

\documentclass{article}
\usepackage{fp,xcolor,colortbl}
\FPeval{\resb}{0.5}

\newcommand{\he}[1]{%
    \FPeval{\resa}{2 * #1}%
    \cellcolor[gray]{\resa}%
    #1 
}

\begin{document}
\begin{tabular}{| c | c | c |}
    \hline
    \he{0.1} & \he{0.2} & \he{0.3} \\
    \hline
    \he{0.5} & \he{0.8} & \he{1.0} \\
    \hline
\end{tabular}
\end{document}

The tables contain all floating point numbers. The error I get is :

Undefined control sequence.
<argument> \resa 

Is there a way I can use the result from the FPeval to color the cell?

6

You could add the line

\xdef\resa{\resa}%%

to your code. But things still won't compile properly because your multiplier gets you out of the range from 0 to 1.

\documentclass{article}
\usepackage{fp,xcolor,colortbl}
\FPeval{\resb}{0.5}

\newcommand{\he}[1]{%
    \FPeval{\resa}{2 * #1}%
    \xdef\resa{\resa}%%
    \cellcolor[gray]{\resa}%
    #1 
}

\begin{document}

\begin{tabular}{| c | c | c |}
    \hline
    \he{0.1} & \he{0.2} & \he{0.3} \\
    \hline
    \he{0.5} & \he{0.8} & \he{1.0} \\
    \hline
\end{tabular}

\end{document}

To get a compilable version I wrote

\documentclass{article}
\usepackage{fp,xcolor,colortbl}
\FPeval{\resb}{0.5}

\newcommand{\he}[1]{%
    \FPeval{\resa}{2 * #1}%
    \xdef\resa{\resa}%%
    \ifdim\resa pt>1pt\relax
      \gdef\resa{1}%%
    \fi
    \cellcolor[gray]{\resa}%
    #1 
}

\begin{document}

\begin{tabular}{| c | c | c |}
    \hline
    \he{0.1} & \he{0.2} & \he{0.3} \\
    \hline
    \he{0.5} & \he{0.8} & \he{1.0} \\
    \hline
\end{tabular}

\end{document}
6

The following example solves the issue by expanding \resa before \cellcolor is expanded and looks at its arguments.

The second problem is, the range for the color model gray is between 0 and 1 inclusively. The values 0.8 and 1.0 exceed this, when multiplied by 2. Therefore the example checks the result and limits it to 1 if necessary.

\documentclass{article}
\usepackage{fp,xcolor,colortbl}

\newcommand{\he}[1]{%
    \FPeval{\resa}{2 * #1}%
    \ifdim\resa pt>1pt %
      \def\resa{1}%
    \fi
    \edef\processme{\noexpand\cellcolor[gray]{\resa}}%
    \processme
    #1%
}

\begin{document}
\begin{tabular}{| c | c | c |}
    \hline
    \he{0.1} & \he{0.2} & \he{0.3} \\
    \hline
    \he{0.5} & \he{0.8} & \he{1.0} \\
    \hline
\end{tabular}
\end{document}

Result

And a version, where all the math is done by fp means. Also the text color is switched to white, if the background color is getting to dark to maintain readability.

\documentclass{article}
\usepackage{fp,xcolor,colortbl}

\newcommand{\he}[1]{%
    \FPeval{\resa}{max(0, min(1, 2 * #1))}%
    \edef\processme{\noexpand\cellcolor[gray]{\resa}}%
    \processme
    \FPiflt{\resa}{0.5}%
      \color{white}%
    \fi
    #1%
}

\begin{document}
\begin{tabular}{| c | c | c |}
    \hline
    \he{0.1} & \he{0.2} & \he{0.3} \\
    \hline
    \he{0.5} & \he{0.8} & \he{1.0} \\
    \hline
\end{tabular}
\end{document}

Result

Still, there is room for improvement. The number result has lots of unnecessary zeros at both ends, which can be shortened, e.g.:

0.200000000000000000 ⇒ .2
0.400000000000000000 ⇒ .4
1.000000000000000000 ⇒ 1

The zeroes at the end can be removed by \FPclip to 0.2, 0.4 and 1.

Package thepdfnumber goes a step further and provides \thepdfnumber for shortening the decimal numbers at both ends to get .2, .4 and 1. Even better, \thepdfnumberNormZeroOne takes care of the range condition for the gray values:

\documentclass{article}
\usepackage{fp,xcolor,colortbl}

\usepackage{thepdfnumber}

\newcommand{\he}[1]{%
    \FPeval{\resa}{2 * #1}%
    \edef\processme{%
      \noexpand\cellcolor[gray]{\thepdfnumberNormZeroOne\resa}%
    }%
    \processme
    \FPiflt{\resa}{0.5}%
      \color{white}%
    \fi
    #1%
}

\begin{document}
\begin{tabular}{| c | c | c |}
    \hline
    \he{0.1} & \he{0.2} & \he{0.3} \\
    \hline
    \he{0.5} & \he{0.8} & \he{1.0} \\
    \hline
\end{tabular}
\end{document}
  • 1
    Almost simultaneously answered. Interesting to see how we do things the same way and how we don't. – A.Ellett Apr 25 '15 at 20:45
  • As far as I can see, \cellcolor[gray]{\resa} will work, provided \resa expands to a proper value. – egreg Apr 25 '15 at 21:11
  • @egreg Macro \resa is defined inside the cell group. \cellcolor stores the color setting in a global macro via \gdef, thus \resa is not expanded. Then after the cell is processed and stored in a box, colortbl sets the cell background and the box, but the cell background color contains \resa, whose definition is lost after processing the cell contents. – Heiko Oberdiek Apr 25 '15 at 21:50
  • Well, my macro is much better, then. ;-) – egreg Apr 25 '15 at 21:58
  • @egreg Expandable calculations can also be done without LaTeX3 and fp by using eTeX: \cellcolor[gray]{\thepdfnumberNormZeroOne{\strip@pt\dimexpr#1pt*2}}. But storing the number in a macro is nicer, especially if it is used more than once as in the more elaborate examples. – Heiko Oberdiek Apr 25 '15 at 22:20
5

A simpler solution using expl3 and its powerful fp module.

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

\ExplSyntaxOn
\NewDocumentCommand{\he}{m}
 {
  \cellcolor[gray]{ \fp_eval:n { min ( 2*#1, 1 ) } }
  #1
 }
\NewDocumentCommand{\hetest}{m}
 {
  \cellcolor[gray]{ \fp_eval:n { min ( 2*#1, 1 ) } }
  \textcolor{red}{#1 ~ -- ~ \fp_eval:n { min ( 2*#1, 1 ) }}
 }
\ExplSyntaxOff

\begin{document}

\begin{tabular}{| c | c | c |}
\hline
\he{0.1} & \he{0.2} & \he{0.3} \\
\hline
\he{0.5} & \he{0.8} & \he{1.0} \\
\hline
\end{tabular}
\qquad
\begin{tabular}{| c | c | c |}
\hline
\hetest{0.1} & \hetest{0.2} & \hetest{0.3} \\
\hline
\hetest{0.5} & \hetest{0.8} & \hetest{1.0} \\
\hline
\end{tabular}

\end{document}

The \hetest command also prints (in red) the argument and the computed color value, for testing purpose.

enter image description here

Variant 1

The argument is printed white if the grayness is below 0.5

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

\ExplSyntaxOn
\NewDocumentCommand{\he}{m}
 {
  \cellcolor[gray]{ \fp_eval:n { min ( 2 * #1 , 1 ) } }
  \fp_compare:nT { 2 * #1 < 0.5 } { \color{white} }
  #1
 }
\ExplSyntaxOff

\begin{document}

\begin{tabular}{| c | c | c |}
\hline
\he{0.1} & \he{0.2} & \he{0.3} \\
\hline
\he{0.5} & \he{0.8} & \he{1.0} \\
\hline
\end{tabular}

\end{document}

Variant 2

The same as before, but the values are stored in fp variables; this may be convenient in case the computations are heavier, for performance reason.

Here I define syntactic sugar \__ecker_cellcolor:n for \cellcolor[gray]{...} so that with a variant we can expand the value at call time, using f expansion.

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

\ExplSyntaxOn
\NewDocumentCommand{\he}{m}
 {
  \ecker_he:n { #1 }
 }

\fp_new:N \l_ecker_resa_fp
\fp_new:N \l_ecker_resb_fp
\cs_new_protected:Npn \ecker_he:n #1
 {
  \fp_set:Nn \l_ecker_resa_fp { 2 * #1 }
  \fp_set:Nn \l_ecker_resb_fp { min ( \l_ecker_resa_fp, 1 ) }
  \__ecker_cellcolor:f { \l_ecker_resb_fp }
  \fp_compare:nT { \l_ecker_resb_fp < 0.5 } { \color{white} }
  #1
 }
\cs_new_protected:Npn \__ecker_cellcolor:n #1
 {
  \cellcolor[gray]{ \fp_eval:n { #1 } }
 }
\cs_generate_variant:Nn \__ecker_cellcolor:n { f }
\ExplSyntaxOff

\begin{document}

\begin{tabular}{| c | c | c |}
\hline
\he{0.1} & \he{0.2} & \he{0.3} \\
\hline
\he{0.5} & \he{0.8} & \he{1.0} \\
\hline
\end{tabular}

\end{document}

Output of variants 1 and 2

enter image description here

0

A simple solution using the xintexpr module from bundle xint:

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

\newcommand\he[1]{%
  \cellcolor[gray]{\xinttheiexpr[2] min(2*#1, 1)\relax}%
  #1%
}

\newcommand\hetest[1]{%
  \cellcolor[gray]{\xinttheiexpr[2] min(2*#1, 1)\relax}%
  \textcolor{red}{#1 -- \xinttheiexpr[2] min(2*#1, 1)\relax}%
}

\begin{document}

\begin{tabular}{| c | c | c |}
\hline
\he{0.1} & \he{0.2} & \he{0.3} \\
\hline
\he{0.5} & \he{0.8} & \he{1.0} \\
\hline
\end{tabular}
\qquad
\begin{tabular}{| c | c | c |}
\hline
\hetest{0.1} & \hetest{0.2} & \hetest{0.3} \\
\hline
\hetest{0.5} & \hetest{0.8} & \hetest{1.0} \\
\hline
\end{tabular}

\end{document}

enter image description here

The macros use \xinttheiexpr [2] which says to produce fixed point numbers with 2 digits after decimal mark.

N.B.: this works because it turns out \cellcolor macro expands at some point its argument, so we don't have to do it beforehand. See comments in Variant2 below for how one could proceed if the used macro was less forgiving than \cellcolor.

Variant 1

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

\newcommand{\he}[1]{%
  \cellcolor[gray]{\xinttheiexpr[2] min ( 2 * #1 , 1 ) \relax}%
  \xintifboolexpr{ 2 * #1 < 0.5 }{\color{white}}{}%
  #1%
}

\begin{document}

\begin{tabular}{| c | c | c |}
\hline
\he{0.1} & \he{0.2} & \he{0.3} \\
\hline
\he{0.5} & \he{0.8} & \he{1.0} \\
\hline
\end{tabular}

\end{document}

enter image description here

Variant 2

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

\makeatletter

\newcommand{\he}[1]{\ecker@he{#1}}

\protected\def\ecker@he #1{%
   \xdef\ecker@he@resa{\xintexpr 2*#1 \relax}%
   \xdef\ecker@he@resb{\xintexpr min(\ecker@he@resa,1) \relax}%
   \cellcolor[gray]{\xinttheiexpr[2] \ecker@he@resb \relax}%
   \xintifboolexpr{ \ecker@he@resb < 0.5 }{\color{white}}{}%
   #1%
}

% if \cellcolor did not f-expand its argument we would have used something
% like, perhaps,
% \protected\def\ecker@cellcolor@f #1{%
%    \expandafter\ecker@cellcolor@n\expandafter{\romannumeral-`0#1}%
% }

% \protected\def\ecker@cellcolor@n #1{%
%    \cellcolor[gray]{#1}%
% }

% and the call would have been
%    \ecker@cellcolor@f{\xinttheiexpr[2] \ecker@he@resb \relax}
% We need the iexpr[2] encapsulation because variable \ecker@he@resb
% was defined with \xintexpr, variant:
% \xdef\ecker@he@resb{\xintiexpr[2] min(\ecker@he@resa,1) \relax}%
% Then we would have done
%    \ecker@cellcolor@f{\xintthe\ecker@he@resb}


% We 
\makeatother

\begin{document}

\begin{tabular}{| c | c | c |}
\hline
\he{0.1} & \he{0.2} & \he{0.3} \\
\hline
\he{0.5} & \he{0.8} & \he{1.0} \\
\hline
\end{tabular}

\end{document}

It produces the same as Variant 1.

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.