Designing and Grading Interactive R Exercises

Create Exercises with Hints, Solutions, and Custom Grading in Quarto Live

Learn how to design interactive R exercises using Quarto Live. This tutorial provides a step-by-step guide to creating exercises, including setting up code, adding hints and solutions, and implementing custom grading for immediate feedback.

Tools
Author
Affiliation
Published

March 15, 2025

Keywords

interactive R exercises, Quarto Live grading, R interactive challenges

Introduction

Interactive exercises enhance learning by offering immediate feedback through hints, solutions, and custom grading. In this tutorial, you’ll create an interactive exercise step-by-step using Quarto Live. We’ll cover the following:

  1. Creating a Basic Exercise
    Define an interactive code block as an exercise using a unique label.

  2. Running Setup Code
    Prepare the environment (e.g., load packages or set variables) before the learner’s code is executed.

  3. Adding Hints and Solutions
    Provide progressive hints to guide the learner. Offer a full solution that can be revealed when needed.

  4. Using Tabsets for Exercises
    Organize hints and solutions in a tabset for a cleaner user interface.

  5. Implementing Custom Grading
    Write custom grading logic that provides immediate feedback based on the learner’s input.

Let’s go through each of these steps with practical examples.



Creating a Basic Exercise

To mark a webr code block as an exercise, use the exercise cell option with a unique label. For example, the following block asks the learner to fill in the blank so that the sum equals 10:

Source

exercise.qmd
Fill in the blank so that the result of the sum is 10.

```{webr}
#| exercise: ex_1
1 + 2 + 3 + ______
```

Output

Fill in the blank so that the result of the sum is 10.

Note

Exercises do not auto-evaluate by default. The learner must click “Run Code” to see the output.

Running Setup Code

Often, you’ll need to run setup code before an exercise (e.g., to load packages or define variables).

A setup code block can be created as follow:

  1. Define a Setup Block:
    Use the setup: true cell option to designate a code block as setup code.
  2. Link to an Exercise: Set the exercise cell option to match an existing exercise label.
Note

The setup code will be executed before the learner’s code in the exercise.

Example Setup Code for One Exercise

Find below an example of a setup code block followed by an exercise block:

Source

Fill in the blank so that the result of the sum is 10.

exercise.qmd
```{webr}
#| setup: true
#| exercise: ex_2
foo <- 1
bar <- 2
baz <- 3
```

```{webr}
#| exercise: ex_2
foo + bar + baz + ______
```

Output

Fill in the blank so that the result of the sum is 10.

Example Setup Code for Multiple Exercises

A setup block may be attached to multiple exercises by providing a list of exercises for the exercise cell option. The code in the setup cell will be executed before every evaluation of any of the listed exercises.

Source

exercise.qmd
```{webr}
#| setup: true
#| exercise:
#|   - ex_a1
#|   - ex_a2
var_xyz <- c(1, 3, 7, 9, 13, 15)
```

```{webr}
#| exercise: ex_a1
var_xyz * 2
```

```{webr}
#| exercise: ex_a2
var_xyz ** 2
```

Output

Adding Hints and Solutions

  • Hints are added using fenced blocks with the .hint class and the same exercise attribute. They are revealed progressively when the learner requests help.
  • Solutions are added using fenced blocks with the .solution class and the same exercise attribute. They are revealed at once when the learner requests the solution.

Source

exercise.qmd
Filter the `starwars` dataset so that only the droid characters are included.

```{webr}
#| setup: true
#| exercise: ex_3
library(dplyr)
```

```{webr}
#| exercise: ex_3
starwars |> ______
```

::: { .hint exercise="ex_3"}
::: { .callout-note collapse="false"}
## Hint 1

Consider using the `filter()` function from `dplyr`.

```r
starwars |> filter(______)
```
:::
:::

::: { .hint exercise="ex_3"}
::: { .callout-note collapse="false"}
## Hint 2

You should filter the dataset using the `species` column.

```r
starwars |> filter(species == ______)
```
:::
:::

::: { .solution exercise="ex_3" }
::: { .callout-tip collapse="false"}
## Fully worked solution:

Use the `filter()` function from `dplyr`:

```r
starwars |>                                 #<1>
    filter(species == "Droid")              #<2>
```
1. Take the `starwars` dataset, and then,
2. Filter for the "Droid" species.

:::
:::

Output

Filter the starwars dataset so that only the droid characters are included.

Hint 1

Consider using the filter() function from dplyr.

starwars |> filter(______)
Hint 2

You should filter the dataset using the species column.

starwars |> filter(species == ______)
Fully worked solution:

Use the filter() function from dplyr:

1starwars |>
2    filter(species == "Droid")
1
Take the starwars dataset, and then,
2
Filter for the “Droid” species.

Organizing Exercises with Tabsets

For a cleaner interface, you can wrap hints and solutions in a tabset. This allows learners to reveal hints progressively and see the solution when ready.

Source
exercise.qmd
:::: {.panel-tabset}

## Exercise

```{webr}
#| setup: true
#| exercise: ex_4
library(dplyr)
```

```{webr}
#| exercise: ex_4
starwars |> ______
```

## Hints

::: { .hint exercise="ex_4"}
Consider using the `filter()` function from `dplyr`.

```r
starwars |> filter(______)
```
:::

## Solution

::: { .solution exercise="ex_4" }
Use the `filter()` function from `dplyr`:

```r
starwars |>                                 #<1>
    filter(species == "Droid")              #<2>
```
1. Take the `starwars` dataset, and then,
2. Filter for the "Droid" species.
:::

::::

Output

Consider using the filter() function from dplyr.

starwars |> filter(______)

Use the filter() function from dplyr:

1starwars |>
2    filter(species == "Droid")
1
Take the starwars dataset, and then,
2
Filter for the “Droid” species.

Document level options

Enable and disable hints and solutions for an entire document using the live key in the document YAML header.

---
live:
  show-hints: true
  show-solutions: true
---

Implementing Custom Grading

To automatically evaluate the learner’s code, include a code block with the check: true option. This block compares the learner’s output (referenced by .result) to the expected result.

Source

Calculate the average of all of the integers from 1 to 10.

```{webr}
#| exercise: ex_1_r
______(1:10)
```

```{webr}
#| exercise: ex_1_r
#| check: true
if (identical(.result, mean(1:10))) {
  list(correct = TRUE, message = "Nice work!")
} else {
  list(correct = FALSE, message = "That's incorrect, sorry.")
}
```

Output

Calculate the average of all of the integers from 1 to 10.

Note

This grading block automatically provides feedback based on the learner’s input.

Further Reading

Conclusion

Designing interactive exercises in Quarto Live allows you to provide a hands-on, supportive learning experience. By following this step-by-step guide, you can create exercises that include setup code, hints, solutions, and custom grading logic. Experiment with these techniques and adapt them to your teaching needs to build engaging interactive R challenges.

Back to top

Reuse

Citation

BibTeX citation:
@online{kassambara2025,
  author = {Kassambara, Alboukadel},
  title = {Designing and {Grading} {Interactive} {R} {Exercises}},
  date = {2025-03-15},
  url = {https://www.datanovia.com/learn/interactive/r/exercises.html},
  langid = {en}
}
For attribution, please cite this work as:
Kassambara, Alboukadel. 2025. “Designing and Grading Interactive R Exercises.” March 15, 2025. https://www.datanovia.com/learn/interactive/r/exercises.html.