定义多种自定义颜色的简洁方法

定义多种自定义颜色的简洁方法

我是 Latex 的新手,这是我对 tex.sx 的第一个问题,我提前为无法做出一个好的可重现的例子道歉。

我正在尝试根据颜色代码的“矢量”为表格的单元格着色。

我看到过一些关于根据单元格的值对单元格进行着色的问题(例如是否有一种简单的方法可以根据每个单元格中的值为表格着色?)。我尝试指定一个长度与表格中的行数相同的颜色向量,然后使用它来定义其中一列的颜色。

我甚至不确定你是否可以在乳胶中以这种方式创建“矢量”!

非常感谢。

答案1

欢迎使用 TeX.SX!您可以这样做(例如,为第二列中的单元格着色):

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

\ExplSyntaxOn

\msg_new:nnn { mytblvectorcolor } { not-enough-elements-in-color-vector }
  { Not~enough~elements~in~color~vector. }

\seq_new:N \l_my_color_vector_seq
\seq_new:N \g__my_work_color_vector_seq

\cs_new_protected:Npn \my_set_local_color_vector:n #1
  {
    \seq_set_from_clist:Nn \l_my_color_vector_seq {#1}
  }

\cs_new_protected:Nn \my_use_current_color_vector:
  {
    \seq_gset_eq:NN \g__my_work_color_vector_seq \l_my_color_vector_seq
  }

\cs_new_protected:Npn \my_set_color_vector:n #1
  {
    \my_set_local_color_vector:n {#1}
    \my_use_current_color_vector:
  }

\cs_generate_variant:Nn \my_set_color_vector:n { x }

\NewDocumentCommand \myUseCurrentColorVector { }
  {
    \my_use_current_color_vector:
  }

\NewDocumentCommand \mySetColorVector { m }
  {
    \my_set_color_vector:n {#1}
  }

\cs_new_protected:Npn \my_apply_current_vector_color:N #1
  {
    \seq_gpop_left:NN \g__my_work_color_vector_seq \l_tmpa_tl

    \tl_if_eq:NNTF \l_tmpa_tl \q_no_value
      {
        \msg_error:nn { mytblvectorcolor }
          { not-enough-elements-in-color-vector }
      }
      { \exp_args:NV #1 \l_tmpa_tl }
  }

\cs_new_protected:Nn \my_apply_current_color_to_cell:
  {
    \my_apply_current_vector_color:N \cellcolor
  }

\NewDocumentCommand \myApplyCurrentColorToCell { }
  {
    \my_apply_current_color_to_cell:
  }

% #1: color model
% #2: stem for color names
% #3: color specs (seq)
\cs_new_protected:Npn \my_define_color_series:nnN #1#2#3
  {
    \seq_set_eq:NN \l_tmpa_seq #3
    \int_step_inline:nnn { 1 } { \seq_count:N #3 }
      {
        \seq_gpop_left:NN \l_tmpa_seq \l_tmpa_tl
        \exp_args:Nnnx
          \definecolor { #2 ##1 } {#1} { \tl_use:N \l_tmpa_tl }
      }
  }

\seq_new:N \l__my_batch_define_colors_seq

% #1: color model
% #2: stem for color names
% #3: color specs (clist)
\cs_new_protected:Npn \my_batch_define_colors:nnn #1#2#3
  {
    \seq_set_from_clist:Nn \l__my_batch_define_colors_seq {#3}
    \my_define_color_series:nnN {#1} {#2} \l__my_batch_define_colors_seq
  }

\NewDocumentCommand \myBatchDefineColors { m m m }
  {
    \my_batch_define_colors:nnn {#1} {#2} {#3}
  }

% #1: first color index (default: 1)
% #2: last color index
% #3: stem for color names
\cs_new_protected:Npn \my_batch_set_color_vector:nnn #1#2#3
  {
    \seq_clear:N \l_tmpa_seq
    \int_step_inline:nnn {#1} {#2}
      { \seq_gput_right:Nn \l_tmpa_seq { #3 ##1 } }
    \my_set_color_vector:x { \seq_use:Nn \l_tmpa_seq { , } }
  }

\NewDocumentCommand \myBatchSetColorVector { O{1} m m }
  {
    \my_batch_set_color_vector:nnn {#1} {#2} {#3}
  }

\ExplSyntaxOff

\begin{document}
\setlength{\parskip}{\baselineskip}

\mySetColorVector{red, green, yellow}% set color vector at global scope
\begin{tabular}{c>{\myApplyCurrentColorToCell}cc}
  a0 & a1 & a2\\
  b0 & b1 & b2\\
  c0 & c1 & c2
\end{tabular}

{% Use different colors in this group (local scope)
  \mySetColorVector{red!20, green!20, blue!20}%
  \begin{tabular}{c>{\myApplyCurrentColorToCell}cc}
    A0 & A1 & A2\\
    B0 & B1 & B2\\
    C0 & C1 & C2
  \end{tabular}%
}%

% Reuse the color vector set at global scope
\myUseCurrentColorVector
\begin{tabular}{c>{\myApplyCurrentColorToCell}cc}
  a0 & a1 & a2\\
  b0 & b1 & b2\\
  c0 & c1 & c2
\end{tabular}

% Example of batch-definition for colors and the color vector.
% Note: \myBatchDefineColors can be called in the preamble.
\myBatchDefineColors{rgb}{MyColor}{%
  {0.8,0.9,1.0},
  {0.7,0.6,0.5},
  {0.6,0.5,0.7},
  {0.5,0.4,0.5},
  {0.4,0.6,0.5},
  {0.6,0.8,0.7}
}%
% \myBatchDefineColors{HTML}{MyColor}{
%   00AA00,
%   00BB11,
%   11DDEE,
%   5547FE,
%   AD0245,
%   14CB1A
% }%
%
% What follows is a shortcut for
% \mySetColorVector{MyColor1,MyColor2,MyColor3,MyColor4,MyColor5,MyColor6}%
\myBatchSetColorVector{6}{MyColor}%
% The table has 5 lines and the color vector 6 elements; that's okay.
\begin{tabular}{c>{\myApplyCurrentColorToCell}cc}
  a0 & a1 & a2\\
  b0 & b1 & b2\\
  c0 & c1 & c2\\
  d0 & d1 & d2\\
  e0 & e1 & e2
\end{tabular}

\end{document}

简单示例的屏幕截图

当然,在启动使用 的表格或数组之前,使用\mySetColorVector或设置的颜色向量必须至少具有与所述表格或数组中调用 的次数一样多的元素。顺便说一句,宏不必总是在同一列中调用;这将在下一个示例中显示。\myUseCurrentColorVector\myApplyCurrentColorToCell\myApplyCurrentColorToCell\myApplyCurrentColorToCell

这是一个更复杂的例子(谁说臃肿?:-),它概括了前面的宏,可以有条件地循环遍历颜色向量。如您所见,这些宏可以在表格或数组环境以外的其他上下文中使用。

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

\ExplSyntaxOn

\msg_new:nnn { mytblvectorcolor } { not-enough-elements-in-color-vector }
  { Not~enough~elements~in~color~vector. }

\seq_new:N \l_my_color_vector_seq
% We are going to copy \g__my_saved_color_vector_seq to this one before
% starting a set of color operations, then from pop from it as we need to get
% each next color.
\seq_new:N \g__my_work_color_vector_seq
\seq_new:N \g__my_saved_color_vector_seq

\cs_new_protected:Npn \my_set_local_color_vector:n #1
  {
    \seq_set_from_clist:Nn \l_my_color_vector_seq {#1}
  }

\cs_new_protected:Nn \my_use_current_color_vector:
  {
    \seq_gset_eq:NN \g__my_work_color_vector_seq \l_my_color_vector_seq
    \seq_gset_eq:NN \g__my_saved_color_vector_seq \l_my_color_vector_seq
  }

\cs_new_protected:Npn \my_set_color_vector:n #1
  {
    \my_set_local_color_vector:n {#1}
    \my_use_current_color_vector:
  }

\cs_generate_variant:Nn \my_set_color_vector:n { x }

\NewDocumentCommand \myUseCurrentColorVector { }
  {
    \my_use_current_color_vector:
  }

\NewDocumentCommand \mySetColorVector { m }
  {
    \my_set_color_vector:n {#1}
  }

% #1: a token (typically a control sequence)
\cs_new_protected:Npn \my_apply_current_vector_color:N #1
  {
    \seq_gpop_left:NN \g__my_work_color_vector_seq \l_tmpa_tl

    \tl_if_eq:NNTF \l_tmpa_tl \q_no_value
      {
        \msg_error:nn { mytblvectorcolor }
          { not-enough-elements-in-color-vector }
      }
      { \exp_args:NV #1 \l_tmpa_tl }
  }

% #1: a <boolean expression> indicating whether looping is enabled
% #2: a token (typically a control sequence) passed to
%     \my_apply_current_vector_color:N
\cs_new_protected:Npn \my_apply_current_vector_color:nN #1#2
  {
    \bool_if:nT {#1}
      {                         % looping allowed -> restore the work vector
        \seq_if_empty:NT \g__my_work_color_vector_seq
          {
            \seq_gset_eq:NN \g__my_work_color_vector_seq
                            \g__my_saved_color_vector_seq
          }
      }

    \my_apply_current_vector_color:N #2
  }

% #1: an xparse boolean that can be tested with \IfBooleanTF and says whether
%     looping is allowed
% #2: a token (typically a control sequence) passed to
%     \my_apply_current_vector_color:N
\cs_new_protected:Npn \my_apply_current_vector_color_usrlevel:nN #1#2
  {
    \exp_args:Nx \my_apply_current_vector_color:nN
      { \IfBooleanTF {#1} { \c_true_bool } { \c_false_bool } }
    #2
  }

% #2: a token (typically a control sequence) passed to
%     \my_apply_current_vector_color:N
%
% Star version: looping is allowed
\NewDocumentCommand \myApplyCurVecColor { s m }
  {
    \my_apply_current_vector_color_usrlevel:nN {#1} #2
  }

\cs_new_protected:Npn \my_list_and_process_elements:nNn #1#2#3
  {
    \seq_set_split:Nnn \l_tmpa_seq { } {#3}
    \seq_clear:N \l_tmpb_seq
    \seq_map_inline:Nn \l_tmpa_seq
      {
        \seq_gput_right:Nn \l_tmpb_seq
          { \my_apply_current_vector_color:nN {#1} #2 {##1} }
      }
    \seq_use:Nnnn \l_tmpb_seq { ~and~ } { ,~ } { ,~and~ }
  }

\NewDocumentCommand \myListAndProcessElements { s m m }
  {
    \exp_args:Nx \my_list_and_process_elements:nNn
      { \IfBooleanTF {#1} { \c_true_bool } { \c_false_bool } }
    #2 {#3}
  }

\NewDocumentCommand \myApplyCurrentColorToCell { s }
  {
    \my_apply_current_vector_color_usrlevel:nN {#1} \cellcolor
  }

% It's ugly to have to define these, but it happens that using a starred
% command such as \myApplyCurrentColorToCell in the >{decl.} syntactic
% element of a tabular preamble causes headaches when the star isn't there
% and LaTeX looks for it... Therefore, we provide the two versions of
% \myApplyCurrentColorToCell in a way that doesn't require to check for the
% presence of the star. These commands are safe to use in the >{decl.} parts
% of a tabular preamble.
\NewDocumentCommand \myApplyCurrentColorToCellNoLoop { }
  {
    \my_apply_current_vector_color:nN { \c_false_bool } \cellcolor
  }

\NewDocumentCommand \myApplyCurrentColorToCellLoop { }
  {
    \my_apply_current_vector_color:nN { \c_true_bool } \cellcolor
  }

% #1: color model
% #2: stem for color names
% #3: color specs (seq)
\cs_new_protected:Npn \my_define_color_series:nnN #1#2#3
  {
    \seq_set_eq:NN \l_tmpa_seq #3
    \int_step_inline:nnn { 1 } { \seq_count:N #3 }
      {
        \seq_gpop_left:NN \l_tmpa_seq \l_tmpa_tl
        \exp_args:Nnnx
          \definecolor { #2 ##1 } {#1} { \tl_use:N \l_tmpa_tl }
      }
  }

\seq_new:N \l__my_batch_define_colors_seq

% #1: color model
% #2: stem for color names
% #3: color specs (clist)
\cs_new_protected:Npn \my_batch_define_colors:nnn #1#2#3
  {
    \seq_set_from_clist:Nn \l__my_batch_define_colors_seq {#3}
    \my_define_color_series:nnN {#1} {#2} \l__my_batch_define_colors_seq
  }

\NewDocumentCommand \myBatchDefineColors { m m m }
  {
    \my_batch_define_colors:nnn {#1} {#2} {#3}
  }

% #1: first color index (default: 1)
% #2: last color index
% #3: stem for color names
\cs_new_protected:Npn \my_batch_set_color_vector:nnn #1#2#3
  {
    \seq_clear:N \l_tmpa_seq
    \int_step_inline:nnn {#1} {#2}
      { \seq_gput_right:Nn \l_tmpa_seq { #3 ##1 } }
    \my_set_color_vector:x { \seq_use:Nn \l_tmpa_seq { , } }
  }

\NewDocumentCommand \myBatchSetColorVector { O{1} m m }
  {
    \my_batch_set_color_vector:nnn {#1} {#2} {#3}
  }

% Macros for saving the last element popped from the color vector, in order
% to potentially use it several times (per tabular row, for instance).
%
% The 'Loop' suffix doesn't mean we store a color loop; it means the macro is
% the variant that is *allowed to loop* over the color vector if it has less
% elements than what is used.
\NewDocumentCommand \myStoreCurrentColorLoop { }
  {
    \my_apply_current_vector_color:nN { \c_true_bool } \myDoStoreColor
  }

\tl_new:N \g_my_current_color_tl % token list for storing a “current color”

\NewDocumentCommand \myDoStoreColor { m }
  {
    \tl_gset:Nn \g_my_current_color_tl {#1}
  }

\NewDocumentCommand \myApplyStoredColorToCell { }
  {
    \exp_args:Nx \cellcolor { \tl_use:N \g_my_current_color_tl }
  }

\ExplSyntaxOff

% Box what follows using a tcolorbox. #1 is the base color; it is blended with
% others by \xymybox. The \colorlet is necessary when #1 itself contains
% exclamation marks.
\newcommand{\myApplyCurrentColorToTCBox}[1]{%
  \colorlet{tmpcolor}{#1}%
  \xmybox[tmpcolor]%
}

% From the tcolorbox manual
\newtcbox{\xmybox}[1][red]{%
  on line, arc=7pt,colback=#1!10!white,colframe=#1!50!black,
  before upper={\rule[-3pt]{0pt}{10pt}},boxrule=1pt,
  boxsep=0pt,left=6pt,right=6pt,top=2pt,bottom=2pt
}

\begin{document}
\setlength{\parskip}{\baselineskip}

\mySetColorVector{red, green, yellow}% set color vector at global scope
\begin{tabular}{c>{\myApplyCurrentColorToCellLoop}cc}
  a0 & a1 & a2\\
  b0 & b1 & b2\\
  c0 & c1 & c2\\
  d0 & d1 & d2\\
  e0 & e1 & e2
\end{tabular}

{% Use different colors in this group (local scope)
  \mySetColorVector{red!20, green!20, blue!20}%
  % 3 colors and 3 lines -> the “Loop” variant would work as well but is not
  % required here.
  \begin{tabular}{c>{\myApplyCurrentColorToCellNoLoop}cc}
    A0 & A1 & A2\\
    B0 & B1 & B2\\
    C0 & C1 & C2
  \end{tabular}%
}%

% Reuse the color vector set at global scope
\myUseCurrentColorVector
\begin{tabular}{c>{\myApplyCurrentColorToCellLoop}cc}
  a0 & a1 & a2\\
  b0 & b1 & b2\\
  c0 & c1 & c2\\
  d0 & d1 & d2\\
  e0 & e1 & e2
\end{tabular}

\myUseCurrentColorVector
{%
  \let\applyColor=\myApplyCurrentColorToCell % abbreviation
  \begin{tabular}{ccc}
    \applyColor a0 & a1 & a2\\
    b0                            & \applyColor b1 & b2\\
    c0                            & c1             & \applyColor c2
  \end{tabular}%
}

\mySetColorVector{red, green, blue!20, yellow!50}%
\myListAndProcessElements*{\myApplyCurrentColorToTCBox}{%
  {I love cats}%
  {small cats}%
  {fat cats}%
  {smart cats}%
  {all kinds of cats}%
  {other cats}%
  {also cats}%
}.

% Example of batch-definition for colors and the color vector.
% Note: \myBatchDefineColors can be called in the preamble.
\myBatchDefineColors{rgb}{MyColor}{%
  {0.4,0.2,0.6},
  {0.2,1.0,0.1},
  {0.3,0.5,0.8},
  {0.9,0.4,0.5},
  {1.0,0.9,0.1},
  {0.1,0.8,0.7}
}%
% What follows is a shortcut for
% \mySetColorVector{MyColor1,MyColor2,MyColor3,MyColor4,MyColor5,MyColor6}%
\myBatchSetColorVector{6}{MyColor}%
\myListAndProcessElements*{\myApplyCurrentColorToTCBox}{%
  {\LaTeX\ is cool}%
  {rather cool}%
  {very cool}%
  {quite cool}%
  {\"{u}ber cool}%
  {most definitely cool}%
}!

\myUseCurrentColorVector
\begin{tabular}{>{\myStoreCurrentColorLoop}c
                >{\myApplyStoredColorToCell}c
                >{\myApplyStoredColorToCell}c}
  a0 & a1 & a2\\
  b0 & b1 & b2\\
  c0 & c1 & c2\\
  d0 & d1 & d2\\
  e0 & e1 & e2
\end{tabular}

\end{document}

复杂的例子

定义多种自定义颜色的简洁方法

如果您想要定义一个包含许多自定义颜色(不是按名称可用的)的向量,您通常必须编写:

\definecolor{MyColor1}{rgb}{0.5,0.6,0.8}
\definecolor{MyColor2}{rgb}{0.7,0.6,0.9}
...
\mySetColorVector{MyColor1,MyColor2,...}

由于这有点繁琐,我在两个例子中都包含了宏,让您可以简单地执行以下操作:

\myBatchDefineColors{rgb}{MyColor}{%
  {0.8,0.9,1.0},
  {0.7,0.6,0.5},
  {0.6,0.5,0.7},
  {0.5,0.4,0.5},
  {0.4,0.6,0.5},
  {0.6,0.8,0.7}
}%
% shortcut for \mySetColorVector{MyColor1,MyColor2,MyColor3,MyColor4,MyColor5,MyColor6}%
\myBatchSetColorVector{6}{MyColor}%
% Use the newly-set color vector here, for instance:
\begin{tabular}{...}
  ...
\end{tabular}

rgb在此示例中使用了颜色模型,但您可以使用 支持的任何颜色模型xcolor。例如,使用HTML颜色模型,以下定义(六种自定义颜色)有效:

\myBatchDefineColors{HTML}{MyColor}{
  00AA00,
  00BB11,
  11DDEE,
  5547FE,
  AD0245,
  14CB1A
}%

(您可以将所有内容放在同一行,如果愿意的话甚至可以不加空格)

注意:\myBatchDefineColors可以在文档前言中调用。对于您自己定义的命令,这通常是个好主意。

相关内容