Utilice el resultado de FPeval para colorear una celda de la tabla

Utilice el resultado de FPeval para colorear una celda de la tabla

Estoy intentando darle a una celda de la tabla un valor de color en escala de grises según su valor numérico. Hasta ahora tengo el siguiente código

\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}

Las tablas contienen todos los números de coma flotante. El error que me sale es:

Undefined control sequence.
<argument> \resa 

¿Hay alguna manera de usar el resultado de FPeval para colorear la celda?

Respuesta1

Podrías agregar la línea

\xdef\resa{\resa}%%

a tu código. Pero las cosas aún no se compilarán correctamente porque tu multiplicador te saca del rango de 0 a 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}

Para obtener una versión compilable escribí

\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}

Respuesta2

El siguiente ejemplo resuelve el problema expandiendo \resaantes de \cellcolorexpandirse y analiza sus argumentos.

El segundo problema es que el rango del modelo de color grayestá entre 0 y 1 inclusive. Los valores 0,8 y 1,0 superan esto cuando se multiplican por 2. Por lo tanto, el ejemplo comprueba el resultado y lo limita a 1 si es necesario.

\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}

Resultado

Y una versión, donde todos los cálculos se hacen por fpmedios. Además, el color del texto cambia a blanco si el color de fondo se vuelve demasiado oscuro para mantener la legibilidad.

\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}

Resultado

Aún así, hay margen de mejora. El resultado numérico tiene muchos ceros innecesarios en ambos extremos, que pueden acortarse, por ejemplo:

0.200000000000000000 ⇒ .2
0.400000000000000000 ⇒ .4
1.000000000000000000 ⇒ 1

Los ceros al final se pueden eliminar con \FPclipa 0.2y 0.4.1

El paquete thepdfnumberva un paso más allá y permite \thepdfnumberacortar los números decimales en ambos extremos para obtener .2, .4y 1. Aún mejor, \thepdfnumberNormZeroOnese ocupa de la condición del rango para los valores de gris:

\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}

Respuesta3

Una solución más sencilla utilizando expl3su potente fpmódulo.

\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}

El \hetestcomando también imprime (en rojo) el argumento y el valor de color calculado, con fines de prueba.

ingrese la descripción de la imagen aquí

Variante 1

El argumento se imprime en blanco si el grado de gris es inferior a 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}

Variante 2

Lo mismo que antes, pero los valores se almacenan en fpvariables; Esto puede resultar conveniente en caso de que los cálculos sean más pesados, por motivos de rendimiento.

Aquí defino el azúcar sintáctico \__ecker_cellcolor:npara \cellcolor[gray]{...}que con una variante podamos expandir el valor en el momento de la llamada, usando fla expansión.

\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}

Salida de las variantes 1 y 2.

ingrese la descripción de la imagen aquí

Respuesta4

Una solución simple usando el xintexprmódulo del paquete 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}

ingrese la descripción de la imagen aquí

Las macros utilizan \xinttheiexpr [2]lo que dice producir números de coma fija con 2 dígitos después de la marca decimal.

NB: esto funciona porque resulta que \cellcolorla macro expande en algún momento su argumento, por lo que no tenemos que hacerlo de antemano. Consulte los comentarios en la Variante 2 a continuación para saber cómo se podría proceder si la macro utilizada fuera menos indulgente que \cellcolor.

Variante 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}

ingrese la descripción de la imagen aquí

Variante 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}

Produce lo mismo que la Variante 1.

información relacionada