【问题标题】:Rmarkdown: Explicitly specify the figure size of a plot within a chunkRmarkdown:显式指定块内绘图的图形大小
【发布时间】:2022-04-14 09:15:06
【问题描述】:

我正在使用 RMarkdown 在功能上使用 results = 'asis'purrr::map 创建文档。在每次purrr 迭代中,都会从块中产生多个图。它们中的大多数大小相同,并且可以使用图形大小的块选项进行设置。然而,一两个需要有不同的大小。由于循环/映射的设置方式,无法将代码分成不同的块。

我找到的最接近的是http://michaeljw.com/blog/post/subchunkify/,但是当我在需要不同大小的绘图上使用它时,它会导致使用 print() 函数输出的第一次迭代的绘图在 subchunkify 的绘图位置被回收.

有没有一种不同的、不那么老套的方法来做到这一点?或者在 subchunkify 代码中是否有一些可以修复的明显内容?

这里是subchunkify()

subchunkify <- function(g, fig_height=7, fig_width=5) {
  g_deparsed <- paste0(deparse(
    function() {g}
  ), collapse = '')

  sub_chunk <- paste0("
  `","``{r sub_chunk_", floor(runif(1) * 10000), ", fig.height=", fig_height, ", fig.width=", fig_width, ", echo=FALSE}",
  "\n(", 
    g_deparsed
    , ")()",
  "\n`","``
  ")

  cat(knitr::knit(text = knitr::knit_expand(text = sub_chunk), quiet = TRUE))
}

【问题讨论】:

    标签: r r-markdown


    【解决方案1】:

    您可以为地块创建所有规格的列表,然后使用purrr::pwalk

    ```{r, echo = FALSE, results = 'asis'}
    library(ggplot2)
    library(purrr)
    plots <- map(1:3, ~ggplot(mtcars, aes(wt, mpg)) + geom_point())
    specs <- list(plots, fig_height = 1.5, fig_width = list(2, 3, 4))
    pwalk(specs, subchunkify)
    ```
    

    【讨论】:

    • 这不是问题。问题是,尽管使用了 runif(),但文件似乎在循环的每次迭代中都以相同的文件名结束。
    【解决方案2】:

    这可能为时已晚,但我想分享我使用subchunkify() 破解重用绘图问题的方法。

    subchunkify() 的主要思想是将情节嵌入到伪子块中。每个伪子块都需要一个唯一的名称才能在编织时正确引用 最终文件。 Subchunkify() 使用随机数生成器 - runif() 来获得唯一的 pname,除了处理循环或复杂的降价块之外,它大部分时间都有效。

    根据我的观察,重用绘图问题的原因是锁定了随机数种子。 我怀疑编织过程错误地将种子锁定在复杂的降价结构中 - 比如 set.seed(),这导致从 runif() 获得相同的随机数列表,最终在多个位置引用相同的图。

    添加后缀 id 可以解决此问题,因为它保留了唯一的子块名称。另一种 hacky 方法是在每次需要 subchunkify() 时解锁随机数种子。

    subchunkify <- function(g, fig_height=7, fig_width=5, id = NULL) {
      rm(.Random.seed, envir = globalenv()) # to remove locked seed
      g_deparsed <- paste0(deparse(function() {g}), collapse = '')
      sub_chunk <- paste0("
      `","``{r sub_chunk_", id, "_", floor(runif(1) * 100000), ", fig.height=", fig_height, ", fig.width=", fig_width, ", echo=FALSE}",
        "\n(", 
      g_deparsed
      , ")()",
      "\n`","``
      ")
    
      cat(knitr::knit(text = knitr::knit_expand(text = sub_chunk), quiet = TRUE))
    }
    

    rm(.Random.seed, envir = globalenv()) 是唯一添加的代码行。对我来说,这个快速修复就像一个魅力。

    顺便说一句,我还鼓励在随机数中包含更多数字。 runif() 偶然可以通过足够的迭代输出相同的数字。将floor(runif(1) * 10000) 用于单个降价文档中的 50 个嵌入图,它实际上有大约 10% 的机会至少有一个冲突。使用floor(runif(1) * 1000000) 而不是floor(runif(1) * 10000) 以减少意外发生随机数冲突的机会。

    【讨论】:

      【解决方案3】:

      所以我还没有找到subchunkify() 的替代方案,但是我确实解决了这个问题,它在每次循环迭代中重用相同的图(尽管我还没有深入研究为什么会这样)。

      我向subchunkify() 添加了一个id 参数并将其包含在文件名中,然后在我的循环/映射中创建了一个id 值,该值将是每次迭代中唯一的变量组合每一个。

      subchunkify <- function(g, fig_height=7, fig_width=5, id = NULL) {
        g_deparsed <- paste0(deparse(
          function() {g}
        ), collapse = '')
      
        sub_chunk <- paste0("
        `","``{r sub_chunk_", id, "_", floor(runif(1) * 10000), ", fig.height=", fig_height, ", fig.width=", fig_width, ", echo=FALSE}",
        "\n(", 
          g_deparsed
          , ")()",
        "\n`","``
        ")
      
        cat(knitr::knit(text = knitr::knit_expand(text = sub_chunk), quiet = TRUE))
      }
      

      所以我不确定为什么subchunkify 中的runif 未能在每次迭代中产生不同的文件名。我怀疑它与knitr 缓存的工作方式有关。我注意到,如果我的循环的后续迭代最终通过相同的条件链生成图 A,那么图 A 将在条件链匹配的任何地方重复使用。但是,如果在不同的条件分支上进行迭代以生成图 B,它将正确生成新图。 (但是,图 B 将在所有具有相同条件分支结尾的地方重用)。

      这仍然不能解释为什么我用id 引入一个唯一的文件名有效,但使用runif 不能,因为在这两种情况下文件名都应该是唯一的,所以这只是一个猜测。

      所以我想如果其他人有问题,我在这里有一个解决方案,但没有解释。非常不满意,但成功了!

      【讨论】:

        猜你喜欢
        • 2021-03-06
        • 2017-02-22
        • 2012-11-12
        • 1970-01-01
        • 2021-07-19
        • 2013-09-30
        • 2011-04-07
        • 2017-02-26
        • 1970-01-01
        相关资源
        最近更新 更多