I ran into the following problem. In order to automatically generate problem sets with Rexams, I want to read questions from a database and then parse them into a Rexams template and then produce another markdown file, that can potentially contain chunks of R code, that then should be processed by Rexams. I tried several forms of getting verbatim text such as
write_chunk1 <- c("```{r, echo = FALSE, results='hide'} \n " )
write_chunk2 <- c(" include_supplement('UCL-J16-Q13-01.png', recursive = TRUE) \n" )
write_chunk3 <- c("```")
cat(noquote(write_chunk1) )
cat(noquote(write_chunk2) )
cat(noquote(write_chunk3) )
but this does not produce the required output in the generated markdown file. Which would be the following (I escaped the last code closing, otherwise it would not show up here either)
```{r, echo = FALSE, results='hide'}
include_supplement('UCL-J16-Q13-01.png', recursive = TRUE)
```
The following file runs a loop that takes the "quizzes" database puts the information into an Rexams template
library(knitr)
library(rmarkdown)
library(here)
library(exams)
library(dplyr)
library(readxl)
## paths
# file.copy(here("quizzes/input/images","*.png"),to = here("quizzes/output/rmd_question_files/"))
## Data
quizzes <- tribble(
~identifier, ~question, ~answer1, ~answer2, ~solution1, ~solution2, ~feedback1, ~feedback2, ~image,
"Q1", "Is this good", "yes", "no", 1, 0, "Because it is", "Wrong", "smile.png"
)
## Loop
for (i in 1:nrow(quizzes)){
rmarkdown::render(input = here("quizzes/code/", "template_rexams.Rmd"),
output_format = "md_document",
output_file = paste0(quizzes$Identifier[i], ".Rmd"),
output_dir = here("quizzes/output/rmd_question_files/")
)
}
The rexams template serves as a template for the markdown files that shousl contain the different exercises.
---
output: md_document
---
```{r echo=FALSE, message=FALSE, warning=FALSE}
quizzes <- tribble(
~question, ~answer1, ~answer2, ~solution1, ~solution2, ~feedback1, ~feedback2, ~image,
"Is this good", "yes", "no", 1, 0, "Because it is", "Wrong", "smile.png"
)
# Read question
question <- quizzes$question[i]
# Create answer lists and solutions with feeback
answers <- c(quizzes$answer1[i], quizzes$answer2[i])
sol <- c(quizzes$solution1[i], quizzes$solution2[i])
sol <- ifelse(sol == 1, TRUE, FALSE)
feedback <- c(quizzes$feedback1[i], quizzes$feedback2[i])
## Get image identifiers
img1 <- quizzes$image
```
```{r get-images, echo=FALSE, message=FALSE, warning=FALSE}
# Define variable containing image locations
img_path <- here::here("quizzes/input/images/")
img1_pt <- ifelse(img1 != "", paste0(img_path, paste0(quizzes$image[i],".png")), "")
img1 <- ifelse(img1 != "", paste0(quizzes$image,".png"), "")
if (!is.na(img1)){
include_supplement(file = c(img1), dir = img_path, recursive = TRUE)
}
write_chunk1 <- c("{r, echo = FALSE, results='hide'} \n " )
write_chunk2 <- c(" include_supplement('")
write_chunk3 <- c(paste0(img1, ", recursive = TRUE) \n" ))
write_chunk4 <- c("```")
```
```{r write_supplement, echo=FALSE, message=FALSE, warning=FALSE, results="asis"}
cat(noquote(write_chunk1) )
cat(noquote(write_chunk2), noquote(write_chunk3) )
cat(noquote(write_chunk4) )
```
Question
========
**Unit `r unit`.`r nmb`**
`r question`
```{r insert-images, echo=FALSE, message=FALSE, warning=FALSE, comment="", results="asis"}
img1_pr <- ifelse(img1 != "", paste0("![](", paste0(img1, ")")), " ")
```
`r if(!is.na(img1)){noquote(img1_pr)}`
```{r answerlist, echo = FALSE, results = "asis"}
answerlist(answers, markup = "markdown")
```
Solution
========
```{r solutionlist, echo = FALSE, results = "asis"}
answerlist(ifelse(sol == 1, "**True**", "**False**"), markup = "markdown", feedback)
```
Meta-information
================
extype: mchoice
exsolution: `r mchoice2string(sol, single = FALSE)`
exname: `r exname`
The problem now is, that this new markdown file should contain the following code chunk at the beginning of the markdown file, where the name of the image to be included changes by exercise.
```{r, echo = FALSE, results='hide'}
include_supplement('smile.png', recursive = TRUE)
```
I hope this explains a bit better my problem. I think my problem is that I do not know how to escape ``` in order to write it into the file.
There is no unified function for this because the exact representation of the questions across data frames, CSV or database files, typically various. However, the general approach I use is to set up a character template for the Rmd (or Rnw) exercise with
%s
string placeholders and the fill the placeholders with the information from the data. Eventually, I usewriteLines()
to write out the resuling code to the exercise file.A worked example for processing a certain CSV file format is discussed in the R/exams forum on R-Forge at: https://R-Forge.R-project.org/forum/forum.php?thread_id=34046&forum_id=4377&group_id=1337
I adapted the code from that post into a
data2rmd()
function that can be applied to thequizzes
tibble from your question. It assumes that there are always exactly two answer options and then you can do:which creates a file
ex1.Rmd
with the R/Markdown code. This can then be processed withexams2html("ex1.Rmd")
or any otherexams2xyz()
function - provided that the image filesmile.png
is in the same folder asex1.Rmd
.Function: