2017-02-13 1 views
2

В документе я рисую несколько сюжетов внутри одного фрагмента. Я бы хотел, чтобы высота каждого графика была пропорциональна количеству категорий на вертикальной оси. Основываясь на this SO answer, я пытаюсь сделать это с помощью knit_expand, чтобы создать новый кусок для каждого сюжета с программными параметрами куска.knitr: Ошибка дублирования метки куска при использовании knit_expand для изменения размеров графика программно внутри фрагмента

Образец документ с воспроизводимыми данными и кодом вклеен ниже. Функция kexpand - это то, что создает новый кусок для каждого сюжета. Я запускаю функцию в цикле for в последнем фрагменте. Цикл for создает три графика, по одному для каждого уровня dept в образцах данных. Однако, когда я (попытка) связать документ, я получаю следующее сообщение об ошибке:

Line 23 Error in parse_block(g[-1], g[1], params.src) : duplicate label 'English' Calls: ... process_file -> split_file -> lapply -> FUN -> parse_block Execution halted

Это первый раз, когда я пытался динамически изменять параметры порций, и я не уверен, как метка чанка получая дублирование, так как каждый уровень dept переходит в knit_expand только один раз. Я попробовал предложение в this SO question использовать knit_child вместо knit внутри функции kexpand, но я получил ту же ошибку.

Итак, мои вопросы: (1) как я могу избежать дублирования ошибки метки и получить документ вязать правильно, и (2) я собираюсь по этому правильному пути или есть лучший способ динамического изменения chunk options при создании графиков или таблиц в цикле?

--- 
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) 
} 
``` 

ответ

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

    This function expands a template based on the R expressions in {{}} (this tag can be customized by the delim argument). These expressions are extracted, evaluated and replaced by their values in the original template.

  • Вместо введения код в динамически генерируемый кусок, вы/Rawr впрыскивает .pl, значение возврата из ggplot.

Попробуйте запустить

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

с переменными, как определено в коде от вопроса (и d набор к unique(df$dept)[1]).Это расширяется до 9 кусков (и много мусора), из-за способа .pl преобразуется в character. Ошибки «дублированной метки» проистекают из всех этих кусков, имеющих одну и ту же метку.

Правильное решение должно быть похоже на последнюю часть в this answer: Используйте возможности шаблонные из knit_expand и перенесите код генерации участка внутри сгенерированные ломти:

--- 
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) 
} 
``` 
2

С небольшой модификацией (проверьте определение kexpand), ваш пример кода работает для меня:

--- 
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 http://stackoverflow.com/a/27234462/496488 
kexpand <- function(ht, cap) { 
    cat(
    knit(
     text=knit_expand(
     text=sprintf("```{r %s, fig.height=%s, fig.cap='%s'}\n .pl \n```", cap, ht, cap) 
    ))) 
} 
``` 

```{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) 
} 
``` 

enter image description here

Смежные вопросы