---
title: "webexercises"
output: rmarkdown::html_vignette
vignette: >
%\VignetteIndexEntry{webexercises}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>"
)
library(webexercises)
```
## Setup
### RMarkdown
Examples are provided in templates. To create an RMarkdown file from the webexercises template in RStudio, click `File -> New File... -> RMarkdown` and in the dialog box that appears, select `From Template` and choose `Web Exercises`.
Alternatively (or if you're not using RStudio) use:
```{r compile-webexercises, eval=FALSE}
rmarkdown::draft("exercises.Rmd", "webexercises", "webexercises")
```
Knit the file to HTML to see how it works. **Note: The widgets only function in a JavaScript-enabled browser.**
### Quarto
You can set up a single template quarto file with the function `create_quarto_doc()`, or add the necessary files and setup to include webexercises in a quarto project with `add_to_quarto()`.
### Bookdown
You can add webexercises to a bookdown project or start a new bookdown project using `add_to_bookdown()`.
```{r, eval = FALSE}
# create a new book
# use default includes and scripts directories (include and R)
# output_format can be bs4_book, gitbook, html_book or tufte_html_book
add_to_bookdown(bookdown_dir = "demo_bs4",
output_format = "bs4_book",
render = TRUE)
# update an existing book with custom include and script directories
add_to_bookdown(bookdown_dir = ".",
include_dir = "www",
script_dir = "scripts",
output_format = "gitbook")
```
## Creating interactive widgets with inline code
The webexercises package provides functions that create HTML widgets using [inline R code](https://github.com/rstudio/cheatsheets/raw/main/rmarkdown.pdf). These functions are:
| function | widget | description |
|:------------------------|:---------------|:-------------------------------|
| `fitb()` | text box | fill-in-the-blank question |
| `mcq()` | pull-down menu | multiple choice question |
| `torf()` | pull-down menu | TRUE or FALSE question |
| `longmcq()` | radio buttons | MCQs with long answers |
| `hide()` and `unhide()` | button | solution revealed when clicked |
The appearance of the text box and pull-down menu widgets changes when users enter the correct answer. Answers can be either static or dynamic (i.e., specified using R code). Widget styles can be changed using `style_widgets()`.
These functions are optimised to be used with inline r code, but you can also use them in code chunks by setting the chunk option `results = 'asis'` and using `cat()` to display the result of the widget.
```{r, results = 'asis'}
# echo = FALSE, results = 'asis'
opts <- c("install.package",
"install.packages",
answer = "library",
"libraries")
q1 <- mcq(opts)
cat("What function loads a package that is already on your computer?", q1)
```
### Fill-In-The-Blanks
Create fill-in-the-blank questions using `fitb()`, providing the answer as the first argument.
```{r, eval = FALSE}
fitb(4)
```
- 2 + 2 is `r fitb(4)`
You can also create these questions dynamically, using variables from your R session (e.g., in a hidden code chunk).
```{r echo = TRUE}
x <- sample(2:8, 1)
```
```{r, eval = FALSE}
fitb(x)
```
- The square root of `r x^2` is: `r fitb(x)`
The blanks are case-sensitive; if you don't care about case, use the argument `ignore_case = TRUE`.
```{r, eval = FALSE}
fitb("E", ignore_case = TRUE)
```
- What is the letter after D? `r fitb("E", ignore_case = TRUE)`
If you want to ignore differences in whitespace use, use the argument `ignore_ws = TRUE` (which is the default) and include spaces in your answer anywhere they could be acceptable.
```{r eval = FALSE}
fitb(c("library( tidyverse )", "library( \"tidyverse\" )", "library( 'tidyverse' )"), ignore_ws = TRUE, width = "20")
```
- How do you load the tidyverse package? `r fitb(c("library( tidyverse )", "library( \"tidyverse\" )", "library( 'tidyverse' )"), ignore_ws = TRUE, width = "20")`
You can set more than one possible correct answer by setting the answers as a vector.
```{r, eval = FALSE}
fitb(c("A", "E", "I", "O" , "U"), ignore_case = TRUE)
```
- Type a vowel: `r fitb(c("A", "E", "I", "O" , "U"), ignore_case = TRUE)`
You can use regular expressions to test answers against more complex rules.
```{r, eval = FALSE}
fitb("^[a-zA-Z]{3}$", width = 3, regex = TRUE)
```
- Type any 3 letters: `r fitb("^[a-zA-Z]{3}$", width = 3, regex = TRUE)`
### Multiple Choice
Set up a multiple-choice drop-down menu using `mcq()`.
```{r, eval = FALSE}
mcq(c("tidyr", "dplyr", answer = "readr", "ggplot2"))
```
- What package helps you load CSV files? `r mcq(c("tidyr", "dplyr", answer = "readr", "ggplot2"))`
- "Never gonna give you up, never gonna: `r mcq(c("let you go", "turn you down", "run away", answer = "let you down"))`"
- "I `r mcq(c(answer = "bless the rains", "guess it rains", "sense the rain"))` down in Africa" -Toto
### True or False
Make quick true/false questions with `torf()`.
```{r, eval = FALSE}
torf(TRUE)
torf(FALSE)
```
- True or False? You can permute values in a vector using `sample()`. `r torf(TRUE)`
### Longer MCQs
When your answers are very long, sometimes a drop-down select box gets formatted oddly. You can use `longmcq()` to deal with this. Since the answers are long, It's probably best to set up the options inside an R chunk with `echo=FALSE`.
```{r, echo = TRUE}
opts_p <- c(
"the probability that the null hypothesis is true",
answer = "the probability of the observed, or more extreme, data, under the assumption that the null-hypothesis is true",
"the probability of making an error in your conclusion"
)
```
```{r, eval=FALSE}
longmcq(opts_p)
```
**What is a p-value?**
`r longmcq(opts_p)`
**What is true about a 95% confidence interval of the mean?**
```{r, echo = FALSE}
# use sample() to randomise the order
opts_ci <- sample(c(
answer = "if you repeated the process many times, 95% of intervals calculated in this way contain the true mean",
"there is a 95% probability that the true mean lies within this range",
"95% of the data fall within this range"
))
```
`r longmcq(opts_ci)`
## Checked sections
Create sections with the class `webex-check` to add a button that hides feedback until it is pressed. Add the class `webex-box` to draw a box around the section (or use your own styles).
````{verbatim}
::: {.webex-check .webex-box}
I am going to learn a lot: `r torf(TRUE)`
```{r, results='asis', echo = FALSE}
opts <- c(
"the probability that the null hypothesis is true",
answer = "the probability of the observed, or more extreme, data, under the assumption that the null-hypothesis is true",
"the probability of making an error in your conclusion"
)
cat("What is a p-value?", longmcq(opts))
```
:::
````
::: {.webex-check .webex-box}
I am going to learn a lot: `r torf(TRUE)`
```{r, results='asis', echo = FALSE}
opts <- c(
"the probability that the null hypothesis is true",
answer = "the probability of the observed, or more extreme, data, under the assumption that the null-hypothesis is true",
"the probability of making an error in your conclusion"
)
cat("What is a p-value?", longmcq(opts))
```
:::
## Hidden solutions and hints
You can fence off a solution area that will be hidden behind a button using `hide()` before the solution and `unhide()` after, each as inline R code. Pass the text you want to appear on the button to the `hide()` function.
````{verbatim}
`r hide("Click here to see the solution")`
```{r, echo = FALSE}
hist(rnorm(1000))
```
`r unhide()`
````
Plot a histogram of 1000 values from a random normal distribution.
`r hide("Click here to see the solution")`
```{r, echo = FALSE}
hist(rnorm(1000))
```
`r unhide()`
If the solution is an RMarkdown code chunk, instead of using `hide()` and `unhide()`, you can set the `webex.hide` chunk option to TRUE, or set it to the string you wish to display on the button.
````{verbatim}
```{r, echo = TRUE, eval = FALSE, webex.hide = "See a hint"}
?plot
```
````
```{r, echo = TRUE, eval = FALSE, webex.hide = "See a hint"}
?plot
```
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
```{r, echo = FALSE, results = 'asis'}
js <- system.file("reports/default/webex.js", package = "webexercises")
cat(paste(readLines(js), collapse = "\n"))
```