使用直方图对单元格背景进行部分着色

使用直方图对单元格背景进行部分着色

Excel 有一个很酷的功能,称为“数据栏”条件格式,它允许用户部分填充单元格背景以根据单元格内容创建直方图。以下是工作簿中的屏幕截图示例:

例子

我正在寻找 TiKZ、minipage 或其他解决方案,以便我仅对单元格的背景进行部分着色。我尝试了几个选项,但没有成功。

\cellcolor这是使用该包的最小工作示例xcolor

\documentclass{article}
\usepackage[table]{xcolor}% http://ctan.org/pkg/xcolor
\begin{document}
\begin{tabular}{l|c|r}
  \hline
  91.41 & \cellcolor{green!25}90.81 & 38.76 \\
  \cellcolor{green!25}98.75 & 13.82 & 94.62 \\
  57.11 & \cellcolor{green!25}51.21 & \cellcolor{green!25}42.84 \\
  \hline
\end{tabular}
\end{document}

上面的代码产生:

mwe 示例

在理想情况下,我会有一个宏,例如\partialcellcolor{green!25}{0.41\linewidth}或任何其他宏,来指定颜色扩展到41%单元格的任意位置。我使用“ R”来生成表格,因此我会让它在编写 latex 代码时进行计算。

有什么建议么?

答案1

我重写了整个答案。有关之前的版本,请参阅这个答案的历史

为此,H引入了采用一个可能为空的参数的 columntype。

对于正数,条形图从左到右填充,对于负数,条形图从右到左填充。

需要设置它们的值minmax、来缩放条形图。该值初始化为,min neg因为它用于确定所需的节点宽度max negmax neg0align=right。(有其他方法来做到这一点,但我会保持简单。)

min我认为设置除此之外min neg的其他选项没有多大意义,0但是有这个选项。

可以使用各种样式来改变外观。希望这些样式是不言自明的。

该表的最终指定方式如下:

\begin{tabular}{
  | H{} | H{min=2.00,max=105.00}
  | H{max neg=-10.00, max=15.00, add format={precision=0}}|}
  \hline
   10    &   2    & -10 \\
   15.49 &  13.82 &  -5 \\
  100    & 105    &   5 \\
  \hline
\end{tabular}

代码

\documentclass{article}
\usepackage{tikz,array,collcell}
\newcommand*\tikzcellbgset{\pgfqkeys{/tikz/cellbg}}
\tikzcellbgset{
  /pgf/number format/.code=\pgfqkeys{/pgf/number format}{#1},
  node/.style={
    /pgf/number format={/tikz/cellbg/number format},
    node contents={\strut\pgfmathprintnumber{#1}},
    anchor=base, outer sep=+0pt, inner ysep=+0pt, align=right,
    inner xsep=\tabcolsep,
    /utils/exec=%
      \pgfmathprintnumberto{\pgfkeysvalueof{/tikz/cellbg/max}}{\tempa}%
      \pgfmathprintnumberto{\pgfkeysvalueof{/tikz/cellbg/max neg}}{\tempb},
    text width/.expanded={max(width("\tempa"),width("\tempb"))},
    path picture={
      \def\tcbgvo########1{\pgfkeysvalueof{/tikz/cellbg/########1}}% Eugh!
      \pgftransformshift
        {\pgfpointanchor{path picture bounding box}{south west}}
      \pgfsetxvec{%
        \pgfpointdiff
          {\pgfpointanchor{path picture bounding box}{south west}}
          {\pgfpointanchor{path picture bounding box}{south east}}}
      \pgfsetyvec{%
        \pgfpointdiff
          {\pgfpointanchor{path picture bounding box}{south west}}
          {\pgfpointanchor{path picture bounding box}{north west}}}
      \pgfmathifthenelse{#1<0}{"0"}{"1"}
      \ifnum\pgfmathresult=0
        \path[cellbg/fill neg](1,0) rectangle
          ++({-(#1-\tcbgvo{min neg})/(\tcbgvo{max neg}-\tcbgvo{min neg})},1);
      \else
        \path[cellbg/fill pos](0,0) rectangle
          ({(#1-\tcbgvo{min})/(\tcbgvo{max}-\tcbgvo{min})},1);
      \fi
  }},
  max/.initial=100, min/.initial=0,
  max neg/.initial=0, min neg/.initial=0,
  pos color/.code=\colorlet{@tikz@cellbg@pos}{#1},
  neg color/.code=\colorlet{@tikz@cellbg@neg}{#1},
  fill pos/.style={fill=@tikz@cellbg@pos}, pos color=green!25,
  fill neg/.style={fill=@tikz@cellbg@neg}, neg color=red!50,
  number format/.style={fixed zerofill},
  add format/.style={/tikz/cellbg/number format/.append style={#1}}
}
\newcommand{\tikzMe}[1]{\tikz[baseline,cellbg/pic/.try]\node[cellbg/node={#1}];}
\newcolumntype{H}[1]{%
  @{}>{\tikzcellbgset{#1}\collectcell\tikzMe}c<{\endcollectcell}@{}}
\begin{document}
\begin{tabular}{
  | H{} | H{min=2.00,max=105.00}
  | H{max neg=-10.00, max=15.00, add format={precision=0}}|}
  \hline
   10    &   2    & -10 \\
   15.49 &  13.82 &  -5 \\
  100    & 105    &   5 \\
  \hline
\end{tabular}
\end{document}

输出

在此处输入图片描述

答案2

另一个 sans-TikZ 替代方案:

在此处输入图片描述

\documentclass{article}
\usepackage[table]{xcolor}% http://ctan.org/pkg/xcolor
\usepackage[nomessages]{fp}% http://ctan.org/pkg/fp
\newcommand{\maxnum}{100.00}
\newlength{\maxlen}
\newcommand{\databar}[2][green!25]{%
  \settowidth{\maxlen}{\maxnum}%
  \addtolength{\maxlen}{\tabcolsep}%
  \FPeval\result{round(#2/\maxnum:4)}%
  \rlap{\color{green!25}\hspace*{-.5\tabcolsep}\rule[-.05\ht\strutbox]{\result\maxlen}{.95\ht\strutbox}}%
  \makebox[\dimexpr\maxlen-\tabcolsep][r]{#2}%
}
\begin{document}

\begin{tabular}{*{3}{|l}|}
  \hline
  \databar{91.41} & \databar {90.81} & \databar{38.76} \\
  \databar{98.75} & \databar {13.82} & \databar{94.62} \\
  \databar{57.11} & \databar {51.21} & \databar{42.84} \\
  \databar{20.00} & \databar{100.00} & \databar{80.00} \\
  \hline
\end{tabular}
\end{document}

您提供用于计算百分比填充的最大数字(作为宏\maxnum)。计算使用fp


使用这种变体\databar可以填充.5\arrayrulewidth表格单元格两侧的(几乎不可见的)。这只是为了避免由查看器引起的任何类型的伪影。TikZ 解决方案不会显示这一点,因为它在整个表格的背景中(几乎作为底层)绘制彩色框,因此规则会覆盖任何重叠:

在此处输入图片描述

%...
\newcommand{\databar}[2][green!25]{%
  \settowidth{\maxlen}{\maxnum}%
  \addtolength{\maxlen}{\dimexpr2\tabcolsep-\arrayrulewidth}%
  \FPeval\result{round(#2/\maxnum:4)}%
  \rlap{\color{green!25}\hspace*{\dimexpr-\tabcolsep+.5\arrayrulewidth}\rule[-.05\ht\strutbox]{\result\maxlen}{.95\ht\strutbox}}%
  \makebox[\dimexpr\maxlen-2\tabcolsep+\arrayrulewidth][r]{#2}%
}
%...

答案3

{NiceTabular}的一个解决方案nicematrix

\documentclass{article}
\usepackage{nicematrix,tikz}
\usetikzlibrary{calc}
\usepackage{collcell}

\begin{document}

\newcolumntype{B}{>{\collectcell\BarValue}c<{\endcollectcell}}

\ExplSyntaxOn

\NewDocumentCommand{\BarValue}{m}
  {
    #1
    \tl_gput_right:Nx \g_nicematrix_code_before_tl
      { 
        \__pantigny_bar_value:nnn 
          { \int_use:c { c@iRow } } 
          { \int_use:c { c@jCol } } 
          { \fp_eval:n { #1 / 100 } } 
      }
  }

\cs_new_protected:Nn \__pantigny_bar_value:nnn 
  {
    \tikz \fill [blue!15] 
          (#1-|#2) 
          rectangle 
          ( $ ( \int_eval:n { #1 + 1 } -| #2 )
              ! #3 !
              ( \int_eval:n { #1 + 1 } -| \int_eval:n { #2 + 1 } ) $ )
    ; 
  }

\ExplSyntaxOff

\begin{NiceTabular}{BBB}[hvlines,first-col]
A & 40.89 & 80.5 & 38.76 \\
B & 90.89 & 70 & 15.76 \\
C & 57.11 & 21.21 & 92.84 
\end{NiceTabular}

\end{document}

您需要多次编译(因为nicematrix在后台使用 PGF/Tikz 节点)。

上述代码的输出

答案4

我利用 TikZ 的功能来实现这一点:简单而灵活!

在此处输入图片描述

\documentclass[tikz,border=5mm]{standalone}
\begin{document}
\newcommand\tab[2]{%
\begin{scope}[shift={(-.5,.5)}]
\fill[green!20] #1 rectangle +(#2/100,-1); 
\draw #1 rectangle +(1,-1);
\end{scope}
\path #1 node{#2};
}% end of tab

\begin{tikzpicture}[yscale=.5,xscale=1.2]
\tab{(0,0)}{40.89}  \tab{(1,0)}{80.5}   \tab{(2,0)}{38.76}
\tab{(0,-1)}{90.89} \tab{(1,-1)}{70}    \tab{(2,-1)}{15.76}
\tab{(0,-2)}{57.11} \tab{(1,-2)}{21.21} \tab{(2,-2)}{92.84}
\end{tikzpicture}

\end{document}

相关内容