knitr/rmarkdown/Latex:如何使用 dcolumn 自定义对齐 xtable 列,同时抑制其他 dcolumn 格式
knitr/rmarkdown/Latex: How to custom justify xtable columns using dcolumn, while suppressing other dcolumn formatting
我有一个 table 个值,其中每个单元格都有一个数字,一个 space,然后是括号中的另一个数字。我正在使用 xtable
在文档中呈现此 table。我希望数字在左括号(或 space 上)对齐。我已经使用 latex
dcolumn
包创建了一个命令来证明左括号。但是,这会改变 table 格式的其他方面,我想防止这种情况发生。
我只知道 latex
会很危险,但我不确定下一步该怎么做。下面是一个可重现的示例,展示了 table 现在的样子,并解释了我真正希望它看起来的样子。我想弄清楚如何在 rmarkdown
文档中以编程方式获取我想要的格式,这样我以后就不必破解乳胶了。另外,我并不拘泥于这种证明 table 值合理性的特殊方法,所以如果我走错了路,请随时提出另一种方法。
由于这个问题的重点是在 r
、knitr
和 rmarkdown
的上下文中使用 latex,我认为在这里提问会更好,但请让我知道如果我应该将其移至 Tex
Stack Exchange 站点。
header.tex
包含 dcolumn
命令的文件:
\usepackage{dcolumn}
\newcolumntype{Q}{D{(}{(}{-1}}
rmarkdown
文件:
---
title: "Test"
date: "July 19, 2016"
output:
pdf_document:
includes:
in_header: header.tex
keep_tex: yes
number_sections: yes
fontsize: 11pt
geometry: margin=1in
graphics: yes
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE, message=FALSE, warning=FALSE, fig.align="center")
```
```{r}
library(xtable)
# Data frame to create table
tab1 = structure(list(Term = structure(1:5, .Label = c("Fall 2007",
"Spring 2008", "Fall 2008", "Spring 2009", "Fall 2009", "Spring 2010",
"Fall 2010", "Spring 2011", "Fall 2011", "Spring 2012", "Fall 2012",
"Spring 2013", "Fall 2013", "Spring 2014", "Fall 2014", "Spring 2015",
"Fall 2015", "Spring 2016", "Fall 2016"), class = c("ordered",
"factor")), `BIO 10` = c("89 (2)", "96 (2)", "77 (1)", "103 (3)",
"81 (1)"), `BIO 20` = c("194 (5)", "175 (3)", "176 (8)", "168 (3)",
"170 (4)"), `BIO 30` = c("153 (2)", "154 (14)", "188 (7)", "192 (9)",
"183 (8)"), `BIO 40` = c("284 (23)", "296 (5)", "267 (17)", "296 (16)",
"279 (7)"), `BIO 50` = c("88 (1)", "107 (5)", "98 (1)", "109 (7)",
"93 (5)")), .Names = c("Term", "BIO 10", "BIO 20", "BIO 30",
"BIO 40", "BIO 50"), row.names = c(NA, 5L), class = "data.frame")
```
```{r results="asis"}
print.xtable(
xtable(tab1,
label="tab:tab1",
caption = "Default Table"),
size="small",
include.rownames=FALSE, comment=FALSE, caption.placement="top"
)
```
```{r results="asis"}
print.xtable(
xtable(tab1,
label="tab:tab2",
caption = "Columns aligned at left parenthesis",
align=c("llQQQQQ")),
size="small",
include.rownames=FALSE, comment=FALSE, caption.placement="top"
)
```
下面是 rmarkdown
文档的输出。 Table 1 是由 xtable
创建的默认值 table。 Table2 在my_header.tex
文件中使用dcolumn
命令。在Table2中,每个单元格中的left-hand数字是right-aligned,这就是我想要的。但是,docolumn
以其他我不想要的方式更改了格式:
- 列 headers 应该看起来像 Table 1 中的列 headers,这意味着不应有斜体并且 BIO 和以下之间应该有一个 space数.
- 列宽应该更像 Table 1.
中的宽度
- 在数据列中,第一个数字和括号中的数字之间应该有一个space。例如,
“89(2)”应该是“89(2)”。
- 如果可以的话,两个号码分开就更好了right-aligned。这意味着数字之间可以有一个或两个space,这取决于括号中的数字分别是两位数还是一位数。
我从这个意义上更新了我的答案,您不再需要 dcolumn
。它有点混合了使用 R 的正则表达式功能和添加原始 LaTeX 命令(例如 {\hskip 0.5em}
)。问题是,您可以在(据我所知)任何 LaTeX 环境中添加这些原语,以便格式化您的段落等。
所以使用 apply
我们 重新格式化 table 单元格的 content 取决于数字是否在括号有1个或2个数字,然后添加适当的水平间距。
通过在 print.xtable
中使用 sanitize.text.function = identity
,我们确保当 data.frame
被 xtable
处理时,这些 LaTeX 命令不会被删除。
---
title: "Test"
output:
pdf_document:
keep_tex: true
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE, message=FALSE, warning=FALSE, fig.align="center")
```
```{r}
library(xtable)
namesVec <- c("Term", "BIO 10", "BIO 20", "BIO 30",
"BIO 40", "BIO 50")
# Data frame to create table
tab1 = structure(list(Term = structure(1:5, .Label = c("Fall 2007",
"Spring 2008", "Fall 2008", "Spring 2009", "Fall 2009", "Spring 2010",
"Fall 2010", "Spring 2011", "Fall 2011", "Spring 2012", "Fall 2012",
"Spring 2013", "Fall 2013", "Spring 2014", "Fall 2014", "Spring 2015",
"Fall 2015", "Spring 2016", "Fall 2016"), class = c("ordered",
"factor")), `BIO 10` = c("89 (2)", "96 (2)", "77 (1)", "103 (3)",
"81 (1)"), `BIO 20` = c("194 (5)", "175 (3)", "176 (8)", "168 (3)",
"170 (4)"), `BIO 30` = c("153 (2)", "154 (14)", "188 (7)", "192 (9)",
"183 (8)"), `BIO 40` = c("284 (23)", "296 (5)", "267 (17)", "296 (16)",
"279 (7)"), `BIO 50` = c("88 (1)", "107 (5)", "98 (1)", "109 (7)",
"93 (5)")), .Names = paste("\textnormal{", namesVec, "}"), row.names = c(NA, 5L), class = "data.frame")
tab1 <-apply(tab1, 2, function(x) {
tmp <- nchar(gsub(".*\( ?([0-9]+).*","\1", x))
skip <-ifelse(tmp == 1, "{\\hskip 1em}(", "{\\hskip 0.5em}(")
ifelse(tmp == 1, gsub(x, pattern = " \(", replacement = paste("{\\hskip 1em}(")),
gsub(x, pattern = " \(", replacement = paste("{\\hskip 0.5em}(")))
})
```
```{r results="asis"}
print.xtable(
xtable(tab1,
label="tab:tab2",
caption = "Columns aligned at left parenthesis",
align=c("llrrrrr")),
size="small",
include.rownames=FALSE, comment=FALSE, caption.placement="top"
, sanitize.text.function = identity)
```
这与 Martin 的方法类似;现在已编辑掉答案。将数字和括号中的数字分别对齐可能更容易(至少对于像我这样的 non-latex 演讲者而言),因此将它们分成单独的列。然后,您可以使用 \multicolumn
对列进行分组,并定义 headers(参见 possible to create latex multicolumns in xtable?)
```{r results="asis", echo=FALSE}
tab1 = structure(list(Term = structure(1:5, .Label = c("Fall 2007",
"Spring 2008", "Fall 2008", "Spring 2009", "Fall 2009", "Spring 2010",
"Fall 2010", "Spring 2011", "Fall 2011", "Spring 2012", "Fall 2012",
"Spring 2013", "Fall 2013", "Spring 2014", "Fall 2014", "Spring 2015",
"Fall 2015", "Spring 2016", "Fall 2016"), class = c("ordered",
"factor")), `BIO 10` = c("89 (2)", "96 (2)", "77 (1)", "103 (3)",
"81 (1)"), `BIO 20` = c("194 (5)", "175 (3)", "176 (8)", "168 (3)",
"170 (4)"), `BIO 30` = c("153 (2)", "154 (14)", "188 (7)", "192 (9)",
"183 (8)"), `BIO 40` = c("284 (23)", "296 (5)", "267 (17)", "296 (16)",
"279 (7)"), `BIO 50` = c("88 (1)", "107 (5)", "98 (1)", "109 (7)",
"93 (5)")), .Names = c("Term", "BIO 10", "BIO 20", "BIO 30",
"BIO 40", "BIO 50"), row.names = c(NA, 5L), class = "data.frame")
tab2 <- cbind(tab1[1], do.call(cbind.data.frame, lapply(tab1[-1], function(x)
do.call(rbind, strsplit(as.character(x), " ")))))
addtorow <- list(list(0), paste(names(tab1)[1], paste0('& \multicolumn{2}{l}{', names(tab1)[-1], '}', collapse=''), '\\'))
library(xtable)
print.xtable(
xtable(tab2,
align=c("l","l", rep(c("r@{\hskip 0in}", "r"),5))),
include.rownames=FALSE, ,
add.to.row=addtorow, include.colnames=FALSE)
```
我有一个 table 个值,其中每个单元格都有一个数字,一个 space,然后是括号中的另一个数字。我正在使用 xtable
在文档中呈现此 table。我希望数字在左括号(或 space 上)对齐。我已经使用 latex
dcolumn
包创建了一个命令来证明左括号。但是,这会改变 table 格式的其他方面,我想防止这种情况发生。
我只知道 latex
会很危险,但我不确定下一步该怎么做。下面是一个可重现的示例,展示了 table 现在的样子,并解释了我真正希望它看起来的样子。我想弄清楚如何在 rmarkdown
文档中以编程方式获取我想要的格式,这样我以后就不必破解乳胶了。另外,我并不拘泥于这种证明 table 值合理性的特殊方法,所以如果我走错了路,请随时提出另一种方法。
由于这个问题的重点是在 r
、knitr
和 rmarkdown
的上下文中使用 latex,我认为在这里提问会更好,但请让我知道如果我应该将其移至 Tex
Stack Exchange 站点。
header.tex
包含 dcolumn
命令的文件:
\usepackage{dcolumn}
\newcolumntype{Q}{D{(}{(}{-1}}
rmarkdown
文件:
---
title: "Test"
date: "July 19, 2016"
output:
pdf_document:
includes:
in_header: header.tex
keep_tex: yes
number_sections: yes
fontsize: 11pt
geometry: margin=1in
graphics: yes
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE, message=FALSE, warning=FALSE, fig.align="center")
```
```{r}
library(xtable)
# Data frame to create table
tab1 = structure(list(Term = structure(1:5, .Label = c("Fall 2007",
"Spring 2008", "Fall 2008", "Spring 2009", "Fall 2009", "Spring 2010",
"Fall 2010", "Spring 2011", "Fall 2011", "Spring 2012", "Fall 2012",
"Spring 2013", "Fall 2013", "Spring 2014", "Fall 2014", "Spring 2015",
"Fall 2015", "Spring 2016", "Fall 2016"), class = c("ordered",
"factor")), `BIO 10` = c("89 (2)", "96 (2)", "77 (1)", "103 (3)",
"81 (1)"), `BIO 20` = c("194 (5)", "175 (3)", "176 (8)", "168 (3)",
"170 (4)"), `BIO 30` = c("153 (2)", "154 (14)", "188 (7)", "192 (9)",
"183 (8)"), `BIO 40` = c("284 (23)", "296 (5)", "267 (17)", "296 (16)",
"279 (7)"), `BIO 50` = c("88 (1)", "107 (5)", "98 (1)", "109 (7)",
"93 (5)")), .Names = c("Term", "BIO 10", "BIO 20", "BIO 30",
"BIO 40", "BIO 50"), row.names = c(NA, 5L), class = "data.frame")
```
```{r results="asis"}
print.xtable(
xtable(tab1,
label="tab:tab1",
caption = "Default Table"),
size="small",
include.rownames=FALSE, comment=FALSE, caption.placement="top"
)
```
```{r results="asis"}
print.xtable(
xtable(tab1,
label="tab:tab2",
caption = "Columns aligned at left parenthesis",
align=c("llQQQQQ")),
size="small",
include.rownames=FALSE, comment=FALSE, caption.placement="top"
)
```
下面是 rmarkdown
文档的输出。 Table 1 是由 xtable
创建的默认值 table。 Table2 在my_header.tex
文件中使用dcolumn
命令。在Table2中,每个单元格中的left-hand数字是right-aligned,这就是我想要的。但是,docolumn
以其他我不想要的方式更改了格式:
- 列 headers 应该看起来像 Table 1 中的列 headers,这意味着不应有斜体并且 BIO 和以下之间应该有一个 space数.
- 列宽应该更像 Table 1. 中的宽度
- 在数据列中,第一个数字和括号中的数字之间应该有一个space。例如, “89(2)”应该是“89(2)”。
- 如果可以的话,两个号码分开就更好了right-aligned。这意味着数字之间可以有一个或两个space,这取决于括号中的数字分别是两位数还是一位数。
我从这个意义上更新了我的答案,您不再需要 dcolumn
。它有点混合了使用 R 的正则表达式功能和添加原始 LaTeX 命令(例如 {\hskip 0.5em}
)。问题是,您可以在(据我所知)任何 LaTeX 环境中添加这些原语,以便格式化您的段落等。
所以使用 apply
我们 重新格式化 table 单元格的 content 取决于数字是否在括号有1个或2个数字,然后添加适当的水平间距。
通过在 print.xtable
中使用 sanitize.text.function = identity
,我们确保当 data.frame
被 xtable
处理时,这些 LaTeX 命令不会被删除。
---
title: "Test"
output:
pdf_document:
keep_tex: true
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE, message=FALSE, warning=FALSE, fig.align="center")
```
```{r}
library(xtable)
namesVec <- c("Term", "BIO 10", "BIO 20", "BIO 30",
"BIO 40", "BIO 50")
# Data frame to create table
tab1 = structure(list(Term = structure(1:5, .Label = c("Fall 2007",
"Spring 2008", "Fall 2008", "Spring 2009", "Fall 2009", "Spring 2010",
"Fall 2010", "Spring 2011", "Fall 2011", "Spring 2012", "Fall 2012",
"Spring 2013", "Fall 2013", "Spring 2014", "Fall 2014", "Spring 2015",
"Fall 2015", "Spring 2016", "Fall 2016"), class = c("ordered",
"factor")), `BIO 10` = c("89 (2)", "96 (2)", "77 (1)", "103 (3)",
"81 (1)"), `BIO 20` = c("194 (5)", "175 (3)", "176 (8)", "168 (3)",
"170 (4)"), `BIO 30` = c("153 (2)", "154 (14)", "188 (7)", "192 (9)",
"183 (8)"), `BIO 40` = c("284 (23)", "296 (5)", "267 (17)", "296 (16)",
"279 (7)"), `BIO 50` = c("88 (1)", "107 (5)", "98 (1)", "109 (7)",
"93 (5)")), .Names = paste("\textnormal{", namesVec, "}"), row.names = c(NA, 5L), class = "data.frame")
tab1 <-apply(tab1, 2, function(x) {
tmp <- nchar(gsub(".*\( ?([0-9]+).*","\1", x))
skip <-ifelse(tmp == 1, "{\\hskip 1em}(", "{\\hskip 0.5em}(")
ifelse(tmp == 1, gsub(x, pattern = " \(", replacement = paste("{\\hskip 1em}(")),
gsub(x, pattern = " \(", replacement = paste("{\\hskip 0.5em}(")))
})
```
```{r results="asis"}
print.xtable(
xtable(tab1,
label="tab:tab2",
caption = "Columns aligned at left parenthesis",
align=c("llrrrrr")),
size="small",
include.rownames=FALSE, comment=FALSE, caption.placement="top"
, sanitize.text.function = identity)
```
这与 Martin 的方法类似;现在已编辑掉答案。将数字和括号中的数字分别对齐可能更容易(至少对于像我这样的 non-latex 演讲者而言),因此将它们分成单独的列。然后,您可以使用 \multicolumn
对列进行分组,并定义 headers(参见 possible to create latex multicolumns in xtable?)
```{r results="asis", echo=FALSE}
tab1 = structure(list(Term = structure(1:5, .Label = c("Fall 2007",
"Spring 2008", "Fall 2008", "Spring 2009", "Fall 2009", "Spring 2010",
"Fall 2010", "Spring 2011", "Fall 2011", "Spring 2012", "Fall 2012",
"Spring 2013", "Fall 2013", "Spring 2014", "Fall 2014", "Spring 2015",
"Fall 2015", "Spring 2016", "Fall 2016"), class = c("ordered",
"factor")), `BIO 10` = c("89 (2)", "96 (2)", "77 (1)", "103 (3)",
"81 (1)"), `BIO 20` = c("194 (5)", "175 (3)", "176 (8)", "168 (3)",
"170 (4)"), `BIO 30` = c("153 (2)", "154 (14)", "188 (7)", "192 (9)",
"183 (8)"), `BIO 40` = c("284 (23)", "296 (5)", "267 (17)", "296 (16)",
"279 (7)"), `BIO 50` = c("88 (1)", "107 (5)", "98 (1)", "109 (7)",
"93 (5)")), .Names = c("Term", "BIO 10", "BIO 20", "BIO 30",
"BIO 40", "BIO 50"), row.names = c(NA, 5L), class = "data.frame")
tab2 <- cbind(tab1[1], do.call(cbind.data.frame, lapply(tab1[-1], function(x)
do.call(rbind, strsplit(as.character(x), " ")))))
addtorow <- list(list(0), paste(names(tab1)[1], paste0('& \multicolumn{2}{l}{', names(tab1)[-1], '}', collapse=''), '\\'))
library(xtable)
print.xtable(
xtable(tab2,
align=c("l","l", rep(c("r@{\hskip 0in}", "r"),5))),
include.rownames=FALSE, ,
add.to.row=addtorow, include.colnames=FALSE)
```