diff --git a/DESCRIPTION b/DESCRIPTION
index 67afeda..b668b44 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -33,4 +33,5 @@ Suggests:
testthat (>= 3.0.0),
digest
Remotes:
+ rstudio/learnr,
rstudio/gradethis
diff --git a/R/build_learnr.R b/R/build_learnr.R
index c7f1d46..8297321 100644
--- a/R/build_learnr.R
+++ b/R/build_learnr.R
@@ -27,7 +27,12 @@ build_learnr <- function(template_file_path, packages = c("learnr", "gradethis",
packages <- c(packages, template$packages)
}
- setup <- paste("```{r setup, include=FALSE}\n", paste("library(", packages, ")", sep = "", collapse = "\n"), "\n```\n")
+ setup <- paste(
+ "```{r setup, include=FALSE}\n",
+ paste("library(", packages, ")", sep = "", collapse = "\n"),
+ "\n",
+ ifelse("setup" %in% names(template), template$setup, ""),
+ "\n```\n")
intro <- template$introduction
@@ -176,7 +181,8 @@ build_content <- function(content, depth = 1, section = 0) {
} else if (item$type == "section") {
markdownText <- paste0(markdownText, prefix, " ", item$title, "\n\n", build_content(item$content, depth + 1))
} else if (item$type == "image") {
- markdownText <- paste0(markdownText, "\n\n")
+ markdownText <- paste0(markdownText, "\n\n")
+ #markdownText <- paste0(markdownText, "\n\n")
} else if (item$type == "code") {
if(is.null(item$name)) {
item$name <- paste0("ex-", generateCodeBlockName(item))
@@ -204,7 +210,7 @@ build_content <- function(content, depth = 1, section = 0) {
} else if (item$type == "table") {
# Simple table conversion; consider enhancing for complex tables
headerRow <- paste("|", paste(item$header, collapse = " | "), "|")
- separatorRow <- paste("|", paste(rep("---", length(item$header)), collapse = " | "), "|")
+ separatorRow <- paste("|", paste(rep(":---", length(item$header)), collapse = " | "), "|")
bodyRows <- sapply(item$rows, function(row) paste("|", paste(row, collapse = " | "), "|"))
tableMarkdown <- paste(c(headerRow, separatorRow, bodyRows), collapse = "\n")
markdownText <- paste0(markdownText, tableMarkdown, "\n\n")
@@ -271,6 +277,7 @@ build_exercise <- function(exercise, exercise_number) {
hints <- exercise$hints
solution <- exercise$solution$code
explanation <- exercise$solution$explanation
+ custom_check <- exercise$solution$check
# Initialize the Rmarkdown content with the exercise instruction
rmarkdown_content <- paste0("### Exercise ", exercise_number, "\n\n", instructions, "\n\n```{r exercise", exercise_number, ", exercise = TRUE}\n# Your code here\n```\n\n")
@@ -288,7 +295,21 @@ build_exercise <- function(exercise, exercise_number) {
explanation_formatted <- stringr::str_replace_all(explanation, "\n", " ")
# Add the exercise check to the Rmarkdown content
- rmarkdown_content <- paste0(rmarkdown_content, "```{r exercise", exercise_number, "-check}\ngrade_this_code(\n correct = c(gradethis::random_praise(), \"", explanation_formatted, "\")\n)\n```\n")
+ if (!is.null(custom_check)) {
+ rmarkdown_content <- paste0(
+ rmarkdown_content,
+ "```{r exercise", exercise_number, "-check}\n",
+ custom_check,
+ "\n```\n"
+ )
+ } else {
+ rmarkdown_content <- paste0(
+ rmarkdown_content,
+ "```{r exercise", exercise_number, "-check}\ngrade_this_code(\n correct = c(gradethis::random_praise(), \"",
+ explanation_formatted,
+ "\")\n)\n```\n"
+ )
+ }
return(rmarkdown_content)
diff --git a/R/reset_lessons.R b/R/reset_lessons.R
new file mode 100644
index 0000000..fa23d93
--- /dev/null
+++ b/R/reset_lessons.R
@@ -0,0 +1,78 @@
+#' Reset a specified lesson from the available tutorials
+#'
+#' This function allows the user to reset a specific lesson from the available tutorials in the `trainingRIntro` package.
+#' It prompts the user to select a lesson if not specified. It checks the validity of the input and handles errors
+#' appropriately, ensuring that only available lessons can be reset.
+#'
+#' @param number An optional integer specifying the lesson number to reset.
+#' If NA (default), the function will prompt the user to choose a lesson.
+#'
+#' @details If `number` is not provided or is NA, the function prompts the user interactively to choose a lesson from
+#' a list of available tutorials. The function ensures that the input corresponds to a valid lesson number
+#' and provides error feedback for invalid entries.
+#'
+#' @return NULL, the function is used for its side effects of running a lesson interactively.
+#' @importFrom learnr available_tutorials
+#' @importFrom learnr run_tutorial
+#' @export
+reset_lesson <- function(number = NA) {
+
+ x <- learnr::available_tutorials()
+ x <- x[x$package == "trainingRIntro", ]
+
+ if(nrow(x) == 0) {
+ stop("No lessons found")
+ }
+
+ # If number is NA (not provided), prompt user to choose a lesson
+ if(is.na(number)) {
+ cat("Please choose a lesson to reset by entering its number:\n")
+ for(i in 1:nrow(x)) {
+ cat(i, ": ", x$title[i], "\n", sep = "")
+ }
+
+ # Using readline() to get input from user
+ repeat {
+ number <- as.integer(readline(prompt = "Enter the lesson number: "))
+ if(!is.na(number) && number > 0 && number <= nrow(x)) break
+ cat("Invalid input. Please enter a number between 1 and ", nrow(x), ".\n", sep = "")
+ }
+ }
+
+ user <- Sys.info()['user']
+
+ dir <- paste0("training.r.intro.", number)
+
+ storage_path <- file.path(rappdirs::user_data_dir(), "R", "learnr", "tutorial", "storage", user, dir)
+
+ if (dir.exists(storage_path)) {
+ dir.remove(storage_path, recursive = TRUE)
+ }
+
+}
+
+#' Resets the user's progress in the trainingRIntro package
+#'
+#' This function allows the user to reset all lessons from the available tutorials in the `trainingRIntro` package.
+#'
+#' @export
+reset_training <- function() {
+
+ x <- learnr::available_tutorials()
+ x <- x[x$package == "trainingRIntro", ]
+
+ if(nrow(x) == 0) {
+ stop("No lessons found")
+ }
+
+ for(i in 1:nrow(x)) {
+ reset_lesson(i)
+ }
+
+ if(file.exists(user_state_file())) {
+ file.remove(user_state_file())
+ }
+
+ return(invisible(TRUE))
+
+}
diff --git a/docs/1-Introduction/readme.md b/docs/1-Introduction/readme.md
index 2457838..65a6ca3 100644
--- a/docs/1-Introduction/readme.md
+++ b/docs/1-Introduction/readme.md
@@ -80,12 +80,12 @@ Once you have installed R, you can open the program itself. On a PC, if you have
will look like this:
-
+
Once opened, the R console looks very plain.
-
+
RStudio makes R much more user friendly. It's free and can be downloaded from the [Posit website](https://posit.co/download/rstudio-desktop/).
Accept the defaults during installation. It's not necessary to open RStudio to use R, but in these sessions we will assume that RStudio is your
@@ -95,29 +95,29 @@ interface to R.
On a PC, the RStudio desktop icon looks like this:
-
+
When you first open RStudio, this is what you see:
-
+
The left panel is the console for R. Type `1 + 1` in the console then hit "Enter" and R will return the answer.
-
+
It's a good idea to use a script so you can save your code. Open a new script by selecting "File" -> "New File" -> "R Script" and it will appear
in the top left panel of RStudio.
-
+
This is a text document that can be saved. Go to "File" -> "Save As" and you can save the file with a `.R` extension. You can type and run more
than one line at a time by highlighting and clicking the "Run" button on the script tool bar.
-
+
The bottom right panel can be used to find and open files, view plots, load packages, and look at help pages. The top right panel gives you information
about what variables you're working with during your R session.
@@ -143,7 +143,7 @@ in the R language.
| Operator | Meaning | Example |
-| --- | --- | --- |
+| :--- | :--- | :--- |
| + | addition | 2 + 2 |
| - | subtraction | 2 - 2 |
| * | multiplication | 2 * 2 |
@@ -221,7 +221,7 @@ x + y
In RStudio, you will see the variables we created in the top right panel.
-
+
If you've already created a variable, you can replace the value with another value.
@@ -240,7 +240,7 @@ x
In the top right panel you can see that the number stored in the variable `x` has changed.
-
+
There are 3 important rules to remember when creating variable names:
@@ -264,7 +264,7 @@ R has three main data types:
| Type | Description | Examples |
-| --- | --- | --- |
+| :--- | :--- | :--- |
| character | letters and words | `z`, `red`, `H2O` |
| numeric | numbers | `1`, `3.14`, `log(10)` |
| logical | binary | `TRUE`, `FALSE` |
diff --git a/docs/2-Functions-and-Importing-Data/readme.md b/docs/2-Functions-and-Importing-Data/readme.md
index d4192f7..4880f4e 100644
--- a/docs/2-Functions-and-Importing-Data/readme.md
+++ b/docs/2-Functions-and-Importing-Data/readme.md
@@ -89,7 +89,7 @@ Many functions also have additional options you can choose, which are called the
In RStudio, you will see the help page for `mean()` in the bottom right corner panel.
-
+
On the help page, under `Usage`, you see `mean(x, ...)`. This means that the only thing that necessarily has to go into `( )` is `x`. On the help page under `Arguments` you will find a description of what `x` needs to be: a numeric or logical vector.
@@ -301,12 +301,12 @@ It's not available because we need to install the package first (again, like ini
In the bottom right panel of RStudio, click on the "Packages" tab then click "Install Packages" in the tool bar.
-
+
A window will pop up. Start typing "EnvStats" into the "Packages" box, select that package, and click "Install".
-
+
Now that we've installed the package, we still can't use the function we want. We need to load the package first (opening the app). We use the `library()` function to do this.
@@ -377,7 +377,14 @@ library(readxl)
Use the `read_excel()` function from the `readxl` package to read emissions data from [this Excel workbook](https://github.com/LADCO/training-r-intro/blob/main/data/emissions_IL_2022.xlsx). Download the file to your working directory and read the first worksheet (named "UNIT_DATA"), skipping the first 6 rows.
-```{r ex-42c0a66e0643, exercise = TRUE, exercise.eval = FALSE, exercise.lines = 5, exercise.cap = 'Read and Inspect Excel Data'}
+```{r ex-4cbff1905b04, exercise = FALSE, eval = FALSE, exercise.cap = 'Read and Inspect Excel Data'}
+library(readxl)
+emissions <- read_excel("emissions_IL_2022.xlsx", sheet = "UNIT_DATA", skip = 6)
+head(emissions)
+
+```
+
+```{r ex-42c0a66e0643, echo = FALSE, eval = TRUE, exercise.cap = 'Read and Inspect Excel Data'}
library(readxl)
emissions <- read_excel("./data/emissions_IL_2022.xlsx", sheet = "UNIT_DATA", skip = 6)
head(emissions)
diff --git a/docs/3-Subsetting-Sorting-and-Combining/readme.md b/docs/3-Subsetting-Sorting-and-Combining/readme.md
index 0e5dafe..5471a26 100644
--- a/docs/3-Subsetting-Sorting-and-Combining/readme.md
+++ b/docs/3-Subsetting-Sorting-and-Combining/readme.md
@@ -99,7 +99,7 @@ View(chicago_air)
```
-
+
By inspecting the data frame this way, you can see that the records are daily values of ozone, temperature, and air pressure. For more information about the data set you can type a question mark in from the name of the data frame variable in the console.
diff --git a/docs/4-Writing-Functions-Conditionals-and-Loops/readme.md b/docs/4-Writing-Functions-Conditionals-and-Loops/readme.md
index b65c65a..3cdae61 100644
--- a/docs/4-Writing-Functions-Conditionals-and-Loops/readme.md
+++ b/docs/4-Writing-Functions-Conditionals-and-Loops/readme.md
@@ -28,10 +28,10 @@ This lesson assumes you are familiar with the material in the previous lessons:
- Functions and Importing Data
- Subsetting, Sorting, and Combining Data Frames
-The data for these lessons is available from this package. It is assumed that this package is already installed and loaded into the R session. If you need to refer to the package, simply refer to it as "this package".
+The data for these lessons is available from this package or the `region5air` package.
-```{r ex-b0dd7d25d817, exercise = FALSE, exercise.eval = TRUE, exercise.cap = 'Load Data from This Package'}
+```{r ex-868d2c8c5b75, exercise = FALSE, exercise.eval = TRUE, exercise.cap = 'Load Data from the Package'}
# Assuming the package is already loaded
data(chicago_air)
@@ -61,7 +61,7 @@ We can write a simple function that prints something to the console. Here is a
function named `print_hello`.
-```{r ex-a3bc32a64175, exercise = TRUE, exercise.eval = TRUE, exercise.cap = 'Simple Function to Print Hello'}
+```{r ex-a3bc32a64175, exercise = TRUE, exercise.eval = TRUE, eval = TRUE, exercise.cap = 'Simple Function to Print Hello'}
print_hello <- function() {
print("Hello")
diff --git a/docs/5-Plotting/readme.md b/docs/5-Plotting/readme.md
index a447fd1..1a2441f 100644
--- a/docs/5-Plotting/readme.md
+++ b/docs/5-Plotting/readme.md
@@ -337,7 +337,7 @@ Plots can be saved in RStudio using the "Export" button at the top of the "Plots
pane.
-
+
You can also save a plot made by `ggplot2` using the `ggsave()` function.
diff --git a/docs/6-Basic-Statistics/readme.md b/docs/6-Basic-Statistics/readme.md
index e8757ca..c315c9a 100644
--- a/docs/6-Basic-Statistics/readme.md
+++ b/docs/6-Basic-Statistics/readme.md
@@ -219,7 +219,7 @@ Below is a reference table of a few popular tests for categorical data analysis
| test | function |
-| --- | --- |
+| :--- | :--- |
| Chi Square Test | `chisq.test()` |
| Fisher's Test | `fisher.test()` |
| Analysis of Variance | `aov()` |
diff --git a/inst/tutorials/1-Introduction/lesson.Rmd b/inst/tutorials/1-Introduction/lesson.Rmd
index dd3130e..7aed79d 100644
--- a/inst/tutorials/1-Introduction/lesson.Rmd
+++ b/inst/tutorials/1-Introduction/lesson.Rmd
@@ -14,11 +14,13 @@ output:
runtime: shiny_prerendered
---
+
```{r setup, include=FALSE}
library(learnr)
library(gradethis)
library(trainingRIntro)
library(shiny)
+
```
This lesson is a part of the Introduction to R for Air Quality Data Science. The sections below provide a basic introduction to R, including how to install and set up R and RStudio, an overview of R syntax, and how to perform simple operations.
@@ -82,7 +84,7 @@ in the R language.
| Operator | Meaning | Example |
-| --- | --- | --- |
+| :--- | :--- | :--- |
| + | addition | 2 + 2 |
| - | subtraction | 2 - 2 |
| * | multiplication | 2 * 2 |
@@ -160,7 +162,7 @@ x + y
In RStudio, you will see the variables we created in the top right panel.
-
+
If you've already created a variable, you can replace the value with another value.
@@ -179,7 +181,7 @@ x
In the top right panel you can see that the number stored in the variable `x` has changed.
-
+
There are 3 important rules to remember when creating variable names:
@@ -203,7 +205,7 @@ R has three main data types:
| Type | Description | Examples |
-| --- | --- | --- |
+| :--- | :--- | :--- |
| character | letters and words | `z`, `red`, `H2O` |
| numeric | numbers | `1`, `3.14`, `log(10)` |
| logical | binary | `TRUE`, `FALSE` |
@@ -472,9 +474,31 @@ df <- data.frame(name = c('Alice', 'Bob', 'Charlie'), age = c(25, 32, 28))
```
```{r exercise5-check}
-grade_this_code(
- correct = c(gradethis::random_praise(), "In R, we can combine vectors of equal length into a data frame using the `data.frame()` function. Here, we're creating two vectors, `name` and `age`, and combining them into a data frame, demonstrating how to organize and structure data in a tabular format. ")
-)
+grade_this({
+ # The student's solution
+ df_student <- .result
+
+ # Expected names
+ expected_names <- c('Alice', 'Bob', 'Charlie')
+
+ # Check that the data frame has the correct structure
+ has_correct_columns <- all(names(df_student) == c('name', 'age'))
+ contains_all_names <- all(expected_names %in% df_student$name)
+ are_ages_numeric <- is.numeric(df_student$age)
+
+ # Provide detailed feedback based on specific issues
+ if (!has_correct_columns) {
+ fail("Incorrect columns. Ensure your data frame has exactly two columns named `name` and `age`.")
+ } else if (!contains_all_names) {
+ missing_names <- setdiff(expected_names, df_student$name)
+ fail(paste("Missing the following names:", paste(missing_names, collapse = ", ")))
+ } else if (!are_ages_numeric) {
+ fail("The `age` column should contain numeric values only. Ensure all ages are numbers.")
+ } else {
+ pass("Correct! You've successfully created a data frame with the names 'Alice', 'Bob', and 'Charlie', and ensured that ages are numeric.")
+ }
+})
+
```
diff --git a/inst/tutorials/1-Introduction/lesson.html b/inst/tutorials/1-Introduction/lesson.html
index acfcad0..b629cb7 100644
--- a/inst/tutorials/1-Introduction/lesson.html
+++ b/inst/tutorials/1-Introduction/lesson.html
@@ -10,7 +10,7 @@
-
+
@@ -185,36 +185,36 @@
Basic Math
-
Operator
-
Meaning
-
Example
+
Operator
+
Meaning
+
Example
-
+
-
addition
-
2 + 2
+
+
+
addition
+
2 + 2
-
-
-
subtraction
-
2 - 2
+
-
+
subtraction
+
2 - 2
-
*
-
multiplication
-
2 * 2
+
*
+
multiplication
+
2 * 2
-
/
-
division
-
2 / 2
+
/
+
division
+
2 / 2
-
^
-
exponentiation
-
2 ^ 2
+
^
+
exponentiation
+
2 ^ 2
@@ -277,10 +277,7 @@
Variables
## [1] 15
In RStudio, you will see the variables we created in the top right
panel.
-
-
-
Variables in RStudio
-
+
If you’ve already created a variable, you can replace the value with
another value.
x
@@ -294,11 +291,7 @@
Variables
In the top right panel you can see that the number stored in the
variable x has changed.
-
-
-
Updated variable in RStudio
-
+
There are 3 important rules to remember when creating variable
names:
diff --git a/inst/tutorials/2-Functions-and-Importing-Data/lesson.Rmd b/inst/tutorials/2-Functions-and-Importing-Data/lesson.Rmd
index 10b93cd..910d855 100644
--- a/inst/tutorials/2-Functions-and-Importing-Data/lesson.Rmd
+++ b/inst/tutorials/2-Functions-and-Importing-Data/lesson.Rmd
@@ -1,6 +1,9 @@
---
author: Fluent Data, LLC
date: '`r Sys.Date()`'
+tutorial:
+ id: training.r.intro.2
+ version: 1.0
description: |
This lesson provides an overview of using functions in R, including built-in and package functions, and demonstrates how to import data
from CSV and Excel files.
@@ -17,8 +20,8 @@ runtime: shiny_prerendered
library(learnr)
library(gradethis)
library(trainingRIntro)
-library(shiny)
-library(EnvStats)
+library(shiny)
+
```
This lesson covers the use of functions in R, including built-in functions and functions from packages. It also discusses how to import
@@ -83,7 +86,7 @@ Many functions also have additional options you can choose, which are called the
In RStudio, you will see the help page for `mean()` in the bottom right corner panel.
-
+
On the help page, under `Usage`, you see `mean(x, ...)`. This means that the only thing that necessarily has to go into `( )` is `x`. On the help page under `Arguments` you will find a description of what `x` needs to be: a numeric or logical vector.
@@ -295,12 +298,12 @@ It's not available because we need to install the package first (again, like ini
In the bottom right panel of RStudio, click on the "Packages" tab then click "Install Packages" in the tool bar.
-
+
A window will pop up. Start typing "EnvStats" into the "Packages" box, select that package, and click "Install".
-
+
Now that we've installed the package, we still can't use the function we want. We need to load the package first (opening the app). We use the `library()` function to do this.
@@ -371,7 +374,14 @@ library(readxl)
Use the `read_excel()` function from the `readxl` package to read emissions data from [this Excel workbook](https://github.com/LADCO/training-r-intro/blob/main/data/emissions_IL_2022.xlsx). Download the file to your working directory and read the first worksheet (named "UNIT_DATA"), skipping the first 6 rows.
-```{r ex-42c0a66e0643, exercise = TRUE, exercise.eval = FALSE, exercise.lines = 5, exercise.cap = 'Read and Inspect Excel Data'}
+```{r ex-4cbff1905b04, exercise = FALSE, eval = FALSE, exercise.cap = 'Read and Inspect Excel Data'}
+library(readxl)
+emissions <- read_excel("emissions_IL_2022.xlsx", sheet = "UNIT_DATA", skip = 6)
+head(emissions)
+
+```
+
+```{r ex-42c0a66e0643, echo = FALSE, eval = TRUE, exercise.cap = 'Read and Inspect Excel Data'}
library(readxl)
emissions <- read_excel("./data/emissions_IL_2022.xlsx", sheet = "UNIT_DATA", skip = 6)
head(emissions)
diff --git a/inst/tutorials/3-Subsetting-Sorting-and-Combining/lesson.Rmd b/inst/tutorials/3-Subsetting-Sorting-and-Combining/lesson.Rmd
index 70af565..d00f7da 100644
--- a/inst/tutorials/3-Subsetting-Sorting-and-Combining/lesson.Rmd
+++ b/inst/tutorials/3-Subsetting-Sorting-and-Combining/lesson.Rmd
@@ -1,6 +1,9 @@
---
author: Fluent Data, LLC
date: '`r Sys.Date()`'
+tutorial:
+ id: training.r.intro.3
+ version: 1.0
description: |
This lesson provides an overview of subsetting, sorting, and combining data frames in R using indexing, logical operations, the filter() function from dplyr, as well as sorting with arrange() and combining data frames with bind_rows().
title: 3 . Subsetting, Sorting, and Combining Data Frames
@@ -17,6 +20,7 @@ runtime: shiny_prerendered
library(gradethis)
library(trainingRIntro)
library(shiny)
+
```
This lesson covers how to subset data using indexing, logical operators, and the `filter()` function from `dplyr`. It also covers how to sort and combine data frames.
@@ -100,7 +104,7 @@ View(chicago_air)
```
-
+
By inspecting the data frame this way, you can see that the records are daily values of ozone, temperature, and air pressure. For more information about the data set you can type a question mark in from the name of the data frame variable in the console.
diff --git a/inst/tutorials/4-Writing-Functions-Conditionals-and-Loops/lesson.Rmd b/inst/tutorials/4-Writing-Functions-Conditionals-and-Loops/lesson.Rmd
index b92dbe7..c0bd724 100644
--- a/inst/tutorials/4-Writing-Functions-Conditionals-and-Loops/lesson.Rmd
+++ b/inst/tutorials/4-Writing-Functions-Conditionals-and-Loops/lesson.Rmd
@@ -1,6 +1,9 @@
---
author: Fluent Data, LLC
date: '`r Sys.Date()`'
+tutorial:
+ id: training.r.intro.4
+ version: 1.0
description: |
This lesson teaches how to create custom R functions, use conditional statements to make decisions in your code, loop through data with for loops, and efficiently apply functions to data structures using the apply function.
title: 4 . Writing Functions, Conditionals, and Loops
@@ -17,6 +20,12 @@ runtime: shiny_prerendered
library(gradethis)
library(trainingRIntro)
library(shiny)
+ print_hello <- function() {
+
+ print("Hello")
+
+}
+
```
This lesson covers how to write your own R functions. It also explains how to automate
@@ -30,10 +39,10 @@ This lesson assumes you are familiar with the material in the previous lessons:
- Functions and Importing Data
- Subsetting, Sorting, and Combining Data Frames
-The data for these lessons is available from this package. It is assumed that this package is already installed and loaded into the R session. If you need to refer to the package, simply refer to it as "this package".
+The data for these lessons is available from this package or the `region5air` package.
-```{r ex-b0dd7d25d817, exercise = FALSE, exercise.eval = TRUE, exercise.cap = 'Load Data from This Package'}
+```{r ex-868d2c8c5b75, exercise = FALSE, exercise.eval = TRUE, exercise.cap = 'Load Data from the Package'}
# Assuming the package is already loaded
data(chicago_air)
@@ -63,7 +72,7 @@ We can write a simple function that prints something to the console. Here is a
function named `print_hello`.
-```{r ex-a3bc32a64175, exercise = TRUE, exercise.eval = TRUE, exercise.cap = 'Simple Function to Print Hello'}
+```{r ex-a3bc32a64175, exercise = TRUE, exercise.eval = TRUE, eval = TRUE, exercise.cap = 'Simple Function to Print Hello'}
print_hello <- function() {
print("Hello")
diff --git a/inst/tutorials/4-Writing-Functions-Conditionals-and-Loops/lesson.html b/inst/tutorials/4-Writing-Functions-Conditionals-and-Loops/lesson.html
new file mode 100644
index 0000000..6679b9b
--- /dev/null
+++ b/inst/tutorials/4-Writing-Functions-Conditionals-and-Loops/lesson.html
@@ -0,0 +1,1735 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4 . Writing Functions, Conditionals, and Loops
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Skip to Tutorial Content
+
+
+
+
+
+
+
+
+
This lesson covers how to write your own R functions. It also
+explains how to automate your code using if() and
+ifelse() functions, for loops, and the apply
+function.
+
print(options("tutorial.storage"))
+
## $tutorial.storage
+## NULL
+
+
Prerequisites
+
This lesson assumes you are familiar with the material in the
+previous lessons:
+
+
Functions and Importing Data
+
Subsetting, Sorting, and Combining Data Frames
+
+
The data for these lessons is available from this package or the
+region5air package.
+
# Assuming the package is already loaded
+
+data(chicago_air)
+
+
+
Writing Functions
+
As discussed in the second lesson on
+functions, R can execute a saved chunk of code by running the name
+of a function, like mean(). The name mean is
+saved like a variable name, but since the name refers to a function, the
+thing that’s saved is not a data object but lines of R code.
+
To save your own function, use this construction:
+
my_function_name <- function() {
+
+ # lines of R code
+
+}
+
We can write a simple function that prints something to the console.
+Here is a function named print_hello.
Most of the functions we have used in these lessons have had at least
+one argument inside of the parentheses. The print_hello()
+function did not have any arguments, so we could run it without putting
+anything inside (). We could modify the function to take an
+argument that pastes some text to the printed message.
+
Here we recreate the same function, but this time we add an argument
+text inside of the parentheses.
Now there are two lines of code inside of the curly braces. The first
+line uses the paste() function to concatenate two character
+values. The first value will always be “Hello”. The second value will be
+supplied by the user in the text argument.
+
+
print_hello(text = "everybody!")
+
+
+
+
+
Default Values
+
We can create a function with more than one argument, and set default
+values when needed. Suppose we would like to make a function that checks
+if a measurement is greater than a criteria pollutant standard. We could
+make a simple function that takes two arguments: one for the measurement
+value, and one for the standard value.
This function will simply return a TRUE or
+FALSE value, depending on whether the measurement is
+greater than the standard or not.
+
+
standard_violated(measurement = 84, standard = 70)
+
+
+
We could write a more specific function for checking a value against
+the ozone standard. For this function, we want to keep the
+standard parameter but make sure the default is
+70. It may be that we typically want to use this function
+to check against the current 8-hour ozone standard in parts per billion,
+but have the flexibility to use a different value.
+
To set a default value, we use = 70 when we create the
+function.
+
+
standard_violated <- function(measurement, standard = 70) {
+
+ measurement > standard
+
+}
+
+
+
Now, when we use the function, it is not necessary to set the
+standard argument.
+
+
standard_violated(measurement = 50)
+
+
+
+
+
Positional Arguments
+
One final note on functions in R. When a function is created, the
+order of the arguments are important. The user can supply values for the
+arguments in the order they appeared in the parentheses of the
+function( ){} call, without writing out the argument
+names.
+
For example, we can supply two numbers to the
+standard_violated() function that we created above, without
+writing out the measurement and standard
+arguments. When R executes the function, it will assign the numbers to
+the arguments based on the position in the parentheses.
+
Here we show that using two numbers in a different order will return
+different outputs.
+
+
standard_violated(60, 70)
+
+
+
+
standard_violated(70, 60)
+
+
+
+
+
if Functions
+
Writing custom functions is a good way to standardize some R code
+that can be reused on different data sets. It’s also helpful to write
+code that will execute different lines of code depending on different
+scenarios. The functions if() and ifelse()
+allow you to control what code is executed based on a logical
+condition.
+
The if() function takes the logical condition in the
+parentheses. The code that will run if the logical expression is
+TRUE is placed inside curly braces. Below is the outline
+(not actual R code).
+
if(<logical expression>) {
+
+ <code that will run if the logical expression is TRUE>
+
+}
+
The key word else can also be used with another set of
+curly braces to hold code that will only run if the logical expression
+returns FALSE.
+
if(<logical expression>) {
+
+ <code that will run if the logical expression is true>
+
+} else {
+
+ <code that will run if the logical expression is false>
+
+}
+
For example, if we wanted to print a message based on the value of
+ozone, we could use this construction:
Since the expression ozone > 0.065 resolves to
+TRUE, the code in the first set of curly braces is run. If
+we set the ozone variable to 0.06, then the
+logical expression will resolve to FALSE and the code in
+the second curly braces will run.
The ifelse() function is another way to use a logical
+condition that determines which output is returned. Here is the
+outline
+
ifelse(<test>, <yes>, <no>)
+
The test argument is the logical expression,
+yes is the value returned if the expression resolves to
+TRUE, and no is the value returned if the
+expression resolves to FALSE.
+
Here we accomplish the same task as the previous example. This time
+we use the ifelse() function to create a variable named
+message.
+
+
ozone_value <- 0.06
+
+message <- ifelse(ozone_value > 0.065, "Potential Health Effects", "All Good")
+
+print(message)
+
+
+
+
+
For loops
+
Like most programming languages, R has for and while loops. This
+tutorial will cover just for loops and move on to apply()
+functions, which are more commonly used in R.
+
For loops are used to repeat an operation a set number of times. Here
+is the basic outline:
+
for(i in sequence){
+
+ <code that will run a set number of times>
+
+}
+
The sequence parameter is typically a vector. The
+i parameter is a variable that will take on the values in
+the sequence vector. For instance, if sequence
+was the vector c(1, 2, 3) then the i variable
+will take on each of those values in turn.
+
This example simply prints the values of the vector as the for loop
+progresses.
+
+
for(i in c(1, 2, 3)) {
+
+ print(i)
+
+}
+
+
+
Typically when we use loops, we want to perform the same operation on
+different sets of data and save the results. To do this using the
+for() function in R, we need to create an empty vector (or
+list or data frame) and save the results during each iteration.
+
Here is an example data frame we will use. It represents a few values
+from three monitors.
In the code below, we create an empty vector called max_values. As
+the for() function loops through the vector c(1, 2, 3), the data frame
+columns are accessed using square brackets [ , i]. Each max value is
+saved to the max_values vector using square brackets [i].
Although the for loop is common in programming languages, it is not
+the most efficient way to apply a function to different sets of data in
+R. The most efficient way to do loops in R is with the
+apply() family of functions, including
+lapply(), tapply(), and mapply().
+This section will demonstrate how to use the apply()
+function.
+
The apply() function takes a data frame (or matrix) as
+the first argument. The second argument determines if each loop will
+apply to the rows (1) or columns (2). And the
+third argument is the function you want to apply to each row or column.
+Additional arguments can be used to pass on to the function being
+applied to each row or column.
+
The example below applies the max() function to the
+monitors data frame from the previous section.
The MARGIN argument is set to 2 because we are applying the max()
+function to the columns of the data frame. Also notice that we do not
+need to create an initial empty vector, as we did with the for()
+function. The returned value is a named vector that is as long as the
+number of columns in the data frame.
+
We could also find the mean of each row in the monitors
+data frame. To do this, we would set the MARGIN argument to
+1.
+
+
apply(monitors, MARGIN = 1, FUN = mean)
+
+
+
+
+
Exercises
+
+
Exercise 1
+
Write a function named ppm_to_ppb that converts a value
+from parts per million to parts per billion.
+
+
# Your code here
+
+
+
+
# Define the function `ppm_to_ppb` with one argument for the value you want to convert.
+
+
+
# Inside the function, multiply the input value by 1000 to convert it to parts per billion.
+
+
+
# Return the converted value.
+
+
+
ppm_to_ppb <- function(value) {
+ value * 1000
+}
+
+
+
+
Exercise 2
+
Write a function named check_value that prints “warning”
+if a value is above a threshold, and “OK” if it’s below. Make the
+threshold an argument in the function.
+
+
# Your code here
+
+
+
+
# Define the function `check_value` with two arguments: `value` and `threshold`.
+
+
+
# Use an `if` statement to check if `value` is greater than `threshold`.
+
+
+
# Print "warning" if the value is above the threshold, otherwise print "OK".
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/inst/tutorials/5-Plotting/lesson.Rmd b/inst/tutorials/5-Plotting/lesson.Rmd
index 0ac6952..504a23e 100644
--- a/inst/tutorials/5-Plotting/lesson.Rmd
+++ b/inst/tutorials/5-Plotting/lesson.Rmd
@@ -1,6 +1,9 @@
---
author: Fluent Data, LLC
date: '`r Sys.Date()`'
+tutorial:
+ id: training.r.intro.5
+ version: 1.0
description: |
This lesson introduces the basics of plotting in R using base plot functions and the ggplot2 package, covering how to visualize data with scatter plots, line graphs, histograms, and box plots, including facets and fitted lines.
title: 5 . Plotting in R
@@ -17,6 +20,7 @@ runtime: shiny_prerendered
library(gradethis)
library(trainingRIntro)
library(shiny)
+
```
In this lesson you will first learn how to quickly visualize data using a few base
@@ -337,7 +341,7 @@ Plots can be saved in RStudio using the "Export" button at the top of the "Plots
pane.
-
+
You can also save a plot made by `ggplot2` using the `ggsave()` function.
diff --git a/inst/tutorials/6-Basic-Statistics/lesson.Rmd b/inst/tutorials/6-Basic-Statistics/lesson.Rmd
index d48ec5b..e83048d 100644
--- a/inst/tutorials/6-Basic-Statistics/lesson.Rmd
+++ b/inst/tutorials/6-Basic-Statistics/lesson.Rmd
@@ -1,6 +1,9 @@
---
author: Fluent Data, LLC
date: '`r Sys.Date()`'
+tutorial:
+ id: training.r.intro.6
+ version: 1.0
description: |
This lesson introduces basic statistical analysis in R, covering descriptive statistics, measures of central tendency and dispersion, statistical tests like the t-test and Shapiro-Wilk test for normality, correlation analysis with the cor() and cor.test() functions, and visualization of relationships between variables using pairwise plots.
title: 6 . Basic Statistics
@@ -17,6 +20,7 @@ runtime: shiny_prerendered
library(gradethis)
library(trainingRIntro)
library(shiny)
+
```
@@ -223,7 +227,7 @@ Below is a reference table of a few popular tests for categorical data analysis
| test | function |
-| --- | --- |
+| :--- | :--- |
| Chi Square Test | `chisq.test()` |
| Fisher's Test | `fisher.test()` |
| Analysis of Variance | `aov()` |
diff --git a/inst/tutorials/7-Quality-Assurance/lesson.Rmd b/inst/tutorials/7-Quality-Assurance/lesson.Rmd
index 6c7e136..ab697b8 100644
--- a/inst/tutorials/7-Quality-Assurance/lesson.Rmd
+++ b/inst/tutorials/7-Quality-Assurance/lesson.Rmd
@@ -1,6 +1,9 @@
---
author: Fluent Data, LLC
date: '`r Sys.Date()`'
+tutorial:
+ id: training.r.intro.7
+ version: 1.0
description: |
This lesson covers quality assurance for data in R, focusing on ensuring the integrity and consistency of data types, managing unallowed values, and handling outliers. It also points out common mistakes and how to address them, emphasizing the importance of accurately understanding and manipulating data to ensure reliable analysis outcomes.
title: 7 . Quality Assurance and Common Pitfalls
@@ -17,6 +20,7 @@ runtime: shiny_prerendered
library(gradethis)
library(trainingRIntro)
library(shiny)
+
```
Quality assurance (QA) in R could refer to at least two things: the quality of the code, or the quality of the data. Advanced R users that develop their own functions should follow general best practices for software development. The package [testthat](https://testthat.r-lib.org/) is useful to ensure that functions are working the way they are intended to work. However, this lesson focuses on _data_ quality, and points out a few common mistakes when using R.
diff --git a/source/1-Introduction/lesson1.yaml b/source/1-Introduction/lesson1.yaml
index d1d0716..d675401 100644
--- a/source/1-Introduction/lesson1.yaml
+++ b/source/1-Introduction/lesson1.yaml
@@ -545,6 +545,31 @@ exercises:
In R, we can combine vectors of equal length into a data frame using the `data.frame()` function. Here, we're creating two vectors, `name` and `age`, and combining them into a data frame, demonstrating how to organize and structure data in a tabular format.
code: |
df <- data.frame(name = c('Alice', 'Bob', 'Charlie'), age = c(25, 32, 28))
+ check: |
+ grade_this({
+ # The student's solution
+ df_student <- .result
+
+ # Expected names
+ expected_names <- c('Alice', 'Bob', 'Charlie')
+
+ # Check that the data frame has the correct structure
+ has_correct_columns <- all(names(df_student) == c('name', 'age'))
+ contains_all_names <- all(expected_names %in% df_student$name)
+ are_ages_numeric <- is.numeric(df_student$age)
+
+ # Provide detailed feedback based on specific issues
+ if (!has_correct_columns) {
+ fail("Incorrect columns. Ensure your data frame has exactly two columns named `name` and `age`.")
+ } else if (!contains_all_names) {
+ missing_names <- setdiff(expected_names, df_student$name)
+ fail(paste("Missing the following names:", paste(missing_names, collapse = ", ")))
+ } else if (!are_ages_numeric) {
+ fail("The `age` column should contain numeric values only. Ensure all ages are numbers.")
+ } else {
+ pass("Correct! You've successfully created a data frame with the names 'Alice', 'Bob', and 'Charlie', and ensured that ages are numeric.")
+ }
+ })
- instructions: "Create a numeric vector `nums` with the values 10, 20, and 30 and add 5 to each element of the vector."
hints:
- "# You can create a vector using the `c()` function."
diff --git a/source/2-Functions-and-Importing-Data/lesson2.yaml b/source/2-Functions-and-Importing-Data/lesson2.yaml
index 4e5f6fb..0cb6bde 100644
--- a/source/2-Functions-and-Importing-Data/lesson2.yaml
+++ b/source/2-Functions-and-Importing-Data/lesson2.yaml
@@ -3,6 +3,9 @@ title: "Functions and Importing Data"
metadata:
author: Fluent Data, LLC
date: "`r Sys.Date()`"
+ tutorial:
+ id: "training.r.intro.2"
+ version: 1.0
description: |
This lesson provides an overview of using functions in R, including built-in and package functions, and demonstrates how to import data
from CSV and Excel files.
@@ -13,8 +16,6 @@ lesson:
closing: |
Well done on mastering Functions and Importing Data! You've expanded your toolkit with new R functions and data import techniques. In the next lesson, Subsetting, Sorting, and Combining Data Frames, you'll explore advanced data manipulation strategies to refine and optimize your data analysis workflows.
-packages:
- - EnvStats
introduction: |
This lesson covers the use of functions in R, including built-in functions and functions from packages. It also discusses how to import
data from CSV text files and Excel documents.
@@ -489,9 +490,18 @@ content:
- type: code
language: r
options:
- exercise: true
- exercise.eval: false
- exercise.lines: 5
+ exercise: false
+ eval: false
+ exercise.cap: "Read and Inspect Excel Data"
+ content: |
+ library(readxl)
+ emissions <- read_excel("emissions_IL_2022.xlsx", sheet = "UNIT_DATA", skip = 6)
+ head(emissions)
+ - type: code
+ language: r
+ options:
+ echo: false
+ eval: true
exercise.cap: "Read and Inspect Excel Data"
content: |
library(readxl)
diff --git a/source/3-Subsetting-Sorting-and-Combining/lesson3.yaml b/source/3-Subsetting-Sorting-and-Combining/lesson3.yaml
index 100b977..9ccf642 100644
--- a/source/3-Subsetting-Sorting-and-Combining/lesson3.yaml
+++ b/source/3-Subsetting-Sorting-and-Combining/lesson3.yaml
@@ -2,6 +2,9 @@ title: "Subsetting, Sorting, and Combining Data Frames"
metadata:
author: Fluent Data, LLC
date: "`r Sys.Date()`"
+ tutorial:
+ id: "training.r.intro.3"
+ version: 1.0
description: |
This lesson provides an overview of subsetting, sorting, and combining data frames in R using indexing, logical operations, the filter() function from dplyr, as well as sorting with arrange() and combining data frames with bind_rows().
lesson:
diff --git a/source/4-Writing-Functions-Conditionals-and-Loops/lesson4.yaml b/source/4-Writing-Functions-Conditionals-and-Loops/lesson4.yaml
index 35426a0..131eeee 100644
--- a/source/4-Writing-Functions-Conditionals-and-Loops/lesson4.yaml
+++ b/source/4-Writing-Functions-Conditionals-and-Loops/lesson4.yaml
@@ -2,6 +2,9 @@ title: "Writing Functions, Conditionals, and Loops"
metadata:
author: Fluent Data, LLC
date: "`r Sys.Date()`"
+ tutorial:
+ id: "training.r.intro.4"
+ version: 1.0
description: |
This lesson teaches how to create custom R functions, use conditional statements to make decisions in your code, loop through data with for loops, and efficiently apply functions to data structures using the apply function.
lesson:
@@ -10,7 +13,12 @@ lesson:
next: 5-Plotting
closing: |
Well done on completing Writing Functions, Conditionals, and Loops! You've developed the skills to customize your analysis and automate tasks in R. Next, you'll move on to Plotting in R, where you'll learn how to visually represent data using various plotting techniques. Get ready to bring your data to life with engaging visuals!
+setup: |
+ print_hello <- function() {
+ print("Hello")
+
+ }
introduction: |
This lesson covers how to write your own R functions. It also explains how to automate
your code using `if()` and `ifelse()` functions, for loops, and the `apply`
@@ -26,13 +34,13 @@ content:
- Functions and Importing Data
- Subsetting, Sorting, and Combining Data Frames
- The data for these lessons is available from this package. It is assumed that this package is already installed and loaded into the R session. If you need to refer to the package, simply refer to it as "this package".
+ The data for these lessons is available from this package or the `region5air` package.
- type: code
language: r
options:
exercise: false
exercise.eval: true
- exercise.cap: "Load Data from This Package"
+ exercise.cap: "Load Data from the Package"
content: |
# Assuming the package is already loaded
@@ -69,6 +77,7 @@ content:
options:
exercise: true
exercise.eval: true
+ eval: true
exercise.cap: "Simple Function to Print Hello"
content: |
print_hello <- function() {
diff --git a/source/5-Plotting/lesson5.yaml b/source/5-Plotting/lesson5.yaml
index 750f68a..c963373 100644
--- a/source/5-Plotting/lesson5.yaml
+++ b/source/5-Plotting/lesson5.yaml
@@ -2,6 +2,9 @@ title: "Plotting in R"
metadata:
author: Fluent Data, LLC
date: "`r Sys.Date()`"
+ tutorial:
+ id: "training.r.intro.5"
+ version: 1.0
description: |
This lesson introduces the basics of plotting in R using base plot functions and the ggplot2 package, covering how to visualize data with scatter plots, line graphs, histograms, and box plots, including facets and fitted lines.
lesson:
diff --git a/source/6-Basic-Statistics/lesson6.yaml b/source/6-Basic-Statistics/lesson6.yaml
index 8bf6563..a297aff 100644
--- a/source/6-Basic-Statistics/lesson6.yaml
+++ b/source/6-Basic-Statistics/lesson6.yaml
@@ -2,6 +2,9 @@ title: "Basic Statistics"
metadata:
author: Fluent Data, LLC
date: "`r Sys.Date()`"
+ tutorial:
+ id: "training.r.intro.6"
+ version: 1.0
description: |
This lesson introduces basic statistical analysis in R, covering descriptive statistics, measures of central tendency and dispersion, statistical tests like the t-test and Shapiro-Wilk test for normality, correlation analysis with the cor() and cor.test() functions, and visualization of relationships between variables using pairwise plots.
lesson:
diff --git a/source/7-Quality-Assurance/lesson7.yaml b/source/7-Quality-Assurance/lesson7.yaml
index 134cdd5..8daa623 100644
--- a/source/7-Quality-Assurance/lesson7.yaml
+++ b/source/7-Quality-Assurance/lesson7.yaml
@@ -2,6 +2,9 @@ title: "Quality Assurance and Common Pitfalls"
metadata:
author: Fluent Data, LLC
date: "`r Sys.Date()`"
+ tutorial:
+ id: "training.r.intro.7"
+ version: 1.0
description: |
This lesson covers quality assurance for data in R, focusing on ensuring the integrity and consistency of data types, managing unallowed values, and handling outliers. It also points out common mistakes and how to address them, emphasizing the importance of accurately understanding and manipulating data to ensure reliable analysis outcomes.
lesson: