```{css alert, echo = FALSE, eval = !identical(Sys.getenv("IN_PKGDOWN", "false"), "true")} / alerts for standard vignettes (not pkgdown with BS5) / .alert { padding: 0.5em 1em; margin: 1em 2em; border: 1px #eee solid; border-radius: 5px; } .alert.alert-success { background-color: #e4f2dc; border-color: #ddedcf; } .alert.alert-success, .alert.alert-success code, .alert.alert-success code a:not(.close):not(.btn) { color: #5c9653; } .alert.alert-danger { background-color: #f2e2e2; border-color: #eed9dc; } .alert.alert-danger, .alert.alert-danger code, .alert.alert-danger code a:not(.close):not(.btn) { color: #ad3532; } .alert code { background-color: #ffffff55; }

```{css echo=FALSE, eval = identical(Sys.getenv("IN_PKGDOWN", "false"), "true")}
/* tweak alert code colors for pkgdown */
.alert code {
  background-blend-mode: lighten;
  background-color: rgba(255, 255, 255, 0.5);
  background-image: none;
  color: inherit;
}

```{css echo=FALSE} / tweak alerts for both pkgdown and standard vignettes / .alert > :last-child { margin-bottom: 0; } / tab button colors / [id^="correct"] svg { fill: var(--bs-success, #5c9653); } [id^="wrong"] svg { fill: var(--bs-danger, #ad3532); } button[role="tab"] > svg { margin-right: 3px; }

```{css callout, echo=FALSE}
.callout {
  padding: 1.5rem 1.5rem 1.5rem 80px;
  margin: 1em 0;
  background-size: 40px;
  background-repeat: no-repeat;
  background-position: 20px 1.5em;
  min-height: 80px;
  position: relative;
  border: 2px solid;
}

.callout::before {
  content: "!";
  display: flex;
  position: absolute;
  top: 0;
  left: 0;
  background-repeat: no-repeat;
  background-size: contain;
  width: 40px;
  height: 40px;
  transform: translate(20px, 20px) scale(1);
  transition: transform 0.15s linear, background-color 0.2s linear;
  font-weight: bold;
  font-size: 2em;
  background-color: #486181;
  color: white;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
}

.callout:first-child {
  margin-top: 0;
}

.callout p:last-child {
  margin-bottom: 0;
}

.callout {
  border-color: #b5c1d2;
}

.callout p, .callout ol, .callout ul {
  color: #486181;
}

.callout h3, .callout h4 {
  color: #294263;
}

.callout p code, .callout ol code, .callout ul code, .callout h3 code, .callout h4 code {
  background-color: #e9f2fd;
  color: #294263;
}

.callout blockquote {
  border-color: #b5c1d1;
}

@media only screen and (max-width: 400px) {
  .callout::before {
    transform: translate(-10px, -15px) scale(0.9);
  }
  .callout {
    padding-left: 1.5rem;
    padding-top: 1.5rem;
    margin-top: 1.5rem;
  }
}
library(gradethis)
library(tblcheck)

gradethis_setup(
    pass.praise = TRUE,
    fail.hint = TRUE,
    fail.encourage = TRUE,
    maybe_code_feedback.before = "\n\n"
)

knitr::opts_chunk$set(
    collapse = TRUE,
    comment = "#>"
)

set.seed(424341)
options(max.print = 20, width = 70)

source(system.file("internal", "fake-grading.R", package = "tblcheck"), local = TRUE)

fake_grade_example <- function(example) {
    ex_prefix <- strsplit(example, "-")[[1]][1]
    fake_grade_chunks(
        user = example,
        setup = paste0(ex_prefix, "-setup"),
        solution = paste0(ex_prefix, "-solution"),
        check = paste0(ex_prefix, "-check")
    )
}

icons <- list(
    code = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M1.75 1.5a.25.25 0 00-.25.25v12.5c0 .138.112.25.25.25h12.5a.25.25 0 00.25-.25V1.75a.25.25 0 00-.25-.25H1.75zM0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0114.25 16H1.75A1.75 1.75 0 010 14.25V1.75zm9.22 3.72a.75.75 0 000 1.06L10.69 8 9.22 9.47a.75.75 0 101.06 1.06l2-2a.75.75 0 000-1.06l-2-2a.75.75 0 00-1.06 0zM6.78 6.53a.75.75 0 00-1.06-1.06l-2 2a.75.75 0 000 1.06l2 2a.75.75 0 101.06-1.06L5.31 8l1.47-1.47z"></path></svg>',
    correct = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M8 16A8 8 0 108 0a8 8 0 000 16zm3.78-9.72a.75.75 0 00-1.06-1.06L6.75 9.19 5.28 7.72a.75.75 0 00-1.06 1.06l2 2a.75.75 0 001.06 0l4.5-4.5z"></path></svg>',
    wrong = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg>'
)

Overview

To help you get a feel for the kind of advice tblcheck provides, we've collected a few example exercises that use grade_this_table() or grade_this_vector() from tblcheck to grade a learnr exercise.

In the examples below, we'll show the specific R chunks you'd need to prepare the exercise. Globally, we assume learnr and gradethis are already loaded, and we've made a few adjustments to the default gradethis options using gradethis::gradethis_setup():

```r`r ''`
library(learnr)
library(gradethis)
library(tblcheck)

gradethis_setup(
  pass.praise = TRUE,
  fail.hint = TRUE,
  fail.encourage = TRUE,
  maybe_code_feedback.before = "\n\n"
)
```

Note that in all examples below we're using either grade_this_table() or grade_this_vector() without any additional customizations. We've also made sure that each exercise contains a -solution chunk. (Read more about how to set up an exercise for use with tblcheck.)

Create a Table {.tabset}

The first example repeats the example presented in the Get started article. The goal is for the learner to use the tibble::tibble() function to create a table, but it takes them a few tries.

Prompt
Create a tibble with three columns: food, vegetable, and color.

  • In food, store "lettuce" and "tomato".
  • In vegetable, store whether the food is a vegetable.
  • In color, store the color of the food.

r icons$code Exercise Code

```r
library(tibble)
```

```r
```

```r
tibble(
    food = c("lettuce", "tomato"),
    vegetable = c(TRUE, FALSE),
    color = c("green", "red")
)
```

```r
grade_this_table()
```

r icons$correct Correct Answer


fake_grade_example("tomato-solution")

r icons$wrong Wrong Class

list(
    food = "lettuce",
    fruit = "TRUE",
    color = "green"
)
fake_grade_example("tomato-wrong-class")

r icons$wrong Wrong Names

tibble(
    food = "lettuce",
    fruit = "TRUE",
    color = "green"
)
fake_grade_example("tomato-wrong-names")

r icons$wrong Wrong Length

tibble(
    food = "lettuce",
    vegetable = "TRUE",
    color = "green"
)
fake_grade_example("tomato-wrong-length")

r icons$wrong Wrong Column Class

tibble(
    food = c("lettuce", "tomato"),
    vegetable = c("TRUE", "TRUE"),
    color = c("green", "red")
)
fake_grade_example("tomato-wrong-column-class")

r icons$wrong Wrong Column Values

tibble(
    food = c("lettuce", "tomato"),
    vegetable = c(TRUE, TRUE),
    color = c("green", "red")
)
fake_grade_example("tomato-wrong-column-values")

Transform a Table with transmute() {.tabset}

The first example shows all of the problems that tblcheck will discover. This example, however, is more realistic.

In this problem students are asked to use the dplyr::transmute() function to transform the starwars dataset.

Prompt
Consider the starwars dataset. Use transmute() to turn convert height from centimeters into inches and mass from kilgrams into pounds, keeping only those columns.

r icons$code Exercise Code

```r
library(dplyr)
```

```r
```

```r
starwars %>%
    transmute(
        height = height / 2.54,
        mass = mass * 2.205
    )
```

```r
grade_this_table(check_column_order = TRUE)
```

r icons$correct Correct Answer

The correct answer uses dplyr::transmute() to divide the height column by 2.54 (to convert height from cm to in) and to multiply the mass column by 2.205 (to convert kg to lb). Note that transmute() keeps only the columns named in its calculations, so our final table has only two columns.


r icons$wrong Wrong Function

In this example, the student uses dplyr::mutate(), which is certainly a reasonable choice but not what was requested. As a result, their submission contains more columns than expected.

starwars %>%
    mutate(
        height = height / 2.54,
        mass = mass * 2.205
    )
fake_grade_example("starwars-wrong-mutate")

r icons$wrong Wrong Column Order

Here the student has done more or less the right thing, but they specified the columns in the opposite order.

starwars %>%
    transmute(
        mass = mass * 2.205,
        height = height / 2.54
    )
fake_grade_example("starwars-wrong-columns")

If we decide we don't mind if the columns aren't in the right order, we could set check_column_order = FALSE in the check code for this exercise.

```r
grade_this_table(check_column_order = FALSE)
```
fake_grade_chunks("starwars-wrong-columns", check = "starwars-check-no-order", setup = "starwars-setup", solution = "starwars-solution")

r icons$wrong Wrong Column Classes

If the student were to somehow create columns with an incorrect class, e.g. integer values where doubles were expected, tblcheck will alert them to their mistake.

starwars %>%
    transmute(
        mass = as.integer(mass * 2.205),
        height = as.integer(height / 2.54)
    )
fake_grade_example("starwars-wrong-class")

r icons$wrong Wrong Calculation

If the values are completely wrong — here the student is multiplying height by 2.54 rather than dividing — then tblcheck points out which column is incorrect and gives a hint about the expected values.

starwars %>%
    transmute(
        height = height * 2.54,
        mass = mass * 2.205
    )
fake_grade_example("starwars-wrong-values")

Transform a Factor Column {.tabset}

This example comes from a lesson on factors in R. Students have just learned about functions from the forcats package, and are now asked to practice using forcats::fct_reorder().

Prompt
Consider the marital_age dataset. Use fct_reorder() to turn the marital column into a factor with levels ordered based on avg_age.

r icons$code Exercise Code

We created a new table specifically for this exercise in the factor-setup chunk, drawing from the data provided in forcats::gss_cat.

```r
library(dplyr)
library(forcats)

marital_age <- gss_cat %>%
    mutate(marital = as.character(marital)) %>%
    group_by(marital) %>%
    summarize(avg_age = mean(age, na.rm = TRUE)) %>%
    ungroup()
```

```r
marital_age
```

```r
marital_age %>%
    mutate(marital = fct_reorder(marital, avg_age))
```

```r
grade_this_table()
```

Since students aren't familiar with the marital_age table, we've included the starter code so they can see the initial state of the table when they start the exercise.


r icons$correct Correct Answer

In the expected solution, the student will use the forecats::fct_reorder() function to transform the marital column, reordering its factor levels by increasing avg_age.


fake_grade_chunks("factor-solution", solution = "factor-solution", check = "factor-check", setup = "factor-setup")

r icons$wrong Wrong Function

Here the student forgets about the forcats::fct_reorder() function and tries to use order() to set the order of the factor levels in the marital column.

marital_age %>%
    mutate(marital = order(marital, avg_age))
fake_grade_chunks("factor-wrong-class", solution = "factor-solution", check = "factor-check", setup = "factor-setup")

r icons$wrong Wrong Column

In this case the student remembers to use forecats::fct_reorder() but incorrectly assigns the result to an unexpected column.

marital_age %>%
    mutate(marital_fct = fct_reorder(marital, avg_age))
fake_grade_chunks("factor-wrong-column", solution = "factor-solution", check = "factor-check", setup = "factor-setup")

r icons$wrong Wrong Direction

In another case, the student uses forecats::fct_reorder() but sets .desc = TRUE, resulting in an unexpected ordering of the factor levels.

marital_age %>%
    mutate(marital = fct_reorder(marital, avg_age, .desc = TRUE))
fake_grade_chunks("factor-wrong-subset", solution = "factor-solution", check = "factor-check", setup = "factor-setup")

Subset a Vector with stringr {.tabset}

In addition to table-checking functions, tblcheck includes functions for checking vectors — after all, columns in a table are vectors!

Here's an example exercise from a tutorial on string transformations with the stringr package. Students are asked to practice concepts they just discovered in the tutorial:

Prompt
Consider the fruit data. Use a function from stringr to create a vector containing only the fruits with more than one word in their name.

Hint: a fruit named with more than one word also has at least one space in its name.

r icons$code Exercise Code

In the exercise markdown, we call grade_this_vector() in the string-check chunk to automatically compare the result of the student's submission with our string-solution.

```r
library(dplyr)
library(stringr)
```

```r
```

```r
str_subset(fruit, " ")
```

```r
grade_this_vector()
```

Note that fruit is from stringr::fruit, a vector containing r length(stringr::fruit) fruit names.

head(stringr::fruit, 20)

r icons$correct Correct Answer

r length(stringr::str_subset(stringr::fruit, " ")) of the r length(stringr::fruit) fruits have more than one word. What's your favorite two-worded fruit name? (Mine is the purple mangosteen.)


fake_grade_example("string-solution")

r icons$wrong Wrong Class

This student submission makes a potentially common mistake of hoping that stringr::str_which() will return the fruit which have pattern. Instead, str_which() follows the base R function which(), and returns an integer index indicating the items in fruit where the pattern is matched.

str_which(fruit, " ")
fake_grade_example("string-wrong-which")

r icons$wrong Wrong Length

In another mistake example, this student probably expected stringr::str_extract() to extract elements from the vector. However, str_extract() instead extracts the pattern from each item, so it returns a vector with the same length as the input.

str_extract(fruit, " ")
fake_grade_example("string-wrong-extract")

r icons$wrong Wrong Subset

Finally, a student might have chosen the right function, but they missed our hint and came up with a pattern that's too clever. Here the student probably looked at the first 20 fruit names and took a guess at the answer.

str_subset(fruit, " (pepper|orange|melon|fruit)")
fake_grade_example("string-wrong-subset")


rstudio/tblcheck documentation built on March 11, 2023, 5:42 p.m.