knitr templating - Dynamic chunks issue

1k views Asked by At

The following code is a very simplified MRE for an issue I'm experiencing. I'm trying to avoid R template packages, such as brew, and only use knit_expand() to achieve my goals. The issue is twofold:

  1. generated chunks don't get parsed (this is not happening in my real code, but happens in MRE)
  2. instead of LaTeX \includegraphics, knitr (or rmarkdown, or pandoc) generates RMarkdown syntax for inserting figures (![]).

In regard to the former, I have a feeling that it might be related to my incorrect use of get() or its argument. Your advice would be very much appreciated. The MRE follows ('.Rmd' document):

---
title: "MRE: a dynamic chunk issue"
author: "Aleksandr Blekh"
output:
  pdf_document:
    fig_caption: yes
    keep_tex: yes
    highlight: NULL
---

```{r, echo=FALSE, include=FALSE}
library(knitr)

opts_knit$set(progress = F, verbose = F)
opts_chunk$set(comment=NA, warning=FALSE, message=FALSE, echo=FALSE, tidy=FALSE)
```

```{r Preparation, results='hide'}

g1 <- plot(cars)
g2 <- plot(iris$Sepal.Length)

myPlots <- list(g1, g2)

bcRefStr <- list("objType" = "fig",
                 "objs" = c("g1", "g2"),
                 "str" = "Plots \\ref{fig:g1} and \\ref{fig:g2}")
```

```{r DynamicChunk, include=FALSE}
chunkName <- "{{name}}"
chunkHeader <- paste0("```{r ", chunkName, ", ")
chunkOptions <- "include=TRUE, results='asis', fig.height=4, fig.width=4, fig.cap='{{name}}'"
chunkHeaderFull <- paste0(chunkHeader, chunkOptions, "}")
chunkBody <- "print(get('{{name}}'))"

latexFigEnvBegin <- "cat('\\\\begin{figure}')"
latexFigEnvEnd <- "cat('\\\\end{figure}')"
latexFigCenter <- "cat('\\\\centering')"

latexObjLabel <- paste0("cat('\\\\caption{\\\\ ", "{{name}}\\\\label{", bcRefStr$objType, ":{{name}}", "}}')")

chunkText <- c(chunkHeaderFull,
               latexFigEnvBegin, latexFigCenter,
               chunkBody,
               latexObjLabel, latexFigEnvEnd,
               "```", "\n")

figReportParts <- lapply(bcRefStr$objs, function (x) knit_expand(text = chunkText, name = x))
```

`r knit(text = unlist(figReportParts))`
1

There are 1 answers

0
Aleksandr Blekh On BEST ANSWER

Finally, I've figured out what was causing the issue. The first part was easy. Due to suggested simplification, I've switched from ggplot2 to standard R graphics functions. The problem is that it appears that plot() doesn't return a value/object, so that's why NULLs has been seen in the output, instead of plots.

The second part was a bit more tricky, but an answer to a related question (https://stackoverflow.com/a/24087398/2872891) clarified the situation. Based on that information, I was able modify my MRE correspondingly and the resulting document appears with correct content (same applies to the generated LaTeX source, which seems to be ready for cross-referencing).

I'm thinking about converting this code into a more generic function for reuse across my project, if time will permit [shouldn't take long] (@Yihui, could this be useful for knitr project?). Thanks to everyone who took time to analyze, help or just read this question. I think that knitr's documentation should be more clear on issues, related to producing PDF documents from RMarkdown source. My solution for the MRE follows.

---
title: "MRE: a dynamic chunk issue"
author: "Aleksandr Blekh"
output:
  pdf_document:
    fig_caption: yes
    keep_tex: yes
    highlight: NULL
---

```{r, echo=FALSE, include=FALSE}
library(knitr)
library(ggplot2)

opts_knit$set(progress = F, verbose = F)
opts_chunk$set(comment=NA, warning=FALSE, message=FALSE, echo=FALSE, tidy=FALSE)
```

```{r Preparation, results='hide'}
library(ggplot2)

g1 <- qplot(mpg, wt, data=mtcars)
g2 <- qplot(mpg, hp, data=mtcars)

myPlots <- list(g1, g2)

bcRefStr <- list("objType" = "fig",
                 "objs" = c("g1", "g2"),
                 "str" = "Plots \\ref{fig:g1} and \\ref{fig:g2}")
```

```{r DynamicChunk, include=FALSE}

latexObjLabel <- paste0("{{name}}\\\\label{", bcRefStr$objType, ":{{name}}", "}")

chunkName <- "{{name}}"
chunkHeader <- paste0("```{r ", chunkName, ", ")
chunkOptions <- paste0("include=TRUE, results='asis', fig.height=4, fig.width=4, fig.cap='", latexObjLabel, "'")
chunkHeaderFull <- paste0(chunkHeader, chunkOptions, "}")
chunkBody <- "print(get('{{name}}'))"

chunkText <- c(chunkHeaderFull,
               chunkBody,
               "```", "\n")

figReportParts <- lapply(bcRefStr$objs, function (x) knit_expand(text = chunkText, name = x))
```

`r knit(text = unlist(figReportParts))`