Overview:
With my R/exams exercise provided below I have the problem that the plot output from my figure chunk is included correctly in the HTML output from exams2html() but it is dropped silently in the PDF output from exams2pdf().
Additionally, I have the same problem with the table output from
modelsummary()but I separated this into another question.
Rmd exercise:
```{r data generation, echo = FALSE, results = "hide",message = FALSE}
library(ggplot2)
library(tibble)
library(broom)
library(dplyr)
## DATA GENERATION
rd = 2 # rounding
# Sample size
n <- sample(c(400,390,420,450),size=1)
# Parameters
beta0 <- runif(1,18,22)
beta1 <- runif(1,0.4,0.6)
beta2 <- runif(1, 8,12)
is_interact = runif(1) > 0.5
beta3 = ifelse(is_interact,runif(1,1,2),0)
# Dataset
omit_df <- tibble(
male = sample(x = c(F, T), size = n, replace = T),
education = runif(n, 3, 9) - 3 * male,
pay = beta0 + beta1 * education + beta2 * male + beta3 * male * education + rnorm(n, sd = 7)
)
modlist = list()
pl = list()
if (is_interact){
modlist[[1]] <- lm(pay ~ education + male, data = omit_df)
modlist[[2]] <- lm(pay ~ education + male + education * male, data = omit_df)
pl[[1]] <- ggplot(data = omit_df, aes(x = education, y = pay, shape = male, color= male)) +
geom_point(size = 2.5, alpha = 0.8) +
geom_hline(yintercept = 0) +
geom_vline(xintercept = 0) +
xlab("Education") +
ylab("Pay") +
theme_bw() +
geom_abline(
intercept = modlist[[1]]$coefficients[1],
slope = modlist[[1]]$coefficients[2],
linewidth = 1
) +
geom_abline(
intercept = modlist[[1]]$coefficients[1] + modlist[[1]]$coefficients[3],
slope = modlist[[1]]$coefficients[2],
linewidth = 1
)
pl[[2]] <- ggplot(data = omit_df, aes(x = education, y = pay, shape = male, color= male)) +
geom_point(size = 2.5, alpha = 0.8) +
geom_hline(yintercept = 0) +
geom_vline(xintercept = 0) +
xlab("Education") +
ylab("Pay") +
theme_bw() +
geom_abline(
intercept = modlist[[2]]$coefficients[1] + modlist[[2]]$coefficients[3],
slope = modlist[[2]]$coefficients[2] + modlist[[2]]$coefficients[4],
linewidth = 1
) +
geom_abline(
intercept = modlist[[2]]$coefficients[1],
slope =modlist[[2]]$coefficients[2],
linewidth = 1
)
} else {
# no interaction
modlist[[1]] <- lm(pay ~ education, data = omit_df)
modlist[[2]] <- lm(pay ~ education + male , data = omit_df)
pl[[1]] <- ggplot(data = omit_df, aes(x = education, y = pay)) +
geom_point(size = 2.5, color = "black", alpha = 0.4, shape = 16) +
geom_hline(yintercept = 0) +
geom_vline(xintercept = 0) +
xlab("Education") +
ylab("Pay") +
theme_bw() + geom_smooth(se = F, color = "black", method = lm)
pl[[2]] <- ggplot(data = omit_df, aes(x = education, y = pay, shape = male, color= male)) +
geom_point(size = 2.5, alpha = 0.8) +
geom_hline(yintercept = 0) +
geom_vline(xintercept = 0) +
xlab("Education") +
ylab("Pay") +
theme_bw() +
geom_abline(
intercept = modlist[[2]]$coefficients[1],
slope = modlist[[2]]$coefficients[2],
linewidth = 1
) +
geom_abline(
intercept = modlist[[2]]$coefficients[1] + modlist[[2]]$coefficients[3],
slope = modlist[[2]]$coefficients[2],
linewidth = 1
)
}
modperm = sample(1:2,2)
modlist = modlist[modperm] # shuffle
pl = pl[modperm]
coeflist = lapply(modlist, tidy)
which_mod = sample(1:2,1) # which model
which_plot = sample(1:2,1) # which plot
which_coef = sample(1:nrow(coeflist[[which_mod]]), size = 1)
coef_name = names(coef(modlist[[which_mod]]))
coef_row = coeflist[[which_mod]][which_coef,]
pvalue_signif = coef_row[,"p.value"] < 0.05
questions <- list()
questions[[1]] <- paste0("The plot corresponds to model (",which_mod,")")
questions[[2]] <- glue::glue("The estimate for `{coef_name[which_coef]}` in model ({which_mod}) is statistically significant at the 5% level")
solution = list()
solution[[1]] = which_mod == which_plot
solution[[2]] = pvalue_signif
```
Question
========
You are given the following based on `r n` observations. Each of the columns displays the OLS regression associated to one of the following models, where `male` is a binary indicator equal to `1` if an individual is male. All models were run on the same input dataset. Which of the following statements is correct?
```{r output1,echo=FALSE,fig.cap="Plot to interpret in this question",fig.width=8, fig.align = "center"}
pl[[which_plot]]
```
Here is the corresponding regression table:
```{r output,echo=FALSE}
modelsummary::modelsummary(modlist, gof_omit = c("Adj.|AIC|BIC|F|Log.Lik.|RMSE"), stars = TRUE)
```
```{r questionlist, echo = FALSE, results = "asis"}
answerlist(questions, markup = "markdown")
```
Solution
========
```{r solutionlist, echo = FALSE, results = "asis"}
answerlist(solution, markup = "markdown")
```
Meta-information
================
extype: mchoice
exsolution: `r mchoice2string(solution)`
exname: reginteract
PDF output:
HTML output:
TL;DR
Avoid using the fig.align option if you want to use an exercise in both PDF and HTML output.
Details
R/exams relies knitr::knit() producing plain Markdown output when processing the Rmd exercise. Subsequently, R/exams handles the conversion to HTML or LaTeX as needed by the corresponding exams2xyz() interface.
However, when fig.align is set, knitr() produces either HTML or LaTeX code for including the graphics file - as opposed to plain Markdown. And because your exercise is in Rmd format, knitr guesses that the final output will be HTML-based. Hence, exams2html() works without problem because the HTML code will just be preserved. However, in exams2pdf() the HTML code gets dropped in the conversion from Markdown to LaTeX.
Better solutions?
Unfortunately, avoiding the fig.align option is the only workaround I found so far.
I tried to play around with knitr::opts_knit$set(out.format = "latex") or pandoc_to = "latex" to convince knitr to produce LaTeX output but I haven't been successful with this. If anyone knows how to do this, pointers are appreciated.