【问题标题】:knitr - exclude chunks from `purl(...)`?knitr - 从`purl(...)`中排除块?
【发布时间】:2013-05-08 01:13:27
【问题描述】:

当我 purl/tangle 文档以将 R 块提取到脚本中时,有什么方法可以:

  • 排除任意块(按名称说)?
  • 如果不是,排除一个块 if eval=F(或者我可以定义一个块挂钩/选项include=F)?

例如,假设我有以下 Rmd:

```{r setup, echo=F}
library(MASS)
```
First, we perform the setup (assume for some reason I need to evaluate `setup`
silently before I wish to display the chunk to the user, hence the repetition)
```{r setup, eval=F}
```

Here's the function I've been explaining:
```{r function}
plus <- function (a, b) a + b
```

And here's an example of its use:
```{r example}
plus(1, 2)
```

纠结的脚本是这样的:

## @knitr setup, echo=F
library(MASS)   

## @knitr setup, eval=F
library(MASS)

## @knitr function
plus <- function (a, b) a + b

## @knitr example
plus(1, 2)

我的想法是,由于我想要评估特定的块,它们至少不应该出现在输出中(在上面的示例中,第二个 setup 块)。

另外,我最好将一些块相对于纠结的输出标记为“不可见”。我不希望在我的输出脚本中出现 example 块(在 Rmd 中用于文档的目的很好,但我希望能够将 Rmd 和 source('myfile.r') 纠缠在一起,如果我想使用 @987654328 @函数,不用担心执行这些额外的例子。目前我是在rmd中纠结,然后手动从脚本中编辑出我不想要的块,这似乎违反了只写的原则一个 Rmd 无需额外努力即可提供文档和脚本。)

【问题讨论】:

  • 注意 - 用include=F 标记一个块将从purl'd 输出中删除,但从Rmd(在来自github的knitr版本中)是;我的计算机版本 1.2 上似乎不存在该功能),因此这对于我的 example 块并不理想(我希望它 包含 在 Rmd 中并从 purl 的输出中删除)
  • purl() 确实有很大的改进空间,使用频率较低,因此开发得不太好
  • 有没有办法只从 Rmd 中提取 r 个块?
  • @KLDavenport 将所有 R 块从 Rmd 提取到 R 脚本中,您使用 purl。它提取了所有的块,我有兴趣只提取其中的一些(或者甚至将特定的块提取到特定的输出文件)。
  • 我无法简单导出所有块以工作,但我会再次查看文档。可惜你可以为每个块设置配置以在你的情况下导出。

标签: r knitr


【解决方案1】:

knitr 1.3 开始,有一个新的块选项purl = TRUE/FALSE 允许包含/排除purl() 的某些代码块。

```{r test, purl=FALSE}
library(MASS)
```

【讨论】:

    【解决方案2】:

    tangle 处理块目前不扩展参数,但我们可以让它这样做...

    # See `?trace` documentation for details.
    bdy <- as.list( body( knitr:::process_tangle.block ) )
    trace.at <- which( grepl(".*opts_chunk\\$merge.*",
                             as.list( body( knitr:::process_tangle.block ) ) ) )
    tracer <- quote({
      # Code borrowed from normal chunk procesing.
      af = opts_knit$get('eval.after'); al = opts_knit$get('aliases')
      if (!is.null(al) && !is.null(af)) af = c(af, names(al[af %in% al]))
      for (o in setdiff(names(params), af)) params[o] = list(eval_lang(params[[o]]))
      # Omit this if using lastest knitr source from github.
      if( isFALSE( params$include ) ) {
        tmp <- knit_code$get();
        tmp[[params$label]] <- "";
        knit_code$restore(tmp)
      }
    })
    
    trace( knitr:::process_tangle.block, tracer=tracer, at=trace.at, print=FALSE )
    

    然后可以使用选项参数控制 purl() 排除...

    ```{r setup, echo=TRUE, results='hide'}
    library(MASS)
    ````
    
    First, we perform the setup (assume for some reason I need to evaluate `setup`
    silently before I wish to display the chunk to the user, hence the repetition)
    ```{r setup2, ref.label="setup", echo=FALSE, results='markup'}
    ```
    
    Here's the function I've been explaining:
    ```{r function}
    plus <- function (a, b) a + b
    ```
    
    And here's an example of its use:
    ```{r example, eval=!opts_knit$get("tangle") }
    plus(1, 2)
    ```
    
    And here's another example of its use:
    ```{r example2, include=!opts_knit$get("tangle") }
    plus(3, 3)
    ```
    

    【讨论】:

    • 但是,这仍然不允许我 排除 我选择的块(例如。在我在问题中给出的示例中,我想排除“示例”块)
    • @mathematical.coffee @Thell 感谢您的探索;我想我将添加一个单独的块选项以允许从purl() 中排除某些块;让我再考虑一下。
    • @Yihui 那太好了!如果它没有伤害任何东西,那么扩展参数会很好,因为钩子选项也可以通过编程方式设置,以发出不同的结果......
    • @Thell 我完全同意你的看法。唯一的问题是当参数使用代码块中的对象时,purl() 将需要执行代码块。也许我们识字编程的人从一开始就错了——识字编程不应该是weavetangle,而是weave[tangle](可选tangleweave过程中)。
    【解决方案3】:

    虽然这更像是一个技巧而不是一个解决方案,但您仍然可以使用一些正则表达式修改由 purl 生成的脚本。

    例如使用以下函数(也许正则表达式有更简单的解决方案):

    dropchunks <- function(scriptname, what.to.drop){
        script <- readLines(scriptname)
        script <- do.call(paste, list(script, collapse = "\n") )
        subpattern = paste0("(", do.call(paste, list(what.to.drop, collapse="|")), ")")
        mainpattern <- paste('(?s)## @knitr ((?!## @knitr).)*?', subpattern, '.*?((?=## @knitr)|$)', sep="")
        script <- gsub(pattern = mainpattern, replacement = "", x = script, perl=TRUE)
        writeLines(text = script, con= scriptname)
    }
    

    然后您可以这样做以删除所有包含 eval=F 的代码块:

    library(knitr)
    purl("test.Rmd")
    dropchunks("test.R", "eval=F")
    

    您可以这样做来删除名为“function”或“example”的块(实际上它会删除任何包含这些单词的块,但这可以通过更改正则表达式来更改):

    purl("test.Rmd")
    dropchunks("test.R", c("function", "example"))
    

    【讨论】:

    • 我喜欢这个主意!由于 knitr 不会抱怨块中的未知参数,因此可以将简单的 ```{r test, purl=F} 设置为默认的“what.to.drop”。
    猜你喜欢
    • 2019-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-28
    • 2017-10-11
    • 2016-02-28
    • 1970-01-01
    相关资源
    最近更新 更多