如何在每个代码块中设置knitr输出宽度?

14

我的问题:

knitr是否有选项可以使每个代码块都能够设置R的width选项?

如果没有,是否有一个很好的理由(即根据knitr模型的一些基本限制)它为什么不支持?

我尝试过:

为了展示我所希望的,这里有一个手动编写的钩子函数,基本上做到了我想要的。(虽然我不是很喜欢它,(a)因为它很丑陋,依赖于将变量.width赋值给全局环境中,以及(b)因为它不像fig.widthout.width等预设选项那样可以直接使用。)

\documentclass[preview=true,width=3mm]{standalone}

\begin{document}

<<setup, include=FALSE, cache=FALSE>>=
options(width=60)

knit_hooks$set(width = function(before, options, envir) {
if(before) {
    .width <<- options(width=options$width) ## Set width and save 'old' value
} else {
    options(.width)}                        ## Restore width's 'old' value
})

@

First chunk uses default width
<<A>>=
c("aaaaa", "bbbbb", "ccccc", "ddddd", "eeeee", "fffff", "ggggg", "hhhhh")
@

Second chunk uses narrower supplied width, but then resets width to
pre-existing value \dots
<<B, width=20>>=
c("aaaaa", "bbbbb", "ccccc", "ddddd", "eeeee", "fffff", "ggggg", "hhhhh")
@

\noindent \dots as shown by results of the third chunk
<<C>>=
c("aaaaa", "bbbbb", "ccccc", "ddddd", "eeeee", "fffff", "ggggg", "hhhhh")
@

\end{document}

在这里输入图片描述


1
我不明白。这不是每个块的宽度吗?您将默认值设置为60,对于任何没有显式更改它的块都有效。您是想永久更改默认值吗? - Tyler
1
@Tyler -- 所以我的问题是:(1)knitr中是否已经有这个功能,(2)如果没有,是否有一些启发性的原因呢?我还想知道(3)如何调整我的钩子函数,使其不需要将.width分配到全局环境中。我尝试过但无法找到避免这种情况的解决方法。这些就是我提出问题的原因,尽管我已经拼凑出了一个基本可行的解决方案... - Josh O'Brien
1
更大的背景是我正在编写 knitr 代码,以便将代码和图像并排排版。如果有一个可以传递到产生这种并排输出的代码块中的 output.width 选项,那么这样做会更简单一些。 - Josh O'Brien
1
我不知道knitr中是否已经有类似的功能,但您可以使用local来解决 #a(全局变量)的问题,在您的设置调用中替换为类似 knit_hooks$set(width=local({ .width <- 0 ; function(before, options, envir) { if (before) .width <<- options(width=options$width) else options(.width) } ; })) 的东西。 - r2evans
@r2evans -- 很有趣的想法,但你真的让它工作了吗?knit_hooks$set()期望传递三个参数(beforeoptionsenvir)的函数定义,这不是你提出的要交给它的东西... - Josh O'Brien
显示剩余3条评论
2个回答

6
尽管这并不是解决整个问题的方法,但你代码中的第一个问题是它使用.width变量污染了全局环境。可以使用local()作为闭包机制来解决这个问题,封装变量以避免在全局变量空间中发生冲突。
因此,如果你将knit_hooks$set调用替换为:
knit_hooks$set(width=local({
    .width <- 0
    function(before, options, envir) {
        if (before) .width <<- options(width=options$width)
        else options(.width)
    }
}))

它可以在不将.width强制放入全局环境的情况下产生相同的结果。 你上面的代码剩余部分仍然像以前一样工作,并且输出也相同。

更多内容可以在help(local)中查看,详见《高级R编程》(Hadley Wickham),并且有很多例子可以参考,如@JeroenOoms的OpenCPU


谢谢。非常聪明。我猜构建一个更通用的 R.opts 钩子函数也同样简单,它可以接受任意全局选项列表(例如 list(width=60, warn=1, scipen=10)),并仅为当前块设置这些选项。 - Josh O'Brien
请使用以下代码替换原有代码:knit_hooks$set(r.opts=local({ ropts <- NA ; function(before, options, envir) { if (before) ropts <<- options(options$r.opts) else options(ropts) ; } })),并将 <<B, width=20>>= 替换为 <<B, r.opts=list(width=20)>>= - r2evans
@user101089:你说得对,称其为“width”肯定是有问题的,但只是为了演示而已;我认为r.widthconsole.width可能会更清晰一些,因为在我看来,output.width可能描述的是knit文档的渲染输出。我认为稍微更好的解决方案在我的先前评论中,它可以调整任意R选项。(@Yihui可能会争辩说你总是可以直接在代码块中执行options(width=20)。我们拭目以待。) - r2evans
2
新的代码块选项R.options现在已经在knitr的开发版本中了。 - Yihui Xie
上面的被接受的答案对我没用,但我很高兴看到更通用的解决方案在knitr 1.6中支持了R.options。在最近的RStudio中,当你输入<<>>=时,它甚至会出现作为建议的块选项。太好了! - user101089
显示剩余5条评论

0
这也解答了我的问题。我正在使用Beamer和knitr来制作幻灯片,有时我会使输出更小(例如,为了在一个部分中得到一个方差分析表而不需要换行)。例如,我有一个默认宽度为50,但现在我可以这样做:
{\small 
<<width=55>>=
  summary(my.aov)
@
}

我在同一行上获取P值,就像平方和一样,但是后续块的宽度仍为50。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接