我有一些来自统计包 R 的表格,我想以 LaTeX 标记的形式导出。
我想做每列与其标签的最长单词一样大(为简单起见,假设相关的表格值较短)。
如果标签如下:
Short label
Very long description
Three letter label
那么期望的输出(包括一些示例值)是:
Short Very long Three
label description letter
label
-----------------------------
1 5 9
2 6 10
3 7 11
4 8 12
-----------------------------
人们可以在 R 中对表格标签/值进行各种各样的操作,但在 LaTeX 之外,R 本身只能计算表格标签的字符数,而不知道 LaTeX 引擎排版时所使用的实际空间。
大意
主要思想是从 R 脚本生成能够措施单词并使用 LaTeX 中计算的长度来设置实际的表格环境。LaTeX 测量文档的草稿如下:
...
\usepackage{varwidth, calc}
...
\newlength{\temp}
%% Column 1
\setlength{\temp}{\widthof{\fbox{\begin{varwidth}{\textwidth}
Short\\ label
\end{varwidth}}}}
\the\temp
%% Column 2
\setlength{\temp}{\widthof{\fbox{\begin{varwidth}{\textwidth}
Very \\ long \\ description
\end{varwidth}}}}
\the\temp
%% Column 3
\setlength{\temp}{\widthof{\fbox{\begin{varwidth}{\textwidth}
Three \\ letter \\ label
\end{varwidth}}}}
\the\temp
对其进行 Latex 处理后,我得到了以下输出:
30.71672pt
54.6612pt
32.38335pt
现在我可以在 R 中解析此输出并生成以下 LaTeX 代码:
\usepackage{array}
...
\def\tabcol{p{30.71672pt}p{54.6612pt}p{32.38335pt}}
\expandafter\tabular\expandafter{\tabcol}
\hline
Short label & Very long description & Three letter label \\\hline
1 & 2 & 3
\endtabular
期望的解决方案
我想知道我是否可以减少这个步骤并直接在 LaTeX 中执行,而不是解析 R 中第一个代码片段的输出,也就是说:我可以捕获长度 \temp
并将它们存储在某种“字符串变量”中,以便我可以在宏中使用它\tabcol
?
编辑
很多评论都在问我为什么不使用 knitr/Sweave 之类的东西。我没有详述这些细节,以免被标记为偏离主题。现在我想读者需要更多的见解。
首先我使用 Rnw
+ knitr
+ xtable
。R-NoWeb 文档是 LaTeX 文档,其中穿插着特殊标记块(称为“代码块”):
<<...>>
...
@
其中的点代表 R 代码或选项。knitr
执行代码块中的 R 代码并将其替换为生成的 LaTeX 格式的输出(如果代码生成图形,knitr 将自动放置\includegraphics...
指向图形文件的 ,除非您选择手动控制 LaTeX 输出)。由于 knitr 解析的文件是“普通”LaTeX 文件,因此您可以对其进行 latex 处理,这样您的报告就完成了。
至于表格,该模块xtable
可以使用几个很酷的 LaTeX 环境( 等)将 R 数据对象转换为 LaTeX booktabs
。tabularx
据我所知,没有人可以像我尝试的那样自动调整表格大小。 tabularx
可以做到,但使用不同的算法。
无论如何,在 R 中,很容易按列排列表格数据,并为每列生成类似于以下内容的 LaTeX 输出:
%% Column 1
\setlength{\temp}{\widthof{\fbox{\begin{varwidth}{\textwidth}
Short\\ label
\end{varwidth}}}}
\the\temp
如上所述,通过编译这些行(对每一列重复),我得到了所需的大小。为了捕获temp
长度,我可能会使用:
\immediate\openout\tempfile=lengths.tex
\immediate\write\tempfile{\the\temp}
\immediate\closeout\tempfile
因此,实际的 R 生成的文件table.tex
应该类似于:
\usepackage{varwidth, calc}
\usepackage{array}
...
\newlength{\temp}
\immediate\openout\tempfile=lengths.tex
...
%% Column 1
\setlength{\temp}{\widthof{\fbox{\begin{varwidth}{\textwidth}
Short\\ label
\end{varwidth}}}}
%\the\temp
\immediate\write\tempfile{\the\temp}
%% Column 2
...
%% Column n
...
\immediate\closeout\tempfile
...
在 LaTeX 中编译后table.tex
,lengths.tex
生成。lengths.tex
可以在 R 中重新解析以读取其中的列值。table.tex
可以生成一个新的
\usepackage{array}
...
\def\tabcol{p{...pt}p{...pt}...}
\expand\tabular\expandafter{\tabcol}
\endtabular
p{...pt}
是从 获得的lengths.tex
。
可以将新的table.tex
关联起来以获得最终结果,但是,如上所述,我想直接在 LaTeX 中自动解析第一个table.tex
(或第一遍输出lengths.tex
)(而无需在 R 和 LaTeX 之间来回切换)。
答案1
我认为我找到了一个可以接受的解决方案。
假设统计表示意图如下:
Short label Very long description Three letter label
1 1 5 9
2 2 6 10
3 3 7 11
4 4 8 12
生成的 LaTeX 代码使每一列的大小与其标签的最长单词一样大是:
\documentclass{article}
\usepackage{varwidth, calc}
\begin{document}
%% LaTeX vars
\def\colDef{}
\newlength{\temp}
%% Column 1
\setlength{\temp}{\widthof{\mbox{\begin{varwidth}{\textwidth}
Short\\label
\end{varwidth}}}}
\edef\colDef{\colDef p{\the\temp}}
%% Column 2
\setlength{\temp}{\widthof{\mbox{\begin{varwidth}{\textwidth}
Very\\long\\description
\end{varwidth}}}}
\edef\colDef{\colDef p{\the\temp}}
%% Column 3
\setlength{\temp}{\widthof{\mbox{\begin{varwidth}{\textwidth}
Three\\letter\\label
\end{varwidth}}}}
\edef\colDef{\colDef p{\the\temp}}
\edef\colDef{{\colDef}}
%% Table Macro
\newcommand{\maketab}[2]{%
\begin{tabular}{#1}
#2
\end{tabular}
}
%% Table Body
\newcommand{\tableBody}{
Short label & Very long description & Three letter label \\
\hline
1 & 5 & 9 \\
2 & 6 & 10 \\
3 & 7 & 11 \\
4 & 8 & 12 \\
\hline
}
%% and...
\expandafter\maketab\colDef{\tableBody}
\end{document}
通过 Latexing 可以获得标签的预期结果:
Short Very long Three
label description letter
label
-----------------------------
1 5 9
2 6 10
3 7 11
4 8 12
-----------------------------
R/knitr 方面
由于 tex.stackexchange 上有knitr
和xtable
标签,我认为生成上述 LaTeX 的 R 代码可能会引起某些人的兴趣。
“编织”的 Rnw 文档是:
\documentclass{article}
\usepackage{varwidth, calc}
\begin{document}
<<label=ididit, results='asis', echo=FALSE>>=
library(xtable)
## Generate sample 4x3 table, with long labels
## -------------------------------------------
tab=data.frame(matrix(1:12, ncol=3))
names(tab) = c("Short label", "Very long description", "Three letter label")
## Generate LaTeX code: every \ needs to be doubled (escaped)
## -----------------------------------------------------------
## Print LaTeX vars
cat("
\\def\\colDef{}
\\newlength{\\temp}
")
## Dynamic text
text1="\\setlength{\\temp}{\\widthof{\\mbox{\\begin{varwidth}{\\textwidth}"
# Labels here separated by //
text2="\\end{varwidth}}}}
\\edef\\colDef{\\colDef p{\\the\\temp}}
"
## Separate labels with \\\\
lab= strsplit(names(tab), " ")
lab= sapply(lab, function(x) paste(x, collapse='\\\\'))
## Replace dynamic text with labels and print it
text=paste(text1, lab, text2, sep="\n", collapse="\n")
cat(text)
cat("\n\\edef\\colDef{{\\colDef}}")
## Setup main table macro
cat("
\\newcommand{\\maketab}[2]{%
\\begin{tabular}{#1}
#2
\\end{tabular}
}
")
## Table body obtained via xtable module
cat("\\newcommand{\\tableBody}{\n")
print.xtable(xtable(tab), only.contents=T, include.rownames=F)
cat("}\n")
### eventually...
cat("\\expandafter\\maketab\\colDef{\\tableBody}")
@
\end{document}
假如这个文档名为table.rnw
,则将其编织起来,也就是在 R 中执行:
knitr("table.rnw")
将生成table.tex
类似上面第一个清单中所示的 LaTeX 代码(加上一些用于图形的 knitr 宏修饰)在 LaTeX 中进行编译以获得所需的表格输出。
对解决方案的评论
请注意,所提出的解决方案需要在 R 中执行一步 + 在 LaTeX 中执行一步,因为生成的 LaTeX 包含用于测量长度和在表格环境中使用长度的代码。xtable
仅用于生成表格内部单元格的格式化列表,因此人们可以轻松地使用一些更花哨的东西定制表格环境和/或为表格设置更多格式化参数。
避免从 R 到 LaTeX 的额外往返意味着速度,无论如何都建议任何进一步改进它的途径。