knitr templating - Dynamic chunks issue - r

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:
generated chunks don't get parsed (this is not happening in my real code, but happens in MRE)
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))`

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

Related

Generate tables in a loop with tab.id with officedown R package

Is there a way to generate tables in a loop and set tab.id that can be later cross-referenced? Generating tables in a loop is trivial, but I don't know how to set ids and captions afterwards. Please, see the code below. Here I'm iterating over a list of R data.frames. In the last chunk I put the vector of ids (its lenght is 2) into chunk options - tab.id and tab.cap. This results in generation of two tables (good), but how to get the id of currently processed data.frame in the chunk?
---
output: officedown::rdocx_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
```
```{r}
library(flextable)
dfs <- list(
df1 = head(iris),
df2 = head(mtcars)
)
df_ids <- names(dfs)
```
```{r results='asis', tab.cap=paste("Result for item", df_ids), tab.id=paste0("tab_", df_ids),
tab.cap.style = "Table Caption"}
flextable(dfs[[???]]) # can current id be accessed somehow?
```
Another option is to use for loop to generate the tables. But how to set tab.id and tab.cap afterwards? Even a workaround solution can be fine for me.
You can probably set these values in a loop by using knitr::opts_chunk$set(). I would probably prefer set_caption in your case.
To print flextables in a loop inside an R Markdown document, use flextable_to_rmd(). See Looping in R Mardown documents.
---
output: officedown::rdocx_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
```
```{r}
library(flextable)
library(officer)
library(officedown)
library(magrittr)
dfs <- list(
df1 = head(iris),
df2 = head(mtcars)
)
df_ids <- names(dfs)
```
```{r results='asis'}
for(i in df_ids){
z <- flextable(dfs[[i]]) %>%
set_caption(caption = paste("Result for item", i),
style = "Table Caption",
autonum = run_autonum(seq_id = "tab", bkm = i))
flextable_to_rmd(z)
crossref_id <- sprintf("\\#ref(tab:%s)", i)
cat("\n\n\nA ref to table ", crossref_id, "\n\n\n\n")
}
```

Is it possible to change the fig.cap chunk option within knitr?

I'd like to change the fig.cap chunk option within a chunk for a knitr document. I tend to write a lot of reporting code that looks like the following to take a plot out of a tibble and use the associated caption with it.
```{r fig, fig.cap=d_plot$caption}
d_plot <- [load the plotting tibble from prior work]
knit_print(d_plot$figure[[1]])
```
Something similar to what I'd like to do is the following, but where the caption actually shows up. And, better yet would be if it would modify fig.cap and fig.scap with the possibility of having multiple knit_print() calls with multiple sets of figures.
---
title: "Untitled"
author: "William Denney"
date: '2022-04-19'
output: pdf_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo=FALSE, warning=FALSE, error=FALSE)
library(tidyverse)
library(knitr)
```
# Test
```{r functions, include=FALSE}
knit_print.fig_n_cap <- function(x) {
lapply(x$figure, knit_print)
opts_chunk$set(fig.cap=x$caption)
}
as_fig_n_cap <- function(x) {
stopifnot(is.data.frame(x))
stopifnot("figure" %in% names(x))
stopifnot("caption" %in% names(x))
class(x) <- c("fig_n_cap", class(x))
x
}
p <- ggplot(data.frame(x=1:3, y=1:3), aes(x=x, y=y)) + geom_line()
d <- as_fig_n_cap(tibble(figure=list(p), caption="My caption"))
```
```{r}
knit_print(d)
```

R Markdown - format text as a header in a loop seems to be working for 1st loop iteration only

I am trying to generate R Markdown document with headers generated dynamically from a loop.
I used suggestions from similar SO questions: Knitr: print text from code block as R markdown, Using bold text in a loop for a Word document in Rmarkdown and wrote
---
title: "Untitled"
output:
html_document:
toc: true
toc_depth: 5
---
## R Markdown
```{r, warning=FALSE, message=FALSE, echo=FALSE}
library(ggplot2)
library(dplyr)
```
```{r fig.width=4, fig.height=2, echo=FALSE, results='asis'}
experiment_names <- paste0("Experiment ", 1:3)
for (id in 1:3){
cat(" \n")
cat("### ", experiment_names[id])
cat(" \n")
set.seed(id)
plt <-
data.frame(x = rnorm(100)) %>%
ggplot(aes(x = x)) +
geom_histogram(binwidth = 0.1)
plot(plt)
}
```
but only the 1st loop iteration header is printed correctly. How to get the two others working too?
I don't know why this works, but try one line instead of three:
cat("\n\n### ", experiment_names[id], "\n")

R markdown YAML issue

I am using R Markdown render to automate sales reporting and I am hit with the following error message:
Error: Invalid YAML front matter (ends with ':').
R Studio, function worked previously. I have tried most quick fixes I've seen online but nothing has worked.
Additionally, if you have any advice for importing company logos, I would love to hear it. When knitted locally, it appears, but once it is sent out, it disappears. I'm sure this is due to the local file path, so any advice for calling it in a non-local manner?
---
output: html_document
params:
---
![](/Users/bingbong284/Desktop/markdown/CopyOf Header.jpg)
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE, comment = NA)
library(dplyr)
library(tidyverse)
library(knitr)
library(kableExtra)
library(yaml)
library(rmarkdown)
```
```{r echo=FALSE, message=FALSE, warning=FALSE, paged.print=FALSE, comment = NA}
today <- Sys.Date()
```
`r format(today, format="%B %d, %Y")`
To Whom It May Concern,
Below is your sales report for fictitious name.
```{r include=FALSE}
aug_rent <- read_csv("Aug R Rent.csv")
colnames(aug_rent)[colnames(aug_rent)=="Vendor ID"] <- "Landlord"
organ_aug <- arrange(aug_rent, aug_rent$'Landlord')
vendors <- unique(organ_aug$`Landlord`)
```
```{r echo=FALSE}
render_my_report <- function(vendor) {
rmarkdown::render("Remote.Rmd",
output_format = "html_document",
output_file = paste0(vendor, "_sales_report_", Sys.Date(), ".html"),
params = list(Landlord = vendor),
output_options = list(self_contained = FALSE, lib_dir = "libs"))
}
purrr::walk(vendors, render_my_report)
```
```{r echo=FALSE, message=FALSE, warning=FALSE, comment=NA}
test_data <- filter(organ_aug, organ_aug$'Landlord' == params)
last_table <- knitr::kable(test_data, captio = "August 2019 Sales Report")
kable_styling(last_table, font_size = 14)
```
If you have any questions regarding this report, please email BingBong284#ficticiousname.com or reach out to BingBong284, BingBong284#ficticiousname.com.
Thank you,
BingBong284, Finance
Function previously generated 66 unique sales reports for 66 vendor ID's, but it is now hitting me with the error listed above.

How to use LaTeX Code in R Chunk in R-Markdown?

I am currently writing on a report with rmarkdown and therefore I want to create sections inside a r code chunk. I figured out that this is possible with the help of cat() and results="asis". My problem with this solution is, that my R code results and code isn't properly displayed as usual.
For example
---
title: "test"
output: pdf_document
---
```{r, results='asis'}
for (i in 1:10) {
cat("\\section{Part:", i, "}")
summary(X)
$\alpha = `r X[1,i]`$
}
```
pretty much does the trick, but here there are still two problems:
the R output for summary() is displayed very strange because I guess it`s interpreted as LaTeX code
I can't use LaTeX formulas in this enviroment, so if I want every section to end with a equation, which also might use a R variable, this is not possible
Does somebody know a solution for some of these problems, or is there even a workaround to create sections within a loop and to have R code, R output and LaTeX formulas in this section? Or maybe at least one of those things?
I am very thankful for every kind of advice
You can do what you are after inline without relying as much on code blocks.
As a minimal example.
---
title: "test"
output: pdf_document
---
```{r sect1_prep, include=FALSE}
i <- 1
```
\section{`r paste0("Part: ", i)`}
```{r sect1_body}
summary(mtcars[, i])
```
$\alpha = `r mtcars[1, i]`$
```{r sect2_prep, include=FALSE}
i <- i + 1
```
\section{`r paste0("Part: ", i)`}
```{r sect2_body}
summary(mtcars[, i])
```
$\alpha = `r mtcars[1, i]`$
Produces...
If you really want to have a section factory, you could consider pander.
---
title: "test"
output: pdf_document
---
```{r setup, include=FALSE}
library(pander)
panderOptions('knitr.auto.asis', FALSE)
```
```{r, results='asis', echo=FALSE}
empty <- lapply(1:10, function(x) {
pandoc.header(paste0("Part: ", x), level = 2)
pander(summary(mtcars[, x]))
pander(paste0("$\\alpha = ", mtcars[1, x], "$\n"))
})
```
which produces...
remove summary table format example
---
title: "test"
output: pdf_document
---
```{r setup, include=FALSE}
library(pander)
panderOptions('knitr.auto.asis', FALSE)
```
```{r, results='asis', echo=FALSE}
content <- lapply(1:10, function(x) {
head <- pandoc.header.return(paste0("Part: ", x), level = 2)
body1 <- pandoc.verbatim.return(attr(summary(mtcars[, x]), "names"))
body2 <- pandoc.verbatim.return(summary(mtcars[, x]))
eqn <- pander_return(paste0("$\\alpha = ", mtcars[1, x], "$"))
return(list(head = head, body1 = body1, body2 = body2, eqn = eqn))
})
writeLines(unlist(content), sep = "\n\n")
```

Resources