【问题标题】:Print a list of dynamically-sized plots in knitr在 knitr 中打印动态大小的绘图列表
【发布时间】:2016-02-15 12:35:02
【问题描述】:

我希望能够在 knitr 中打印出未确定的地块列表。我能够做到这一点,但还有一些皱纹需要熨平。即:

1) 你如何在每个绘图之前的每个页面上抑制列表索引(如 [[2]])?使用 echo=FALSE 不会做任何事情。

2) 是否可以在渲染时设置 每个绘图 的大小?我尝试在块之外设置一个大小变量,但这只能让我使用一个值,而不是每个图的不同值。

我之所以提出这个问题,是因为他们似乎在讲同一课,即制作一个情节列表。

一些示例代码:

\documentclass{article}
\usepackage[margin=.5in, landscape]{geometry}
\begin{document}

<<diamond_plots, echo = FALSE, results = 'hide'>>==
library(ggplot2)

diamond_plot = function(data, cut_type){
  ggplot(data, aes(color, fill=cut)) + 
    geom_bar() +
    ggtitle(paste("Cut:", cut_type, sep = ""))
}

cuts = unique(diamonds$cut)
plots = list()
for(i in 1:length(cuts)){
    data = subset(diamonds, cut == cuts[i])
    plots[[i]] = diamond_plot(data, cuts[i])
}
height = 3
@

<<print_plots, results='asis', echo=FALSE,  fig.width=10, fig.height=height>>=
plots
@
\end{document}

绘图的 PDF 如下所示:

【问题讨论】:

    标签: r ggplot2 knitr


    【解决方案1】:

    1) 你如何在每个绘图之前的每个页面上抑制列表索引(如 [[2]])?使用 echo=FALSE 没有任何作用。

    分别绘制列表中的每个元素 (lapply) 并隐藏 lapply (invisible) 的输出:

    invisible(lapply(plots, print))
    

    2) 是否可以在渲染每个绘图时设置它们的大小?我尝试在块之外设置一个大小变量,但这只让我使用一个值而不是每个图的不同值。

    是的。通常,当您将向量传递给与图形相关的块选项时,ith 元素用于 ith 图。这适用于“特定于图形”的选项,例如fig.capfig.scapout.widthout.height

    但是,其他图形选项是“特定于设备的”。要理解这一点,重要的是看一下optiondev

    dev:将用作图形设备来记录绘图的函数名称 [...] 选项 devfig.extfig.widthfig.heightdpi 可以是向量(更短那些将被回收),例如&lt;&lt;foo, dev=c('pdf', 'png')&gt;&gt;= 为同一个绘图创建两个文件:foo.pdffoo.png

    将向量传递给“特定于图形”选项out.height 的结果是ith 元素被用于ithplot,将向量传递给“设备特定”选项会导致 ith 元素用于 ith设备

    因此,生成动态大小的图需要对块进行一些修改,因为 一个 块无法生成具有不同 fig.height 设置的图。以下解决方案基于knitr 示例`075-knit-expand.Rnwthis post on r-bloggers.com(其中解释了this answer on SO)。

    解决方案的想法是使用块模板并使用适当的表达式扩展模板值以生成块,然后生成具有正确fig.height 设置的图。扩展的模板被传递给knit 以评估块:

    \documentclass{article}
    \begin{document}
    
    <<diamond_plots, echo = FALSE, results = "asis">>==
    library(ggplot2)
    library(knitr)
    
    diamond_plot = function(data, cut_type){
      ggplot(data, aes(color, fill=cut)) +
        geom_bar() +
        ggtitle(paste("Cut:", cut_type, sep = ""))
    }
    
    cuts = unique(diamonds$cut)
    
    template <- "<<plot-cut-{{i}}, fig.height = {{height}}, echo = FALSE>>=
        data = subset(diamonds, cut == cuts[i])
        plot(diamond_plot(data, cuts[i]))
    @"
    
    for (i in seq_along(cuts)) {
      cat(knit(text = knit_expand(text = template, i = i, height = 2 * i), quiet = TRUE))
    }
    
    @
    
    \end{document}
    

    使用knit_expand 扩展模板,将{{}} 中的表达式替换为相应的值。

    对于knit 调用,使用quite = TRUE 很重要。否则,knit 会用日志信息污染主文档。

    使用cat 对于避免隐含的print 很重要,否则会破坏输出。出于同样的原因,“外部”块(diamond_plots)使用results = "asis"

    【讨论】:

    • 赞成并接受,但我会注意到(正如您所做的那样!)由于 out.height 与 fig.height,我看到了严重的失真。如果我/有人能弄清楚如何解决可能会很严重的失真——如果我弄清楚了,我会报告回来。
    • 当我尝试将 fig.height 设置为变量时出现的错误是“选项错误 [[sprintf("fig.%s", i)]] * options$dpi : "
    • 只有在将paste0(seq_along(cuts)*4, "cm") 之类的内容传递给fig.height 时才会出现此错误消息。这是因为fig.height 必须是数字; fig.height=seq_along(cuts) 应该工作(恕我直言),但什么都不做。
    • 我知道了@user2706569 我只是想添加错误消息,以防有人可以使用它来帮助我们将 fig.height 与变量一起使用而不是 out.height。
    • 我更新了答案;新的解决方案可能更有用……
    【解决方案2】:

    您需要访问各个列表元素,否则 print 将始终打印出索引。

    不确定这是否是最干净的答案,但您可以循环打印它们。

    > print(plots)
    [[1]]
    
    [[2]]
    
    [[3]]
    
    [[4]]
    
    [[5]]
    
    > for(x in plots){print(x)}
    

    但我没有在 tex 中尝试过,只是在控制台中尝试。

    【讨论】:

    • 奇怪的是,索引仍然显示。我隐约记得之前尝试过并且很惊讶。关于动态改变 fig.height 的任何想法?
    • 不好玩的想法。我的大部分输出都是在 markdown 中完成的,如果我想自动化绘图的大小,我必须自己放置 html,因为你不能将参数传递给那个 knitr 块。如果您只有 5 个图,请手动进行(单个 r 代码块)。否则,做一个,看看原始乳胶,然后复制它,更改您需要的参数,然后使用 r 代码直接注入。我相信“asis”标志允许您直接从 r 函数传递乳胶输出
    • 嗯,很有趣。不幸的是,我正在尝试编写一个应用程序,该应用程序将通过不同的输入实现完全自动化。我可能只是将图形大小设置为某个常数,然后对数据进行切片以适应图形大小,而不是相反。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-31
    • 2017-07-05
    • 1970-01-01
    • 2020-12-12
    • 2014-04-19
    • 2023-01-23
    • 1970-01-01
    相关资源
    最近更新 更多