我想将一些内容嵌入R
到 LaTeX 文档中。经过一番谷歌搜索,我发现了Sweave
可以knitr
做到这一点的方法。我用它编译了一个简单的示例,Sweave
它运行正常。
如果有人能回答以下问题我将不胜感激:
- 还有其他方法吗?
- 不同方法各有哪些优点?
请注意,我想从命令行运行 LaTeX。我对 IDE 解决方案不感兴趣。
TIA 感谢您的帮助。
答案1
0. 总结
knitr
优于Sweave
,并且ezknitr
knitr
是一个值得使用的包装器- 特别是如果您只从命令行构建文档(但这限制了您使用 R Markdown;见下文);我不认为有集成ezknitr
使用的 IDE(至少在撰写本文时没有) - 因为它可以更轻松地确保目录和路径都是正确的。
knitr
/ ezknitr
(以下仅knitr
)可能或可能不优于Thruston 建议的方法方法,取决于您的使用情况。
下面对这些观点进行一些论证并附上例子。
1.knitr
对比Sweave
knitr
Sweave
出于各种原因,它比 更受欢迎。选择knitr
的两个主要原因Sweave
是 (i) 可以更好地与tikzDevice
在knitr
,以及 (ii) 块选项更加灵活。
1.1.knitr
和tikzDevice
我应该提一下我从未真正使用过的警告Sweave
,但从阅读互联网上的博客文章来看,使用它比使用要tikzDevice
简单knitr
得多Sweave
。
您可能希望在图表中使用这两个原因tikzDevice
是因为 (i) 您可以在标签和标题(尤其是数学)中获得更好的排版,以及 (ii) 您可以在文档中的文本和文档内图表中的文本之间获得一致的字体。以下是显示这两件事的MWE。1
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{decorations.pathreplacing}
\tikzstyle{underbrace style}=[decorate,decoration={brace,raise=5mm,amplitude=3pt,mirror},color=gray]
\tikzstyle{underbrace text style}=[font=\scriptsize, below, pos=.5, yshift=-8mm]
\newcommand*{\MyContrivedTitle}{%
\begin{tikzpicture}
\node (MyTitle) {Average miles per gallon by gear (and some math for fun: $\int_{a}^{b} x^2 dx$)};
\draw [underbrace style] (MyTitle.north west) -- (MyTitle.north east) node [underbrace text style] {My contrived title with \texttt{tikz}};
\end{tikzpicture}}
\begin{document}
\section{Introduction}
<<setup, include=FALSE, cache=FALSE>>=
### Set the global chunk options
### See http://yihui.name/knitr/options/#chunk_options
library(knitr)
opts_chunk$set(cache=FALSE,
echo=FALSE,
message=FALSE,
warning=FALSE,
highlight=FALSE,
sanitize=FALSE,
tidy=TRUE,
dev='tikz',
fig.env='figure',
fig.show='hold',
fig.lp='fig:',
fig.align='center',
fig.pos='htbp',
out.width='.75\\textwidth'
)
@
As can be seen in Figure \ref{fig:car-plot}, \ldots
<<car-plot,fig.cap='A graphic produced by \\texttt{knitr} and \\texttt{tikzDevice}'>>=
library(dplyr) # a good package for data manipulation
library(ggplot2) # a good package for graphing
data <- mtcars %>%
group_by(gear) %>%
summarise(SD = sd(mpg),
SE= (SD/sqrt(length(mpg))),
MEAN = mean(mpg)
)
carplot <- ggplot(data,
aes(x = factor(gear),
y = MEAN
)
) +
geom_bar(stat = "identity") +
geom_errorbar(aes(ymin = MEAN - SE,
ymax = MEAN + SE
),
width = 0.25,
size = 0.5
) +
ggtitle("\\MyContrivedTitle") +
xlab("Gear") +
ylab("Mean MPG") +
theme(plot.margin=unit(c(1,0,0,0),"cm"))
carplot
@
\end{document}
这将产生以下输出:
1.2. 更通用的块选项knitr
(与 相比Sweave
)
此示例直接来自易晖在knitr
(但不是Sweave
)中,可以延迟某些块选项的评估,以便您可以在标题中包含 t 检验的 p 值。
\documentclass{article}
\begin{document}
\section{Introduction}
<<setup, include=FALSE, cache=FALSE>>=
library(knitr)
opts_knit$set(eval.after = 'fig.cap') # evaluate fig.cap after the chunk
opts_chunk$set(cache=FALSE,
echo=FALSE,
message=FALSE,
warning=FALSE,
highlight=FALSE,
sanitize=FALSE,
tidy=TRUE,
dev='tikz',
fig.env='figure',
fig.show='hold',
fig.lp='fig:',
fig.align='center',
fig.pos='htbp',
out.width='.75\\textwidth'
)
@
<<t-test, fig.cap=paste("The P-value is", t.test(x)$p.value)>>=
x = rnorm(100)
boxplot(x)
@
\end{document}
输出结果为:
2.knitr
对比Thruston 建议的方法
如果你希望将 R 代码和 LaTeX 代码分开,Thruston 建议的方法并不一定是更好的选择,因为有可能在 LaTeX 文档中使用外部 R 代码knitr
话虽如此,这两种不同的方法还是有一些优点和缺点值得一提。
knitr
一些优点Thruston 建议的方法是:
- 您拥有一份经过文学编程的文档,因此可以进行可重复的研究/工作流程/等等。
- 人为错误的余地很小(当然,除了编写 R 代码)。
- 在文档和图形中获得一致的字体更容易(尽管如果你使用Thruston 建议的方法并让你的 R 代码输出一个 PDF,其中嵌入了你想要使用的字体)。
的一些优点Thruston 建议的方法以上knitr
是:
- 每次编译文档时,R 代码都不会被评估,因此编译时间会更快,如果你在 R 中绘制大量图形或进行大量计算,编译时间可能会更快(尽管这可以在一定程度上缓解缓存)。
- 您的源代码可能会更加人性化(但这会引入更多人为错误的空间)。例如,以下代码块可能比后续代码块更难读:
用来knitr
使文档更具有可重复性(但在可读性上有所妥协):
\begin{tabular}{lcc}
& Adults & Children \\
Active sentences & \Sexpr{data[data$GROUP == "Adults" & data$CONDITION == "Active",]$ACCURACY} & \Sexpr{data[data$GROUP == "Children" & data$CONDITION == "Active",]$ACCURACY} \\
Passive sentences & \Sexpr{data[data$GROUP == "Adults" & data$CONDITION == "Passive",]$ACCURACY} & \Sexpr{data[data$GROUP == "Children" & data$CONDITION == "Passive",]$ACCURACY} \\
\end{tabular}
不使用knitr
而是复制并粘贴 R 脚本输出的值(因此可以说更易于人读,但也引入了更多人为错误的可能性):
\begin{tabular}{lcc}
& Adults & Children \\
Active sentences & 98 & 93 \\
Passive sentences & 94 & 67 \\
\end{tabular}
3.ezknitr
对比knitr
更新:目前似乎ezknitr
无法处理.Rnw
文件。希望将来可以添加此功能(请参阅这里;另请参阅这里)。
我还没有亲自尝试过ezknitr
,所以一旦有机会,我将不得不更新这个答案,但是博客文章介绍ezknitr
这表明它解决了有时令人沮丧的路径和工作目录问题。引用博客文章中的一段话:
一个常见的挫败之处在于knitr
它假设源文件所在的目录应该是工作目录,但这通常不是真的。ezknitr
通过让您完全控制所有输入和输出的位置来解决此问题,并添加了一些其他便捷功能。两个主要函数是ezknit()
和ezspin()
,它们是和knitr
的包装器,用于使渲染 markdown/HTML 文档更容易。knit()
spin()
这可能很有用,特别是当您从命令行为包含许多不同目录中的文件的项目构建文档时。
4. 编译(从命令行)
为了后代:RStudio— 在大多数情况下 — 是一个适合与knitr
LaTeX 一起使用的良好 IDE(一旦涉及到参考书目,事情就会变得棘手)。
您说您对从命令行编译文档更感兴趣。使用 时knitr
,您会编辑一个.Rnw
文件,然后使用knitr
的knit()
函数处理它,该函数会输出一个.tex
文件。您永远不想.tex
直接编辑该文件。应对文件进行所有更改.Rnw
,然后使用 重新生成该.tex
文件knit()
。
因此,您可以通过执行以下操作从命令行构建文档:
Rscript -e "library(knitr); knit('my_file.Rnw')" # this command produces my_file.tex
pdflatex my_file.tex # this command produces my_file.pdf
您还可以轻松编写某种 batch/make/bash 脚本来执行此操作。2
笔记
- 似乎是一个问题当将
dev
块选项设置tikz
为knitr
和正在加载fontspec
,因此很遗憾,无法在 XeLaTeX 或 LuaLaTeX 中使用任意字体。希望这个问题能尽快得到解决。 - 有
arara
目前使用构建.Rnw
文档时出现问题从命令行,但在即将推出的版本中arara
,Paulo 承诺提供与 配合使用的开箱即arara
用且功能齐全的规则knitr
,因此应该可以在(不久的将来)使用arara
它来构建文档。.Rnw
答案2
基本方法就是将它们分开。我最近一篇论文的工作流程如下:
我编写了一个 R 脚本来计算统计数据并生成(a)图表和(b)数字表。
该脚本生成的图表要么是 as
eps
(我使用 LaTeX 格式),要么是 aspng
(论文的在线版本需要)。图表有很长的描述性文件名。这些表格是使用 R
sink()
函数捕获和的输出并aggregate
以纯文本形式生成的table
。我编写了一个嵌入图表的 LaTeX 文档
includegraphics
(使用很长的描述性名称,所以我知道哪个是哪个)。对于表格,我只是将表格输出文件中的文本复制到我的 LaTex 源中,然后使用编辑器宏。
当我需要进行更改时,图表很容易:我只需运行 R 脚本来重新创建文件
eps
,然后重新运行 LaTeX 来重新创建最终的pdf
.表格有点难,但也不难:我只是用 R 生成的文本输出文件替换了每个表格的主体,然后重新标记它们。由于我使用了宏,并且我在 LaTeX 源中保留了表格页眉和页脚,所以每个表格只需要一两秒钟。
这种方法的主要优点是简单;我保留了 LaTeX 源中对格式的所有控制。主要缺点是每次更改时我都必须半手动地重新创建表格,并且我必须维护两个脚本。另一方面,在这种情况下,拥有一个可以生成两种不同格式的同一张图表版本的 R 脚本非常有用。
代码
png
这是我在和之间切换的 R 函数eps
。
desired.format = "eps"
fig <- function(name) {
if(desired.format=="png") {
png(filename=sprintf("%s-A.png",name), width=1536, height=1152, res=144)
}
else if (desired.format=="eps") {
postscript(file=sprintf("%s-A.eps",name), onefile=FALSE, horizontal=FALSE, paper="special", width=10, height=7.5)
}
}
答案3
还有其他方法吗?
是的,在使用 R 块(R noweb 文件)处理 LaTeX 文件时, 可以lazyWeave.
从头开始创建 LaTeX 文档。Sweave
knitr
lazyWeave
除此之外,值得注意的是其他 R 包就像著名的 xtable
并且Hmisc
可以生成某种类型的 LaTeX 代码。
有何优点?
说实话,我从未使用过lazyWeave
,但根据文档,它提供了在 R 中编写完整文档 LaTeX 代码的功能,而无需过多地处理 LaTeX 代码,这是设计带有自定义和复杂表格的报告的主要优势。但同一文档也警告说,这种knitr
方法更简单(即,处理lazyWeave
函数是一种值得怀疑的优势),lazyWeave 是一种“使用 LaTeX 编写报告的相当低效的方法”,并且“仅旨在提供 LaTeX 的最基本功能”。
就文档而言,这是 R 软件包的典型特征,每个函数都经过系统描述,甚至还附有一些示例,但仍然很难猜测如何将它们组合起来以生成工作报告,因为一些错误的方面没有得到很好的解释。我留下了一个练习,如何发现您需要选择 lazyWeave_latexComments="latex"
避免在输出中使用 HTML 注释,或者为什么只有lazy.matrix(df)
它自己工作(您会在输出中看到 LaTeX 代码),但lazy.write( ...,lazy.matrix(df),...)
对于非工作示例,尽管应该可以工作,但事实并非如此。
尽管如此,下面显示的是我第一次相当成功的测试。
其他软件包如xtable
或Hmisc
只能生成 LaTeX 块,但幸运的是可以毫无问题地与 Sweave/knitr 块一起使用(分别使用选项results='tex'
或results='asis'
)甚至lazyWeave
。
lazyWeawe MWE
1)运行以下 R 脚本。(假设lazyWeawe
已经安装)
# R script
library(lazyWeave)
df <- data.frame(A=c(1,2,3),B=c("a","b","c"),C=c(3.3,5.3,7.5))
options(lazyReportFormat="latex",lazyWeave_latexComments="latex")
lazy.write(
lazy.file.start(title="My MWE of lazyWeave",author="Fran",date="\\today"),
lazy.toc(),
lazy.section("Introduction", ordered=TRUE),
lazy.text("This MWE \\LaTeX\\ example was made with recyclable electrons."),
lazy.section("Example data frame", ordered=TRUE),
lazy.matrix(df,cat=F),
lazy.section("Mean test", ordered=TRUE),
lazy.text("The mean of C is ",round(mean(df$C),1)," that is not 0 with p=",round(t.test(df$C)$p.value,3),"."),
lazy.file.end(),
OutFile="Example.tex")
1b) 编辑输出文件Example.tex
并删除包breakurl
以Sweave
避免编译错误,然后保存。这一点不应该存在。可以在函数中添加其他 LaTeX 包,但不删除默认包。然而,这是一个小问题。如果您需要一个没有任何版本的工作文件,那么通过甚至重写 函数lazy.file.start
构建自己的文件应该很容易。lazy.text("\\documentclass ...")
lazy.file.start()
2)编译 Example.tex
。结果应为:
答案4
对 Thruston 的替代方法 v 的一些批评knitr
:
实际上,可以从一个
.Rnw
文件创建多个图输出(仅包括pdf
LaTeX 输出中的版本)。在我最近做的一份报告中,每次编译文档时,每个图都呈现为:a. 一个
pdf
b.a
png
c. Windows 增强型图元文件
d. PowerPoint 幻灯片
此外,我还编写了一个钩子,将提供给每个
ggplot
图表的数据写入文件。所有这些都会增加编译时间(尽管实际上并不多),并且需要额外的设置。但这只是将附加函数传递给中的块选项csv
的问题。例如,将为每个图生成一个和。dev
knitr::opts_chunk$set()
knitr::opts_chunk$set(dev = c("pdf", "png"), fig.ext = c("pdf", "png"))
pdf
png
不要低估你产生散文以及通过 R 生成的表格和图表。例如,我们的报告研究了特定税收变化对预算收入和受影响人数的影响。在发布前几周,我们决定对这些税收提案进行轻微修改。如果我们没有该文件的文字副本,那么可能会出现以下句子:
我们的提案(预计2017-18年筹集10亿美元)将仅影响最贫困的五分之一家庭中的13%。
报告中到处可见的这些功能,很有可能无法更新。相反,它们只需修改脚本顶部的一个值即可自动更新。
我们的提案(预计2017-18年筹集13亿美元)将仅影响最贫困的五分之一家庭中的14%。
而且由于 R 可以创建对象,因此您无需在 中使用冗长的 R 表达式
\Sexpr
。相反,只需在一个块中评估所需的对象,然后将其传递给<<revenue_from_policy>>= revenue1718_from_policy <- ... calculations ... @ <<prop_affected_bottom_quintile>>= prop_affected_bottom_quintile <- ... calculations ... @ Our proposal (estimated to raise \Sexpr{revenue1718_from_policy} in 2017-18) would affect only \Sexpr{percent(prop_affected_bottom_quintile)} of the poorest one-fifth of households.
RStudio
变得knitr
非常容易。你只需输入Compile PDF
一个Rnw
文件,它就可以工作。它还允许代码折叠之类的操作,并提供在 REPL 中运行代码块的键盘快捷键。话虽如此,作为一个纯粹的 LaTeX IDE,RStudio 与其他 IDE 相比黯然失色。语法突出显示是基本的,错误解析和代码完成基本上不存在。此外,你基本上只能在文件上运行pdflatex
或。特别是,你不能(直接)运行等。我相信在今年下半年(2016 年 9 月)这些功能将有实质性的改进,但目前还没有。话虽如此,RStudio 是 R 的至高无上的 IDE。而且切换到另一个 IDE 来编写你的散文很简单。xelatex
tex
biber
我发现
tikzDevice
相当笨重。某些字体存在问题,错误很常见,而且基本上是采用或放弃文件的方法tikz
——很难编辑 tikz。我认为您最好使用块选项fig.showtext=TRUE
并library(sysfonts)
在图表中应用一致的字体。这不是 的缺点knitr
,只是我发现这不是tikzDevice
它的优点之一。
要获取相同的字体,请使用以下方法(对于helvet
):
<<font_add>>=
library(showtext)
library(sysfonts)
library(knitr)
font.add("helvet",
regular = "C:/Program Files/MiKTeX 2.9/fonts/type1/urw/helvetic/uhvr8a.pfb",
bold = "C:/Program Files/MiKTeX 2.9/fonts/type1/urw/helvetic/uhvb8a.pfb",
italic = "C:/Program Files/MiKTeX 2.9/fonts/type1/urw/helvetic/uhvro8a.pfb")
ggplot2::update_geom_defaults("text", list(family = "helvet"))
ggplot <- function(...) ggplot2::ggplot(...) + ggplot2::theme_grey(base_family = "helvet")
@
合并booktabs
很简单xtable
:
<<mytable, results='asis'>>=
library(xtable)
print.xtable(xtable(data.frame(abdef = 1:5, ghif = 1:5)), booktabs = TRUE)
@
我已经使用了此答案中描述的功能https://stackoverflow.com/q/36660598/1664978,强调了自动但简洁的表格生成是可以的。