eip*_*i10 13 formatting latex r knitr r-markdown
我有一张表,我想从rmarkdown
文档中以PDF格式输出.但是,由于我有限的乳胶技能,我无法弄清楚如何获得跨越列,单元格边框和字体面,就像我希望它们使用xtable
各种Latex
添加方式一样.
我能够使用包中的FlexTable
函数获得我想要的东西ReporteRs
,但它看起来FlexTable
只能用于rmarkdown
生成html输出,但不能用于PDF输出.
所以,我正在寻找帮助格式化我的表使用xtable
,或任何其他R包或(可能是自定义)R函数,可用于以编程方式为PDF输出创建合理复杂的表.此外,如果有一些方法可以FlexTable
同时使用PDF输出,那也会很棒.
下面我创建一个表使用,FlexTable
这样你就可以看到我的目标.接下来,我提供了一个示例rmarkdown
文档,显示了我在使用时创建类似表的(有点蹩脚)努力中所处的位置xtable
.
ReporteRs::FlexTable
版首先,让我们创建将进入表格的数据:
library(ReporteRs)
x = structure(c(34L, 6L, 9L, 35L), .Dim = c(2L, 2L), .Dimnames = structure(list(
Actual = c("Fail", "Pass"), Predicted = c("Fail", "Pass")), .Names = c("Actual",
"Predicted")), class = "table")
x=cbind(x, prop.table(x), prop.table(x, 1), prop.table(x,2))
x[, -c(1,2)] = sapply(x[,-c(1,2)], function(i) paste0(sprintf("%1.1f", i*100),"%"))
x = cbind(Actual=rownames(x), x)
Run Code Online (Sandbox Code Playgroud)
现在为FlexTable创建和格式化:
# Set up general table properties and formatting
cell_p = cellProperties(padding.right=3, padding.left=3)
par_p = parProperties(text.align="right")
# Create table
ft = FlexTable(x, header.columns=FALSE, body.cell.props=cell_p, body.par.props=par_p)
# Add three header rows
ft = addHeaderRow(ft, text.properties=textBold(), c("","Predicted"),
colspan=c(1,8), par.properties=parCenter())
ft = addHeaderRow(ft, text.properties=textBold(),
value=c("", "Count", "Overall\nPercent", "Row\nPercent", "Column\nPercent"),
colspan=c(1,rep(2,4)), par.properties=parCenter())
ft = addHeaderRow(ft, text.properties=textItalic(), par.properties=parCenter(),
value=colnames(x))
# Format specific cells
ft[1:2, 1, to="header", side="left"] = borderProperties(color="white")
ft[1:2, 1, to="header", side="top"] = borderProperties(color="white")
ft[3, 1, to="header"] = textProperties(font.style="normal", font.weight="bold")
ft[ , 1] = textProperties(font.style="italic")
ft[ , 2:3] = cellProperties(padding.right=7, padding.left=7)
ft[ , 1] = cellProperties(padding.right=10, padding.left=10)
# Display ft
ft
Run Code Online (Sandbox Code Playgroud)
这是最终表格的样子(这是浏览器窗口中显示的表格的PNG截图):
现在我尝试做同样的事情xtable
.
xtable
版这是rmarkdown
文档和header.tex
文件:
---
title: "Untitled"
author: "eipi10"
date: "11/19/2016"
output:
pdf_document:
fig_caption: yes
includes:
in_header: header.tex
---
```{r setup, include=FALSE}
library(knitr)
opts_chunk$set(echo = FALSE, message=FALSE)
```
```{r}
# Fake confusion matrix to work with
x = structure(c(34L, 6L, 9L, 35L), .Dim = c(2L, 2L), .Dimnames = structure(list(
Actual = c("Fail", "Pass"), Predicted = c("Fail", "Pass")), .Names = c("Actual",
"Predicted")), class = "table")
x=cbind(x, prop.table(x), prop.table(x, 1), prop.table(x,2))
x[, -c(1,2)] = sapply(x[,-c(1,2)], function(i) paste0(sprintf("%1.1f", i*100),"%"))
x = cbind(Actual=rownames(x), x)
```
```{r use_xtable, results="asis"}
# Output the confusion matrix created above as a latex table
library(xtable)
options(xtable.comment=FALSE)
# This is a modified version of a function created in the following SO answer:
# http://stackoverflow.com/a/38978541/496488
make_addtorow <- function(row.name, terms, colSpan, width) {
# Custom row function
paste0(row.name,
paste0('& \\multicolumn{', colSpan, '}{C{', width, 'cm}}{',
terms,
'}',
collapse=''),
'\\\\')
}
addtorow <- list()
addtorow$pos <- list(-1,-1,-1,-1)
addtorow$command <- c(
"\\hline",
make_addtorow("", c("Predicted"), 8, 12),
"\\hline",
make_addtorow("", c("Count", "Percent", "Row Percent", "Column Percent"), 2, 3)
)
xtbl = xtable(x, caption="Created with xtable")
align(xtbl) <- c("|L{0cm}|", "L{1.2cm}|", rep("R{1cm}|",8))
print(xtbl,
include.rownames=FALSE,
tabular.environment="tabularx",
width="0.92\\textwidth",
add.to.row = addtorow)
```
Run Code Online (Sandbox Code Playgroud)
文件header.tex
,其用于针织上述rmarkdown文件:
% xtable manual: https://cran.r-project.org/web/packages/xtable/vignettes/xtableGallery.pdf
\usepackage{array}
\usepackage{tabularx}
\newcolumntype{L}[1]{>{\raggedright\let\newline\\
\arraybackslash\hspace{0pt}}m{#1}}
\newcolumntype{C}[1]{>{\centering\let\newline\\
\arraybackslash\hspace{0pt}}m{#1}}
\newcolumntype{R}[1]{>{\raggedleft\let\newline\\
\arraybackslash\hspace{0pt}}m{#1}}
\newcolumntype{P}[1]{>{\raggedright\tabularxbackslash}p{#1}}
% Caption on top
% http://tex.stackexchange.com/a/14862/4762
\usepackage{floatrow}
\floatsetup[figure]{capposition=top}
Run Code Online (Sandbox Code Playgroud)
这是PDF输出中的表格:
引用此评论:
我正在寻找一种方法来从rmarkdown文档中以编程方式执行此操作,而无需对格式进行硬编码,因此它具有可重现性和灵活性.
以下解决方案使用硬编码的"模板",但模板可以填充任何数据(前提是它具有相同的2x8结构).
生成的表如下所示:
完整代码如下.
基本上,最终表由9列组成,因此基本的LaTeX结构是
\begin{tabular}{|c|c|c|c|c|c|c|c|c|}
% rest of table
\end{tabular}
Run Code Online (Sandbox Code Playgroud)
但是,固定细胞的宽度很方便.这可以使用自定义列类型C
(从TEX.SE这里获取),它允许具有固定宽度的居中内容.这与重复列类型的更紧凑语法一起提供:
\begin{tabular}{|c *{8}{|C{1cm}}|}
% rest of table
\end{tabular}
Run Code Online (Sandbox Code Playgroud)
(第一列以柔性宽度为中心,然后是8个中心列,每个1cm宽).
可以使用跨越多列的单元格\multicolumn
.这些单元格也应具有固定的宽度,以便将单元格标题分成两行.请注意,假设跨越两个1cm列的单元格应该具有2cm的宽度是错误的,因为两个跨越的单元格之间具有额外的填充.一些测量显示,大约2.436cm可以提供良好的结果.
备注第一列:尽管初\multicolumn{1}{...}{...}
看起来看起来毫无用处,但它对于更改单个单元格的列类型(包括左/右)边框非常有用.我用它来删除前两行中最左边的垂直线.
\cline{x-y}
提供了仅跨越列水平线x
到y
.
把这些碎片放在一起给出:
\begin{tabular}{|c *{8}{|C{1cm}}|} \cline{2-9}
\multicolumn{1}{c|}{} & \multicolumn{8}{c|}{\textbf{Predicted}} \\ \cline{2-9}
\multicolumn{1}{c|}{} & \multicolumn{2}{c|}{\textbf{Count}} & \multicolumn{2}{C{2.436cm}|}{\textbf{Overall Percent}} & \multicolumn{2}{C{2.436cm}|}{\textbf{Row \newline Percent}} & \multicolumn{2}{C{2.436cm}|}{\textbf{Column Percent}} \\ \hline
% rest of table
\end{tabular}
Run Code Online (Sandbox Code Playgroud)
关于数据,我删除了生成的代码的最后一行,以获取:
> x <- structure(c(34L, 6L, 9L, 35L), .Dim = c(2L, 2L), .Dimnames = structure(list(Actual = c("Fail", "Pass"), Predicted = c("Fail", "Pass")), .Names = c("Actual", "Predicted")), class = "table")
> x <- cbind(x, prop.table(x), prop.table(x, 1), prop.table(x,2))
> x[, -c(1,2)] <- sapply(x[,-c(1,2)], function(i) paste0(sprintf("%1.1f", i*100),"%"))
> x
Fail Pass Fail Pass Fail Pass Fail Pass
Fail "34" "9" "40.5%" "10.7%" "79.1%" "20.9%" "85.0%" "20.5%"
Pass "6" "35" "7.1%" "41.7%" "14.6%" "85.4%" "15.0%" "79.5%"
Run Code Online (Sandbox Code Playgroud)
要以斜体设置列名和行名,请应用
colnames(x) <- sprintf("\\emph{%s}", colnames(x)) # highlight colnames
rownames(x) <- sprintf("\\emph{%s}", rownames(x)) # highlight rownames
Run Code Online (Sandbox Code Playgroud)
然后,xtable
可以使用以下代码:
print(xtable(x),
only.contents = TRUE,
comment = FALSE,
sanitize.colnames.function = identity,
sanitize.rownames.function = identity,
hline.after = 0:2)
Run Code Online (Sandbox Code Playgroud)
这个论点only.contents
抑制了封闭的tabular
环境.将身份功能分配给sanitize.colnames.function
并且sanitize.rownames.function
意味着"不要消毒".我们需要这个,因为列名和行名包含不应转义的特殊LaTeX字符(\emph
).
输出应该%rest of table
从上面替换占位符.
从概念上讲,代码xtable
仅用于生成表体而不是标题,因为手动编写标题要容易得多.
尽管整个表头是"硬编码的",但可以根据需要更改数据.
别忘\
了一秒钟逃脱一切\
!此外,必须在header(header.tex
)中添加以下内容:
\usepackage{array}
\newcolumntype{C}[1]{>{\centering\let\newline\\\arraybackslash\hspace{0pt}}m{#1}} % https://tex.stackexchange.com/a/12712/37118
Run Code Online (Sandbox Code Playgroud)
我将上面概述的所有元素包装在一个函数中PrintConfusionMatrix
,该函数可以与提供数据和列/行名称的任何2x8数据帧一起使用.
---
output:
pdf_document:
keep_tex: yes
includes:
in_header: header.tex
---
```{r, echo = FALSE}
library(xtable)
# Sample data from question
x <- structure(c(34L, 6L, 9L, 35L), .Dim = c(2L, 2L), .Dimnames = structure(list(Actual = c("Fail", "Pass"), Predicted = c("Fail", "Pass")), .Names = c("Actual", "Predicted")), class = "table")
x <- cbind(x, prop.table(x), prop.table(x, 1), prop.table(x,2))
x[, -c(1,2)] <- sapply(x[,-c(1,2)], function(i) paste0(sprintf("%1.1f", i*100),"%"))
#x <- cbind(Actual=rownames(x), x) # dropped; better not to add row names to data
PrintConfusionMatrix <- function(data, ...) {
stopifnot(all(dim(x) == c(2, 8)))
colnames(x) <- sprintf("\\emph{%s}", colnames(x)) # highlight colnames
rownames(x) <- sprintf("\\emph{%s}", rownames(x)) # highlight rownames
cat('\\begin{tabular}{|c *{8}{|C{1cm}}|} \\cline{2-9}
\\multicolumn{1}{c|}{} & \\multicolumn{8}{c|}{\\textbf{Predicted}} \\\\ \\cline{2-9}
\\multicolumn{1}{c|}{} & \\multicolumn{2}{c|}{\\textbf{Count}} & \\multicolumn{2}{C{2.436cm}|}{\\textbf{Overall Percent}} & \\multicolumn{2}{C{2.436cm}|}{\\textbf{Row \\newline Percent}} & \\multicolumn{2}{C{2.436cm}|}{\\textbf{Column Percent}} \\\\ \\hline
\\textbf{Actual} ')
print(xtable(x),
only.contents = TRUE,
comment = FALSE,
sanitize.colnames.function = identity,
sanitize.rownames.function = identity,
hline.after = 0:2,
...)
cat("\\end{tabular}")
}
```
```{r, results='asis'}
PrintConfusionMatrix(x)
```
Run Code Online (Sandbox Code Playgroud)
小智 3
add_header_above
使用KableExtra 包中的命令可以非常简单地完成此操作。您可以根据需要添加任意数量的列分组。这是我要做的:
d <- mtcars[1:5,1:5]
kable(d,longtable = T, booktabs = T) %>%
add_header_above(c(" ", "Group 1" = 2, "Group 2" = 3)) %>%
add_header_above(c("","Groups" = 5))
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
4422 次 |
最近记录: |