我使用 LaTeX 进行脑成像 (fMRI) 的科学报告。我有一个tabular
LaTeX 数组,其中包含相当多的行和列,它们都是大脑区域,并且在每个相交的单元格中都有一些有关它们连接的数据。
此数组的内容tabular
是使用命令加载的另一个 .tex 文件中单独定义的\input
。在此另一个 .tex 文件中,数组的每个单元格的内容tabular
使用数百个\newcommand
命令单独定义。数组中除了这些命令tabular
外没有其他内容。数组位于内部以允许对单元格值进行一些基本计算(尽管这不是必需的)。到目前为止一切正常。\newcommand
tabular
\begin{spreadtab}
因此,\newcommand
定义如下:
\newcommand{\origREGIONONEdestREGIONONE}{ NA } % NA for cells on the diagonal.
\newcommand{\origREGIONONEdestREGIONTWO}{ - } % this is the default case.
...
\newcommand{\origREGINOTWOdestREGIONTWO}{ NA }
\newcommand{\origREGIONTWOdestREGIONONE}{ \ref{Spielberg1981} }
\newcommand{\origREGIONTWOdestREGIONTHREE}{ bilateral \ref{Cameron1989} }
...
\newcommand
所有列 x 行交叉点都有一个特定的定义。
数组代码tabular
如下所示(3x3 的示例,但实际上它大于 20x20):
\tiny
\begin{table}
\scalebox{0.6}{
\begin{spreadtab}{{tabular}{*{3}{c}}}
\hline
\to/from :={} & REGIONONE :={} & REGIONTWO :={} & REGIONTHREE :={} \\
\hline
to REGIONONE :={} & \origREGIONONEdestREGIONONE :={} & \origREGIONTWOdestREGIONONE :={} &\origREGIONTHREEdestREGIONONE :={} \\
to REGIONTWO :={} & \origREGIONONEdestREGIONTWO :={} & \origREGIONTWOdestREGIONTWO :={} &\origREGIONTHREEdestREGIONTWO :={} \\
to REGIONTHREE :={} & \origREGIONONEdestREGIONTHREE :={} & \origREGIONTWOdestREGIONTHREE :={} &\origREGIONTHREEdestREGIONTHREE :={} \\
\hline
\end{spreadtab}
} % end scalebox
\caption{A table of connections between brain regions 1, 2 & 3}
\begin{enumerate}
\item \cite{Spielberg1981}\label{Spielberg1981}
\item \cite{Cameron1989}\label{Cameron1989}
\end{enumerate}
\end{table}
\normalsize
现在我想要的是能够tabular
根据列表或字符串数组(或使用任何可能的数据类型)动态生成类似的定义:
在 MATLAB 语法中它将是:ListOfBrainRegions = { 'BRAINREGIONABC', 'BRAINREGIONDEF', 'BRAINREGIONXYZ' }
在 Python 语法中:ListOfBrainRegions = [ 'BRAINREGIONABC', 'BRAINREGIONDEF', 'BRAINREGIONXYZ' ]
列表或数组将被转换成如下代码(如果出现问题spreadtab
则不转换):spreadtab
\hline
\to/from :={} & REGIONABC :={} & REGIONDEF :={} & REGIONXYZ :={} \\
\hline
to REGIONABC :={} & \origREGIONABCdestREGIONABC :={} & \origREGIONDEFdestREGIONABC :={} &\origREGIONXYZdestREGIONABC :={} \\
to REGIONDEF :={} & \origREGIONABCdestREGIONDEF :={} & \origREGIONDEFdestREGIONDEF :={} &\origREGIONXYZdestREGIONDEF :={} \\
to REGIONXYZ :={} & \origREGIONABCdestREGIONXYZ :={} & \origREGIONDEFdestREGIONXYZ :={} &\origREGIONXYZdestREGIONXYZ :={} \\
\hline
那么,我应该如何ListOfBrainRegions
在 LaTeX 中定义?然后如何在编译 .tex 文件时生成 LaTeX 代码?如果我使用其他编程语言(例如 MATLAB、Common Lisp 或 awk)进行编程,则任务(生成程序代码)一点也不难。似乎 LaTeX 没有内置数组、if
... elseif
...else
命令for
或while
循环,尽管某些软件包提供了一些附加功能。那么,如何实现呢?或者,我应该使用哪些 LaTeX 命令、软件包和/或额外工具来完成这项任务?
感谢您的任何帮助 :)
答案1
实际上,LaTeX 格式确实有循环\@tfor
等,但在表格中,TeX 处于有点微妙的状态,所以在这里我只使用普通扩展。
\documentclass{article}
\def\listheadings{%
\expandafter\xlistheadings\regionlist,\relax,}
\def\xlistheadings#1,{%
\ifx\relax#1%
\expandafter\\%
\else
&\textbf{#1}%
\expandafter\xlistheadings
\fi}
\def\listbody{%
\expandafter\xlistbody\regionlist,\relax,}
\def\xlistbody#1,{%
\ifx\relax#1%
\else
\textbf{#1}%
\gdef\thisrow{#1}%
\expandafter\xlistdata\regionlist,\relax,%
\expandafter\xlistbody
\fi}
\def\xlistdata#1,{%
\ifx\relax#1%
\expandafter\\%
\else
&\csname origREGION\thisrow destREGION#1\endcsname
\expandafter\xlistdata
\fi}
\def\preamble{\expandafter\xpreamble\regionlist,\relax,}
\def\xpreamble#1,{%
\ifx\relax#1%
\else
c|%
\expandafter\xpreamble
\fi}
\def\tablestart{%
\edef\temp{\noexpand\begin{tabular}{|c|\preamble}}%
\temp}
\begin{document}
\newcommand\regionlist{ONE,TWO,THREE}
\def\origREGIONONEdestREGIONONE{1/1}
\def\origREGIONONEdestREGIONTWO{1/2}
\def\origREGIONONEdestREGIONTHREE{1/3}
\def\origREGIONTWOdestREGIONONE{2/1}
\def\origREGIONTWOdestREGIONTWO{2/2}
\def\origREGIONTWOdestREGIONTHREE{2/3}
\def\origREGIONTHREEdestREGIONONE{3/1}
\def\origREGIONTHREEdestREGIONTWO{3/2}
\def\origREGIONTHREEdestREGIONTHREE{3/3}
\tablestart
\hline
\listheadings
\hline
\listbody
\hline
\end{tabular}
\end{document}
答案2
以下解决方案expl3
展示了该语言的一些优良特性:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\generatetable}{m}{\nrz_generate_table:n {#1}}
\seq_new:N \l_nrz_head_seq
\tl_new:N \l_nrz_preamble_tl
\tl_new:N \l_nrz_header_tl
\tl_new:N \l_nrz_body_tl
\cs_new_protected:Npn \nrz_generate_table:n #1
{
\seq_set_split:Nnn \l_nrz_head_seq { , } { #1 }
\nrz_generate_table_data:
\nrz_output_table:
}
\cs_new_protected:Npn \nrz_generate_table_data:
{
\tl_set:Nn \l_nrz_preamble_tl { | c | }
\tl_clear:N \l_nrz_header_tl
\tl_clear:N \l_nrz_body_tl
\seq_map_inline:Nn \l_nrz_head_seq
{
\tl_put_right:Nn \l_nrz_preamble_tl { c | }
\tl_put_right:Nn \l_nrz_header_tl { & \textbf{ ##1 } }
\tl_put_right:Nn \l_nrz_body_tl { \textbf{ ##1 } } % first col
\seq_map_inline:Nn \l_nrz_head_seq % other cols
{
\tl_put_right:Nn \l_nrz_body_tl { & \use:c { origREGION ##1 destREGION ####1 } }
}
\tl_put_right:Nn \l_nrz_body_tl { \\ }
}
\tl_put_right:Nn \l_nrz_header_tl { \\ }
}
\cs_new_protected:Npn \nrz_output_table:
{
\begin{tabular}{ \tl_use:N \l_nrz_preamble_tl }
\hline
\tl_use:N \l_nrz_header_tl
\hline
\tl_use:N \l_nrz_body_tl
\hline
\end{tabular}
}
\ExplSyntaxOff
\begin{document}
\def\origREGIONONEdestREGIONONE{1/1}
\def\origREGIONONEdestREGIONTWO{1/2}
\def\origREGIONONEdestREGIONTHREE{1/3}
\def\origREGIONTWOdestREGIONONE{2/1}
\def\origREGIONTWOdestREGIONTWO{2/2}
\def\origREGIONTWOdestREGIONTHREE{2/3}
\def\origREGIONTHREEdestREGIONONE{3/1}
\def\origREGIONTHREEdestREGIONTWO{3/2}
\def\origREGIONTHREEdestREGIONTHREE{3/3}
\generatetable{ONE,TWO,THREE}
\end{document}
表主体由一个映射函数构建,使用相同的映射序列!
首先,我们从作为参数传递给 的列表中构建序列\generatetable
;然后我们继续使用这样获得的序列构建表格前言(以 开始|c|
,并在每一步添加c|
)、表格标题(& <string>
在每一步添加,最后添加\\
)和表格主体,每次一行。行的构建方式类似,使用内部循环。