knitr:使用knit_expand以编程方式在块

时间:2017-02-13 00:59:08

标签: r knitr r-markdown

rmarkdown文档中,我正在一个块中绘制几个图。我想使每个图的高度与垂直轴上的类别数成比例。基于this SO answer,我尝试使用knit_expand为每个绘图创建一个新块,并以编程方式设置块选项。

下面粘贴了具有可重现数据和代码的示例rmarkdown文档。 kexpand函数为每个绘图创建一个新块。我在最后一个块中的for循环中运行该函数。 for循环创建三个图,一个用于样本数据中的每个dept级别。但是,当我(尝试)编织文档时,我收到以下错误:

  

第23行错误parse_block(g [-1],g [1],params.src):重复标签'English'Calls:... process_file - > split_file - > lapply - >乐趣 - > parse_block执行暂停

这是我第一次尝试动态更改块选项而我不确定块标签是如何重复的,因为dept的每个级别只进入knit_expand一次。我尝试了this SO question中的建议,在knit_child函数中使用knit而不是kexpand,但我遇到了同样的错误。

所以,我的问题是:(1)如何避免重复的标签错误并使文档正确编织,以及(2)我是以正确的方式进行此操作还是有更好的方法来动态更改块在循环中创建绘图或表时的选项?

---
title: "Untitled"
author: "eipi10"
date: "February 12, 2017"
output: pdf_document
---

```{r setup, include=FALSE}
knitr::opts_knit$set(progress = FALSE, verbose = FALSE)
knitr::opts_chunk$set(echo = FALSE, message=FALSE, warning=FALSE)

library(tidyverse)
library(scales)
library(knitr)
```

```{r}
# Adapted from https://stackoverflow.com/a/27234462/496488
kexpand <- function(ht, cap, plot) {
  cat(
    knit(
      text=knit_expand(
        text=sprintf("```{r %s, fig.height=%s, fig.cap='%s'}\n%s\n```", cap, ht, cap, plot)
      )))
}
```

```{r data}
df = structure(list(dept = c("English", "English", "English", "English", 
"English", "English", "English", "English", "English", "English", 
"English", "English", "English", "English", "English", "Biology", 
"Biology", "Biology", "Biology", "Biology", "Biology", "Government", 
"Government"), tot_enrl = c(114, 349, 325, 393, 415, 401, 166, 
117, 302, 267, 256, 224, 481, 295, 122, 410, 478, 116, 278, 279, 
238, 142, 145), course = c("ENGL 1", "ENGL 10M", "ENGL 11M", 
"ENGL 16", "ENGL 1X", "ENGL 20M", "ENGL 3", "ENGL 30A", "ENGL 40A", 
"ENGL 40B", "ENGL 50A", "ENGL 50B", "ENGL 5M", "ENGL 60", "ENGL 65", 
"BIO 15L", "BIO 2", "BIO 30", "BIO 39", "BIO 7", "BIO 9", "GOVT 10", 
"GOVT 1H")), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, 
-23L), .Names = c("dept", "tot_enrl", "course"))
```

```{r results="asis"}
height.unit = 0.2

for (d in unique(df$dept)) {

  .pl = ggplot(df[df$dept==d, ], aes(tot_enrl, reorder(course,tot_enrl))) + geom_point()

  ht = height.unit *  length(unique(df$course[df$dept==d])) + 1

  kexpand(ht=ht, cap=d, plot=.pl)
}
```

2 个答案:

答案 0 :(得分:2)

通过一些小修改(检查$(function){ $(document).on("click",".btn",function(){ $(".btn").removeClass("active"); $(this).addClass("active"); }); }); 的定义),您的示例代码适用于我:

kexpand

enter image description here

答案 1 :(得分:1)

在这里使用knit_expand是正确的方法,但您调整from rawr's anser的实现是......很奇怪(恕我直言)。

这是您解决方案的核心:

knit_expand(text=sprintf("```{r %s, fig.height=%s, fig.cap='%s'}\n%s\n```", cap, ht, cap, plot))

这可能适用于r-bloggers.com post rawr的解决方案所基于的环境,但一般而言,这不是knit_expand应该使用的方式。

  • knit_expand自行解析模板 - 在这里使用sprintf毫无意义。来自?knit_expand
      

    此函数基于{{}}中的R表达式扩展模板(此标记可以由delim参数自定义)。这些表达式被提取,评估并替换为原始模板中的值。

  • 您不是将代码注入到动态生成的块中,而是/ rawr正在注入.plggplot返回值

尝试运行

knit_expand(text=sprintf("```{r %s, fig.height=%s, fig.cap='%s'}\n%s\n```", d, ht, d, .pl))

使用问题代码中定义的变量(d设置为unique(df$dept)[1])。由于.pl转换为character的方式,这会扩展为 9个块(以及大量垃圾)。 &#34;重复标签&#34;错误源于所有这些具有相同标签的块。

正确的解决方案应该类似于this answer中的最后一部分:使用knit_expand的模板功能并移动生成内部 生成块的图表的代码: / p>

---
output: pdf_document
---

```{r setup, include=FALSE}
knitr::opts_knit$set(progress = FALSE, verbose = FALSE)
knitr::opts_chunk$set(echo = FALSE, message=FALSE, warning=FALSE)

library(ggplot2)
library(knitr)
```

```{r}
kexpand <- function(height, caption, d) {

  cat(
    knit(text=knit_expand(
      text=(
"```{r {{caption}}, fig.height={{height}}, fig.cap='{{caption}}'}
ggplot(df[df$dept=='{{d}}', ], aes(tot_enrl, reorder(course,tot_enrl))) + geom_point()
```"),
      caption = caption,
      height = height,
      d = d)))
}
```

```{r data}
df = structure(list(dept = c("English", "English", "English", "English", 
    "English", "English", "English", "English", "English", "English", 
    "English", "English", "English", "English", "English", "Biology", 
    "Biology", "Biology", "Biology", "Biology", "Biology", "Government", 
    "Government"), tot_enrl = c(114, 349, 325, 393, 415, 401, 166, 
    117, 302, 267, 256, 224, 481, 295, 122, 410, 478, 116, 278, 279, 
    238, 142, 145), course = c("ENGL 1", "ENGL 10M", "ENGL 11M", 
    "ENGL 16", "ENGL 1X", "ENGL 20M", "ENGL 3", "ENGL 30A", "ENGL 40A", 
    "ENGL 40B", "ENGL 50A", "ENGL 50B", "ENGL 5M", "ENGL 60", "ENGL 65", 
    "BIO 15L", "BIO 2", "BIO 30", "BIO 39", "BIO 7", "BIO 9", "GOVT 10", 
    "GOVT 1H")), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, 
    -23L), .Names = c("dept", "tot_enrl", "course"))
```

```{r results="asis"}
height.unit <- 0.2

for (d in unique(df$dept)) {
  ht <- height.unit *  length(unique(df$course[df$dept==d])) + 1

  kexpand(height=ht, caption=d, d = d)
}
```