knitr使代码中的PDF成为(在我的情况下)R和LaTEX的组合。可以用儿童文件组装文件。
正如我现在使用的那样,文档是由全局变量组合而成,传入和传出每个子文档。这样可以很容易地生成意大利面条代码。
有没有办法让R变量成为子doc的“本地”?如何明确导出变量?
我可以在子doc的末尾清空每个局部变量,但我想知道是否有一些合理的正式机制来放松子文档之间的代码耦合。
答案 0 :(得分:14)
knitr
评估公共环境中的所有块(由knit_global()
返回)。这是设计的;就像源文件中的所有代码都在同一环境中运行一样,所有块都在公共环境中执行。这同样适用于child documents,因为它们(原则上不是技术上)只是主文档的一部分,外部化为另一个文件。
这不一定会导致意大利面条代码:没有什么能阻止用户使用函数和其他对象来组织knitr
文档中的代码/数据。但可能很少有用户这样做......
因此,没有用于块/子文档的封装机制的原因是它们假定以共享公共环境,因为它们是 one (main)的一部分文档。
但是, 可以包含子文档,使用户能够控制对象子文档和主文档共享。该解决方案基于函数knit_child()
,它与chunk option child
非常相似。直接调用knit_child()
(通过child
选项隐式调用)的优点是可以设置envir
参数,该参数定义了代码块所在的环境。被评估" (来自?knit
)。
在knit_child()
左右,我编写了包装器IsolatedChild
来简化问题:
IsolatedChild <- function(input, ...) {
evaluationEnv <- list2env(x = list(...), parent = as.environment(2))
cat(asis_output(knit_child(input = input, envir = evaluationEnv, quiet = TRUE)))
return(evaluationEnv)
}
传递给...
的参数将在子文档中提供。 (将它们命名,请参见下面的示例。)该函数返回已评估子文档的环境。
在parent
中指定list2env
至关重要,我根据this answer选择as.environment(2)
。否则parent
将默认为parent.frame()
,从而将knit_global()
中的对象公开给子文档。
assign
可用于在全球环境中提供从IsolatedChild
返回的对象。
请注意cat(asis_output())
周围的knit_child
构造,以确保子文档的输出正确包含在主文档中,而不管当前块中的results
设置。
在转向这个例子之前,有两个最后的评论:
knit
子文档并使用\include{}
将其包含在主文档中。knitr
个选项。此外,这两个文件都可以通过副作用进行互动(options()
,par()
,打开的设备......)。下面是完整的示例/演示:
inputNormal
没有什么特别之处,它只是对正常行为的证明。 inputHidden
演示了IsolatedChild()
的使用,将两个变量传递给子文档。 IsolatedChild()
返回这两个值以及在子项中创建的第三个对象。check
演示了传递给&#34;隔离的孩子&#34;不要污染全球环境。import
显示assign
如何用于&#34;导入&#34;来自孤立的孩子的对象&#34;对全球环境。<强>
main.Rnw
强>
\documentclass{article}
\begin{document}
<<setup>>=
library(knitr)
objInMain <- TRUE
IsolatedChild <- function(input, ...) {
evaluationEnv <- list2env(x = list(...), parent = as.environment(2))
cat(asis_output(knit_child(input = input, envir = evaluationEnv, quiet = TRUE)))
return(evaluationEnv)
}
@
<<inputNormal, child="child_normal.Rnw">>=
@
<<inputHidden, results = "asis">>=
returned <- IsolatedChild(input = "child_hidden.Rnw",
passedValue = 42,
otherPassedValue = 3.14)
cat(sprintf("Returned from hidden child: \\texttt{%s}",
paste(ls(returned), collapse = ", ")))
@
<<check, results = "asis">>=
cat(sprintf("In global evaluation environment: \\texttt{%s}",
paste(ls(), collapse = ", ")))
@
<<import, results = "asis">>=
assign("objInChildHidden", returned$objInChildHidden)
cat(sprintf("In global evaluation environment: \\texttt{%s}",
paste(ls(), collapse = ", ")))
@
\end{document}
<强>
child_normal.Rnw
强>
<<inChildNormal>>=
objInChildNormal <- TRUE # visible in main.Rnw (standard behaviour)
@
<强>
child_hidden.Rnw
强>
Text in \texttt{child\_hidden.Rnw}.
<<inChildHidden>>=
objInChildHidden <- TRUE
print(sprintf("In hidden child: %s",
paste(ls(), collapse = ", ")))
# Returns FALSE.
# Would be TRUE if "parent" weren't specifiet in list2env().
exists("objInMain", inherits = TRUE)
@
<强>
main.pdf
强>