diff --git a/.gitignore b/.gitignore
index 05c2f8e..358b132 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,7 @@ docs/
!docs/*.md
*.dcf
*.html
+*.png
# renv - using DESCRIPTION for dependencies instead
renv/
@@ -20,4 +21,6 @@ rsconnect/
venv/
-legacy/
\ No newline at end of file
+legacy/
+
+CLAUDE.md
\ No newline at end of file
diff --git a/DESCRIPTION b/DESCRIPTION
index b92e383..f5046d8 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -12,6 +12,7 @@ URL: https://github.com/ds4owd-dev/quiz,
https://ds4owd-dev.github.io/quiz/
BugReports: https://github.com/ds4owd-dev/quiz/issues
Imports:
+ remotes,
learnr,
dplyr,
gapminder,
@@ -24,9 +25,18 @@ Imports:
shiny,
bslib,
rsconnect,
- yaml
+ yaml,
+ countrycode,
+ ggplot2,
+ here,
+ palmerpenguins,
+ readr,
+ rnaturalearth,
+ rnaturalearthdata,
+ sf
Suggests:
pkgdown
Remotes:
rstudio/gradethis,
- rundel/learnrhash
+ rundel/learnrhash,
+ ropensci/rnaturalearthdata
diff --git a/README.md b/README.md
index 79af800..b70fdaf 100644
--- a/README.md
+++ b/README.md
@@ -2,19 +2,23 @@
This directory contains interactive learnr quizzes for the openwashdata course and a landing page to access them.
-**Live Demo**: https://hjj91u-nicolo-massari.shinyapps.io/openwashdata-quiz-hub/
+**Live Demo**: https://u4x6xe-lars-sch0bitz.shinyapps.io/ds4owd-002-quiz/
## Structure
- `app.R` - Quiz landing page that automatically displays all configured quizzes
- `build.R` - Deployment script with helper functions for automated deployment
- `config.R` - Shared configuration file defining all available quizzes
-- `modules/` - Directory containing all quiz files
- - `md-01-quiz.Rmd` - Module 1 quiz on Quarto basics (learnr tutorial)
- - `_github_username.Rmd` - Reusable component for GitHub username input with CSV data
- - `_submission.Rmd` - Reusable component for quiz submission
- - `github_usernames.csv` - Student GitHub username database
- - Additional quiz files can be added as `md-XX-quiz.Rmd`
+- `modules/` - Directory containing individual quiz directories
+ - `md-01-quiz/` - Module 1 quiz directory with all required files
+ - `md-02-quiz/` - Module 2 quiz directory with all required files
+ - Each quiz directory contains:
+ - `md-XX-quiz.Rmd` - Main quiz file (learnr tutorial)
+ - `_github_username.Rmd` - Reusable component for GitHub username input
+ - `_participation.Rmd` - Reusable component for participation tracking
+ - `_submission.Rmd` - Reusable component for quiz submission
+ - `github_usernames.csv` - Student GitHub username database
+ - `data/` - Quiz-specific data files (if needed)
## Required Packages
@@ -145,25 +149,35 @@ source("build.R")
```
The deployment system features:
-- **Automatic file bundling**: CSV files and dependencies are automatically included
+- **Direct module deployment**: Deploys directly from module directories (no temp files)
+- **Self-contained modules**: Each quiz directory contains all required files
- **Streamlined process**: One script deploys everything configured in `config.R`
## Adding New Quizzes
-The system now uses automatic configuration - adding a new quiz is simple:
+The system uses a modular directory structure - adding a new quiz requires creating a complete directory:
-### 1. Create the Quiz File
+### 1. Create the Quiz Directory
-Create `modules/md-02-quiz.Rmd` with the standardized YAML header:
+Create a new directory `modules/md-XX-quiz/` and add all required files:
+
+```bash
+mkdir modules/md-03-quiz
+cp modules/md-01-quiz/_*.Rmd modules/md-01-quiz/github_usernames.csv modules/md-03-quiz/
+```
+
+### 2. Create the Quiz File
+
+Create `modules/md-XX-quiz/md-XX-quiz.Rmd` with the standardized YAML header:
```yaml
---
-title: "Module 2: Your Title"
+title: "Module 3: Your Title"
output: learnr::tutorial
runtime: shiny_prerendered
description: "Your quiz description"
tutorial:
- id: "module2-your-id"
+ id: "md-03-quiz"
---
```
@@ -171,18 +185,19 @@ Add your quiz content following the existing pattern, including:
- GitHub username collection: `{r github-username, child='_github_username.Rmd'}`
- Quiz submission: `{r submission-section, child='_submission.Rmd'}`
-### 2. Update Configuration
+### 3. Update Configuration
Edit `config.R` to include your new quiz:
```r
quiz_names <- c(
"md-01-quiz",
- "md-02-quiz" # Add new quiz here
+ "md-02-quiz",
+ "md-03-quiz" # Add new quiz here
)
```
-### 3. Deploy
+### 4. Deploy
Run the build script to deploy everything:
@@ -200,7 +215,8 @@ This will:
```r
# Test a quiz locally
-rmarkdown::run("modules/md-01-quiz.Rmd")
+setwd("modules/md-01-quiz")
+rmarkdown::run("md-01-quiz.Rmd")
```
### Test Landing Page
diff --git a/app.R b/app.R
index 5557542..0d10337 100644
--- a/app.R
+++ b/app.R
@@ -9,7 +9,7 @@ source("config.R")
# Function to extract quiz metadata from Rmd files
extract_quiz_metadata <- function(quiz_name) {
- rmd_path <- file.path("modules", paste0(quiz_name, ".Rmd"))
+ rmd_path <- file.path("modules", quiz_name, paste0(quiz_name, ".Rmd"))
if (!file.exists(rmd_path)) {
return(NULL)
@@ -60,7 +60,7 @@ quizzes <- generate_quiz_list(quiz_names)
# UI
ui <- page_navbar(
- title = "openwashdata Quizzes",
+ title = "ds4owd-002 quiz",
theme = bs_theme(bootswatch = "cosmo"),
nav_panel(
@@ -69,8 +69,9 @@ ui <- page_navbar(
class = "container mt-5",
div(
class = "text-center mb-5",
- h1("openwashdata Course Quizzes"),
- p(class = "lead", "Interactive tutorials to test your knowledge")
+ h1("data science for openwashdata - quiz"),
+ p(class = "lead", "Interactive tutorials to test your knowledge."),
+ p(class = "lead text-warning fw-bold", "For successful completion of the course, you need to complete the quizzes for each module."),
),
div(
@@ -118,7 +119,7 @@ ui <- page_navbar(
div(
class = "col-md-8",
h2("About These Quizzes"),
- p("These interactive quizzes are designed to help you learn and practice concepts from the openwashdata course."),
+ p("These interactive quizzes are designed to help you learn and practice concepts from the ds4owd course. They are required to be completed for each module of the course."),
h3("Features"),
tags$ul(
@@ -126,7 +127,7 @@ ui <- page_navbar(
tags$li("Immediate feedback on your answers"),
tags$li("Hints and solutions available"),
tags$li("Progress tracking within each quiz"),
- tags$li("Automatic grading with gradethis")
+ tags$li("Automatic grading")
),
h3("How to Use"),
@@ -136,7 +137,8 @@ ui <- page_navbar(
tags$li("Work through the questions at your own pace"),
tags$li("Run code in the interactive exercises"),
tags$li("Use hints if you get stuck"),
- tags$li("Check your solutions for immediate feedback")
+ tags$li("Check your solutions for immediate feedback"),
+ tags$li("Ensure to submit the Quiz with your GitHub username")
),
h3("Technical Requirements"),
diff --git a/build.R b/build.R
index 97df4b8..cbd222c 100644
--- a/build.R
+++ b/build.R
@@ -4,13 +4,22 @@ source("config.R")
# HELPER
deploy_quiz <- function(module_name) {
- module_path <- paste0(file.path("modules", module_name), ".Rmd")
+ # Deploy directly from module directory - no temp directories!
+ module_dir <- file.path("modules", module_name)
+ rmd_file <- file.path(module_dir, paste0(module_name, ".Rmd"))
+
+ if (!file.exists(rmd_file)) {
+ stop("Quiz file not found: ", rmd_file)
+ }
+
+ # Deploy directly from module directory
rsconnect::deployDoc(
- doc = module_path,
+ doc = rmd_file,
appName = module_name,
forceUpdate = TRUE,
logLevel = "verbose"
)
+ rsconnect::showLogs()
}
diff --git a/config.R b/config.R
index 73d1dff..122f86d 100644
--- a/config.R
+++ b/config.R
@@ -3,17 +3,17 @@
# List of quiz modules to deploy and display
quiz_names <- c(
- "md-01-quiz"
+ "md-01-quiz",
+ "md-02-quiz"
# Add new quizzes here:
- # "md-02-quiz",
# "md-03-quiz"
)
# Base URL for deployed quizzes
-base_url <- "https://hjj91u-nicolo-massari.shinyapps.io/"
+base_url <- "https://u4x6xe-lars-sch0bitz.shinyapps.io/"
# Main app configuration
-main_app_name <- "openwashdata-quiz-hub"
+main_app_name <- "ds4owd-002-quiz"
# in modules/_submission.Rmd
#
diff --git a/modules/_participation.Rmd b/modules/_participation.Rmd
deleted file mode 100644
index e43c787..0000000
--- a/modules/_participation.Rmd
+++ /dev/null
@@ -1,9 +0,0 @@
-```{r participation-question, echo=FALSE}
-question("Have you participated in the live module or did you watch the recording?",
- answer("Live module", correct = TRUE),
- answer("Recording", correct = TRUE),
- answer("Neither", correct = TRUE),
- allow_retry = TRUE,
- random_answer_order = FALSE
-)
-```
\ No newline at end of file
diff --git a/modules/github_usernames.csv b/modules/github_usernames.csv
deleted file mode 100644
index ca90856..0000000
--- a/modules/github_usernames.csv
+++ /dev/null
@@ -1,9 +0,0 @@
-First Name,Last Name,Email,Registration Time,Approval Status,GitHub Username
-Rainbow,Train,larnsce@gmail.com,08/28/2025 1:36:03 PM,approved,rainbow-train
-John,Doe,john.doe@email.com,08/25/2025 9:15:22 AM,approved,johndoe
-Jane,Smith,jane.smith@email.com,08/26/2025 2:30:45 PM,approved,janesmith
-Alice,Johnson,alice.j@email.com,08/27/2025 11:20:10 AM,approved,alice-johnson
-Bob,Wilson,bob.wilson@email.com,08/27/2025 3:45:33 PM,approved,bobwilson
-Carol,Brown,carol.brown@email.com,08/28/2025 8:12:15 AM,approved,carol-brown
-David,Miller,d.miller@email.com,08/28/2025 10:25:40 AM,approved,davidmiller
-Emily,Davis,emily.davis@email.com,08/28/2025 4:18:22 PM,approved,emily-davis
\ No newline at end of file
diff --git a/modules/md-01-quiz.Rmd b/modules/md-01-quiz.Rmd
deleted file mode 100644
index 3fb4e26..0000000
--- a/modules/md-01-quiz.Rmd
+++ /dev/null
@@ -1,229 +0,0 @@
----
-title: "Module 1: Quarto Basics"
-output: learnr::tutorial
-runtime: shiny_prerendered
-description: "Test your understanding of Quarto basics for openwashdata package documentation"
-resource_files:
- - github_usernames.csv
- - _github_username.Rmd
- - _participation.Rmd
- - _submission.Rmd
-tutorial:
- id: "module1-quarto-basics"
----
-
-```{r setup, include=FALSE}
-library(learnr)
-library(dplyr)
-library(gapminder)
-library(knitr)
-library(gradethis)
-library(learnrhash)
-library(httr)
-
-# Enable exercise checking
-tutorial_options(
- exercise.eval = FALSE,
- exercise.checker = gradethis::grade_learnr
-)
-
-knitr::opts_chunk$set(echo = FALSE)
-
-```
-
-## Introduction
-
-This quiz tests your understanding of Quarto basics for openwashdata package documentation. The quiz covers YAML headers, code chunks, and data analysis integration.
-
-**Important**: Please enter your GitHub username below and click "Submit Quiz" at the end to record your completion.
-
-```{r github-username, child='_github_username.Rmd'}
-```
-
-```{r participation, child='_participation.Rmd'}
-```
-
-## Section 1: Quarto Fundamentals
-
-### Question 1: YAML Header
-
-```{r yaml-question}
-question("Which of the following is the correct YAML header for an openwashdata package README?",
- answer("`---`\n`output: html_document`\n`---`"),
- answer("`---`\n`output: github_document`\n`---`", correct = TRUE),
- answer("`---`\n`format: html`\n`---`"),
- answer("`---`\n`format: markdown`\n`---`"),
- allow_retry = TRUE,
- incorrect = "Think about what output format is typically used for GitHub README files.",
- correct = "Correct! The github_document output format is used for README files that will be displayed on GitHub."
-)
-```
-
-### Question 2: pkgdown Configuration
-
-```{r pkgdown-question}
-question("What file is used to configure the pkgdown website for an openwashdata package?",
- answer("pkgdown.yml"),
- answer("_pkgdown.yml", correct = TRUE),
- answer("config.yml"),
- answer("_config.yml"),
- allow_retry = TRUE,
- incorrect = "The configuration file starts with an underscore and has a .yml extension.",
- correct = "Correct! The _pkgdown.yml file is used to configure pkgdown websites."
-)
-```
-
-## Section 2: Code Chunks and Options
-
-### Question 3: Code Chunk Options
-
-```{r chunk-options-question}
-question("Which chunk options would you use to hide both code and messages when loading tidyverse?",
- answer("`echo = TRUE, message = TRUE`"),
- answer("`echo = FALSE, message = FALSE`", correct = TRUE),
- answer("`include = TRUE`"),
- answer("`eval = FALSE`"),
- allow_retry = TRUE,
- incorrect = "In Quarto, you can use `#| echo: false` and `#| message: false` to hide code and messages.",
- correct = "Correct! Setting echo = FALSE hides the code and message = FALSE hides the messages."
-)
-```
-
-### Question 4: Creating Tables
-
-Use the gapminder dataset to create a summary table showing the average life expectancy by continent in 2007:
-
-```{r create-table-setup}
-library(dplyr)
-library(gapminder)
-library(knitr)
-```
-
-```{r create-table, exercise=TRUE, exercise.lines=10}
-# Create a summary table of average life expectancy by continent for 2007
-# Your code here
-```
-
-```{r create-table-hint-1}
-# Start by filtering for year 2007
-gapminder %>%
- filter(year == 2007)
-```
-
-```{r create-table-hint-2}
-# Then group by continent and calculate mean
-gapminder %>%
- filter(year == 2007) %>%
- group_by(continent) %>%
- summarise(avg_life_exp = mean(lifeExp))
-```
-
-```{r create-table-solution}
-gapminder %>%
- filter(year == 2007) %>%
- group_by(continent) %>%
- summarise(avg_life_exp = mean(lifeExp)) %>%
- knitr::kable(digits = 1)
-```
-
-```{r create-table-check}
-grade_this_code()
-```
-
-## Section 3: Data Analysis Integration
-
-### Question 5: Inline Code
-
-Calculate the mean GDP per capita for Switzerland in 2007:
-
-```{r inline-code-setup}
-library(dplyr)
-library(gapminder)
-```
-
-```{r inline-code, exercise=TRUE, exercise.lines=10}
-# Calculate Switzerland's GDP per capita in 2007
-swiss_gdp_2007 <- gapminder %>%
- filter(country == "Switzerland", year == 2007) %>%
- pull(gdpPercap)
-
-# Display the result
-paste("Switzerland's GDP per capita in 2007 was $",
- format(swiss_gdp_2007, big.mark = ","), sep = "")
-```
-
-```{r inline-code-solution}
-swiss_gdp_2007 <- gapminder %>%
- filter(country == "Switzerland", year == 2007) %>%
- pull(gdpPercap)
-
-paste("Switzerland's GDP per capita in 2007 was $",
- format(swiss_gdp_2007, big.mark = ","), sep = "")
-```
-
-```{r inline-code-check}
-grade_this_code()
-```
-
-### Question 6: Data Visualization
-
-Create a line plot showing the life expectancy over time for African countries with a population greater than 30 million in 2007:
-
-```{r visualization-setup}
-library(dplyr)
-library(gapminder)
-
-# Identify African countries with population > 30 million in 2007
-large_african_countries <- gapminder %>%
- filter(continent == "Africa", year == 2007, pop > 30000000) %>%
- pull(country)
-```
-
-```{r visualization, exercise=TRUE, exercise.lines=15}
-# Create the plot
-# Your code here
-```
-
-```{r visualization-hint-1}
-# Start by filtering for the large African countries
-gapminder %>%
- filter(country %in% large_african_countries)
-```
-
-```{r visualization-hint-2}
-# Then create a ggplot with appropriate aesthetics
-gapminder %>%
- filter(country %in% large_african_countries) %>%
- ggplot(aes(x = year, y = lifeExp, color = country))
-```
-
-```{r visualization-solution}
-gapminder %>%
- filter(country %in% large_african_countries) %>%
- ggplot(aes(x = year, y = lifeExp, color = country)) +
- geom_line() +
- labs(title = "Life Expectancy Over Time",
- subtitle = "African countries with population > 30 million in 2007",
- x = "Year",
- y = "Life Expectancy (years)",
- color = "Country") +
- theme_minimal()
-```
-
-```{r visualization-check}
-grade_this_code()
-```
-
-```{r submission-section, child='_submission.Rmd'}
-```
-
-## Summary
-
-This quiz covered essential Quarto skills for openwashdata package documentation:
-
-1. **YAML Headers**: Configuring document output formats
-2. **Code Chunks**: Managing code execution and output display
-3. **Data Integration**: Combining narrative text with R analysis
-4. **Visualization**: Creating informative plots within documents
-
-Remember that Quarto documents can be rendered to multiple formats, making them ideal for creating both package documentation and interactive tutorials like this one!
\ No newline at end of file
diff --git a/modules/_github_username.Rmd b/modules/md-01-quiz/_github_username.Rmd
similarity index 89%
rename from modules/_github_username.Rmd
rename to modules/md-01-quiz/_github_username.Rmd
index ace5310..b0d4f2e 100644
--- a/modules/_github_username.Rmd
+++ b/modules/md-01-quiz/_github_username.Rmd
@@ -7,10 +7,10 @@ tryCatch({
csv_path <- "modules/github_usernames.csv"
}
github_users <- read.csv(csv_path, stringsAsFactors = FALSE)
- # Create choices with display format: "First Last (username)"
+ # Create choices with display format: "First Name (username)"
username_choices <- setNames(
- github_users$GitHub.Username,
- paste0(github_users$First.Name, " ", github_users$Last.Name, " (", github_users$GitHub.Username, ")")
+ github_users$github_username,
+ paste0(github_users$first_name, " (", github_users$github_username, ")")
)
}, error = function(e) {
# Fallback if CSV not found
@@ -51,10 +51,10 @@ username_choices <- reactive({
csv_path <- "modules/github_usernames.csv"
}
github_users <- read.csv(csv_path, stringsAsFactors = FALSE)
- # Create choices with display format: "First Last (username)"
+ # Create choices with display format: "First Name (username)"
setNames(
- github_users$GitHub.Username,
- paste0(github_users$First.Name, " ", github_users$Last.Name, " (", github_users$GitHub.Username, ")")
+ github_users$github_username,
+ paste0(github_users$first_name, " (", github_users$github_username, ")")
)
}, error = function(e) {
# Fallback if CSV not found
diff --git a/modules/md-01-quiz/_participation.Rmd b/modules/md-01-quiz/_participation.Rmd
new file mode 100644
index 0000000..0623325
--- /dev/null
+++ b/modules/md-01-quiz/_participation.Rmd
@@ -0,0 +1,10 @@
+```{r participation-question, echo=FALSE}
+question("Have you participated in the live module, did you watch the recording, or are you only completing the quiz?",
+ answer("Live module", correct = TRUE),
+ answer("Recording", correct = TRUE),
+ answer("Both, live & recording", correct = TRUE),
+ answer("Neither", correct = TRUE),
+ random_answer_order = FALSE,
+ type = "single"
+)
+```
\ No newline at end of file
diff --git a/modules/_submission.Rmd b/modules/md-01-quiz/_submission.Rmd
similarity index 100%
rename from modules/_submission.Rmd
rename to modules/md-01-quiz/_submission.Rmd
diff --git a/modules/md-01-quiz/github_usernames.csv b/modules/md-01-quiz/github_usernames.csv
new file mode 100644
index 0000000..a38fa9b
--- /dev/null
+++ b/modules/md-01-quiz/github_usernames.csv
@@ -0,0 +1,146 @@
+github_username,first_name
+massarin,Nicolo
+rainbow-train,Rainbow
+kpeckeref,Kaitlin
+jmfoss03,Jeffrey
+dspalthoff,Daniel
+madalitsokanache,Madalitso
+tesssadurham,Tessa
+ambuehlb,benjamin
+getenehmoges,Geteneh
+dkabanyana-cyber,Diane
+aditya-khedkar,Aditya
+faraharbi,Farah
+gaduku,Godwin
+mejbahce1991,Mejbah Uddin
+djamphie,Kwasi
+emmanuellmhango,emmanuel
+soziee,Masozi
+severin-ek,Sévérin
+fundilek,Fundile
+traviskunnen,Travis
+phumlileamanda,Phumlile
+ellentafm,Ellen
+eugene-6203,Eugene
+stacianordin,Stacia
+collo2004,Collins
+dapeguero,Daniela
+melita235,Melita Nathania
+clwanga183,Isaac
+yozgoesdigital,Jos
+iggonz,Iggo
+aditiowthar,Aditi
+elizabeth-tilley,Elizabeth
+bwana3010,Jackline
+barbygk,Barbara
+alazarnegash-horecha,Alazar
+mushana-stack,Mushana Joseph
+hopechilunga,Hope
+quishqa,Mario
+prakash4272,Prakash
+beckeinstein,Benjamin
+bensi4,Waffo Benedicte
+fadilah-hub,Fadila
+almamykonte,Almamy
+kobina-afful,Kobina
+onyangomoriswanyama,Moris Wanyama
+oliverwale94,Oliver
+ksumona,Sumona
+seyrama,Seyram
+elishaokoth,Elisha
+matlove23,Matthews
+eacquah-arch,Ebenezer
+aravind-soman,Aravind
+kjrezek,Kyle
+ssiima,Syson
+shafsharif,Shafkat
+carleytru,Carley
+paul103-cloud,Paul
+montoyna,Natalia
+biyiemmy,Emmanuel
+joseph6348,Joseph Lee
+karezek,Kaitlyn
+foma4tune,foma
+crh00,Chris
+iamsilvia,Sílvia
+bettyghg,Betelhem Gebeyehu
+mesenbet-fentie,Mesenbet Fentie
+rafaellabaracho,Rafaella
+tshepi-sys,Tshephang
+munjame,Mundrugo
+chiwanzamunashe,Munashe
+frantisek-ficek,František
+andrema123-git,Mwansa Andrew
+ike76,Isaac
+berti83,Alberto
+andrealescano,Andrea
+rebecca-lk,Rebecca
+pascarini,Sri Pascarini
+adesijivictoria,Victoria
+collins1125,Collins
+sarah78016,Sarah
+rayprinz99,Ismail
+g-njoroge,George
+musabasha,Maibasha
+jngalamu,Julius
+dustingarrick,Dustin
+fnboadu,Frank
+miller-meghan,Meghan
+kosgey-001,kosgey
+wondibernega,Wondiber Nega
+0920458603,Abiel Teshome
+mosisabekele,Mosisa Bekele
+squiebble,Ranya
+michaelnacquah,Michael
+johnbrogan-alt,John
+salgadosebastian-glitch,Sebastian
+sgetahun,Samuel Tenaw
+hingamercy50-cmyk,Mercy
+laigarve,Laia
+bttgcm,Giacomo
+roh2o,Rocio
+tangqiqing,Qiqing
+prabhatjoshi007,Prabhat
+tmoneytmali,Thabiso
+asimenye99,Doreen
+imegit,Augustine
+kunzrp,Richard
+adgomezs,Adriana
+watnafu,Wondafrash Atnafu
+adheesh20,Adheesh
+stefanie123456,Stefanie
+hawahmugisha,Hawah
+gervaismomo42,Gervais
+ebeidomer-byte,Omer
+davismajara,Davis
+promise707-lab,Promise
+blessingrebecca26,Blessing
+big-gen,Nnaemeka
+mmasomoma,mmasom
+visionary210,Isaiah
+otoosakyidavid,David
+baadedotun,Adedotun
+clairegrand,Claire
+wisjay,Wisdom
+pjosephy,Taylor
+astute2011,Kabir
+harlod-max,Harlod
+irshadadi-luc,SHADADI
+snowty930,Sinoxolo
+assumpta-hub,Assumpta
+reahmq2018-oss,Reem
+willis-254,William
+mercyncube,Mercy
+fernando-pm,Fernando
+rewarda58,Reward
+yousefia601,Ali
+chekwube-web,Chekwubechukwu Victory
+qzahra08,Qazi Aniqua
+gloajugwo,GLORIA
+ocheaikpa,Ochea
+faizaaudri03,Faiza Tabassum Haque
+analystkemi,Blessing
+betadetective,Beta
+redd-om,Olivia
+mmumba266,Moses
+galacticasparagus,Galactica
diff --git a/modules/md-01-quiz/md-01-quiz.Rmd b/modules/md-01-quiz/md-01-quiz.Rmd
new file mode 100644
index 0000000..61392a6
--- /dev/null
+++ b/modules/md-01-quiz/md-01-quiz.Rmd
@@ -0,0 +1,131 @@
+---
+title: "Module 1: Getting Started"
+output: learnr::tutorial
+runtime: shiny_prerendered
+description: "Test your understanding of the concepts covered in Module 1"
+resource_files:
+ - github_usernames.csv
+ - _github_username.Rmd
+ - _participation.Rmd
+ - _submission.Rmd
+tutorial:
+ id: "md-01-quiz"
+---
+
+```{r setup, include=FALSE}
+library(learnr)
+library(dplyr)
+library(gapminder)
+library(knitr)
+library(gradethis)
+library(learnrhash)
+library(httr)
+
+# Enable exercise checking
+tutorial_options(
+ exercise.eval = FALSE,
+ exercise.checker = gradethis::grade_learnr
+)
+
+knitr::opts_chunk$set(echo = FALSE)
+
+```
+
+## Introduction
+
+This weekly quiz is designed to support your learning in the ds4owd course. It will test your understanding of the concepts covered in Module 1, including RStudio IDE, GitHub Personal Access Tokens (PATs), and basic R syntax. A submission of the quiz for each module is required to complete the course.
+
+## Multiple Choice Questions
+
+### Question 1: GitHub PAT Storage
+
+```{r q1}
+question_radio(
+ "Where should you store your GitHub Personal Access Token (PAT) for secure and convenient use when working in cloud environments like Posit Cloud?",
+ answer("In a text file on your desktop for easy access"),
+ answer("In your R script as a comment for reference"),
+ answer("In a secure password manager or credentials manager", correct = TRUE),
+ answer("In your browser's bookmarks for quick retrieval"),
+ incorrect = "GitHub PATs should be stored securely in a password manager or credentials manager to prevent unauthorized access. Since we'll be working in Posit Cloud, system credential managers aren't available, so external password managers are recommended.",
+ correct = "Correct! Storing PATs in a secure password manager or credentials manager provides security while allowing you to access them when needed in cloud environments where system credential stores aren't available.",
+ allow_retry = TRUE,
+ random_answer_order = TRUE
+)
+```
+
+### Question 2: RStudio IDE Panes
+
+```{r q2}
+question_checkbox(
+ "Which four panes make up the RStudio IDE? (Select all four)",
+ answer("Source Editor", correct = TRUE),
+ answer("Console", correct = TRUE),
+ answer("Environment/History/Git/Connections", correct = TRUE),
+ answer("Files/Plots/Packages/Help/Viewer", correct = TRUE),
+ answer("Terminal"),
+ answer("Debug"),
+ answer("Version Control"),
+ incorrect = "The RStudio IDE has four main panes. Try again and select exactly four options.",
+ correct = "Excellent! The four panes are: Source Editor (top-left), Console (bottom-left), Environment/History/Connections (top-right), and Files/Plots/Packages/Help/Viewer (bottom-right).",
+ allow_retry = TRUE
+)
+```
+
+### Question 3: R Assignment Operator
+
+```{r q5}
+question_radio(
+ "Which is the assignment operator in R?",
+ answer("="),
+ answer("<-", correct = TRUE),
+ answer("<<-"),
+ answer("->"),
+ incorrect = "The tidyverse style guide recommends using a specific assignment operator for clarity and consistency.",
+ correct = "Correct! The arrow operator '<-' is preferred in R for assignment, as it clearly shows the direction of assignment and avoids confusion with function arguments.",
+ allow_retry = TRUE,
+ random_answer_order = TRUE
+)
+```
+
+## Coding Exercises
+
+### Exercise 1: Modifying gapminder data
+
+The code below filters the gapminder dataset for the year 2007 and calculates the mean life expectancy by continent. Modify the code to filter for the year 1952 instead.
+
+```{r exercise1, exercise=TRUE}
+gapminder |>
+ filter(year == 2007) |>
+ group_by(continent) |>
+ summarise(
+ mean_life_exp = mean(lifeExp)
+ )
+```
+
+```{r exercise1-solution}
+gapminder |>
+ filter(year == 1952) |>
+ group_by(continent) |>
+ summarise(
+ mean_life_exp = mean(lifeExp)
+ )
+```
+
+```{r exercise1-check}
+grade_this_code()
+```
+
+## Details
+
+**Important**: Please enter your GitHub username below and click "Submit Quiz" at the end to record your completion.
+
+```{r github-username, child='_github_username.Rmd'}
+```
+
+```{r participation, child='_participation.Rmd'}
+```
+
+```{r submission-section, child='_submission.Rmd'}
+```
+
+You've completed the Module 1 quiz!
diff --git a/modules/md-02-quiz/_github_username.Rmd b/modules/md-02-quiz/_github_username.Rmd
new file mode 100644
index 0000000..b0d4f2e
--- /dev/null
+++ b/modules/md-02-quiz/_github_username.Rmd
@@ -0,0 +1,122 @@
+```{r github-username-setup, include=FALSE}
+# Read GitHub usernames from CSV
+tryCatch({
+ # Try deployed path first, then fallback to local path
+ csv_path <- "github_usernames.csv"
+ if (!file.exists(csv_path)) {
+ csv_path <- "modules/github_usernames.csv"
+ }
+ github_users <- read.csv(csv_path, stringsAsFactors = FALSE)
+ # Create choices with display format: "First Name (username)"
+ username_choices <- setNames(
+ github_users$github_username,
+ paste0(github_users$first_name, " (", github_users$github_username, ")")
+ )
+}, error = function(e) {
+ # Fallback if CSV not found
+ username_choices <- character(0)
+})
+```
+
+```{r github-username, echo=FALSE}
+div(
+ selectizeInput(
+ "github_username",
+ "GitHub Username:",
+ choices = NULL, # Start empty for performance
+ options = list(
+ placeholder = "Start typing your name or GitHub username...",
+ maxItems = 1,
+ searchField = c("value", "text"),
+ create = TRUE, # Allow creating new entries
+ persist = TRUE, # Keep options persistent
+ closeAfterSelect = TRUE,
+ loadThrottle = 200 # Delay loading to prevent auto-selection
+ )
+ ),
+ # Warning message for new usernames
+ div(id = "username-warning", style = "color: orange; font-size: 12px; margin-top: 5px;"),
+ # Confirmation for new usernames
+ div(id = "username-confirmation", style = "margin-top: 10px;")
+)
+```
+
+```{r, context="server"}
+# Read GitHub usernames in server context
+username_choices <- reactive({
+ tryCatch({
+ # Try deployed path first, then fallback to local path
+ csv_path <- "github_usernames.csv"
+ if (!file.exists(csv_path)) {
+ csv_path <- "modules/github_usernames.csv"
+ }
+ github_users <- read.csv(csv_path, stringsAsFactors = FALSE)
+ # Create choices with display format: "First Name (username)"
+ setNames(
+ github_users$github_username,
+ paste0(github_users$first_name, " (", github_users$github_username, ")")
+ )
+ }, error = function(e) {
+ # Fallback if CSV not found
+ character(0)
+ })
+})
+
+# Update selectize choices on server side - delay to prevent auto-selection
+observeEvent(session$clientData, {
+ # Small delay to ensure UI is ready before populating choices
+ invalidateLater(500, session)
+ isolate({
+ updateSelectizeInput(
+ session = session,
+ inputId = "github_username",
+ choices = username_choices(),
+ selected = character(0), # Ensure nothing is pre-selected
+ server = FALSE
+ )
+ })
+}, once = TRUE)
+
+# Validate username and show warning/confirmation
+observeEvent(input$github_username, {
+ if (!is.null(input$github_username) && input$github_username != "") {
+ # Check if username is in the approved list
+ is_approved <- input$github_username %in% username_choices()
+
+ if (!is_approved) {
+ # Show warning for new username
+ output$`username-warning` <- renderUI({
+ div(
+ style = "color: orange; font-size: 12px; margin-top: 5px;",
+ HTML("⚠️ Warning: This username is not in the approved list. Please confirm it's correct.")
+ )
+ })
+
+ # Show confirmation checkbox
+ output$`username-confirmation` <- renderUI({
+ div(
+ style = "margin-top: 10px;",
+ checkboxInput(
+ "confirm_username",
+ HTML(paste0("I confirm that ", input$github_username, " is my correct GitHub username")),
+ value = FALSE
+ )
+ )
+ })
+ } else {
+ # Clear warnings for approved username
+ output$`username-warning` <- renderUI({
+ div(
+ style = "color: green; font-size: 12px; margin-top: 5px;",
+ HTML("✓ Username found in approved list")
+ )
+ })
+ output$`username-confirmation` <- renderUI({})
+ }
+ } else {
+ # Clear all messages when empty
+ output$`username-warning` <- renderUI({})
+ output$`username-confirmation` <- renderUI({})
+ }
+}, ignoreInit = TRUE)
+```
\ No newline at end of file
diff --git a/modules/md-02-quiz/_participation.Rmd b/modules/md-02-quiz/_participation.Rmd
new file mode 100644
index 0000000..0623325
--- /dev/null
+++ b/modules/md-02-quiz/_participation.Rmd
@@ -0,0 +1,10 @@
+```{r participation-question, echo=FALSE}
+question("Have you participated in the live module, did you watch the recording, or are you only completing the quiz?",
+ answer("Live module", correct = TRUE),
+ answer("Recording", correct = TRUE),
+ answer("Both, live & recording", correct = TRUE),
+ answer("Neither", correct = TRUE),
+ random_answer_order = FALSE,
+ type = "single"
+)
+```
\ No newline at end of file
diff --git a/modules/md-02-quiz/_submission.Rmd b/modules/md-02-quiz/_submission.Rmd
new file mode 100644
index 0000000..1d51d97
--- /dev/null
+++ b/modules/md-02-quiz/_submission.Rmd
@@ -0,0 +1,81 @@
+```{r, context="server"}
+# Google Form setup
+form_url <- "https://docs.google.com/forms/d/e/1FAIpQLScnw9R8wMU5SfFqNVXGeEkiIygLTB_Dc6jWBmbwEeHuekBDzg/formResponse"
+
+# Entry ID mappings
+learnrhash_entry_id <- "entry.1315905314"
+github_username_entry_id <- "entry.61564704"
+tutorial_id_entry_id <- "entry.1169139257"
+```
+
+## Quiz Submission
+
+Please click the button below to submit your quiz results:
+
+```{r submission, echo=FALSE}
+actionButton("submit", "Submit Quiz", class = "btn-primary btn-lg")
+
+# Submission status
+textOutput("submission_status")
+```
+
+```{r, context="server"}
+# Handle quiz submission
+observeEvent(input$submit, {
+
+ # Get GitHub username
+ github_username <- input$github_username
+
+ if (is.null(github_username) || github_username == "") {
+ output$submission_status <- renderText({
+ "Please enter your GitHub username before submitting."
+ })
+ return()
+ }
+
+ # Generate learnrhash
+ tryCatch({
+ # Get tutorial state and generate hash
+ state <- learnr::get_tutorial_state()
+ learnrhash_submission <- learnrhash::encode_obj(state)
+
+ # Get tutorial info
+ tutorial_info <- learnr::get_tutorial_info()
+ tutorial_id <- ifelse(is.null(tutorial_info$tutorial_id), "unknown", tutorial_info$tutorial_id)
+
+
+ # Prepare form data for Google Form with separate fields
+ form_data <- list()
+ form_data[[learnrhash_entry_id]] <- learnrhash_submission
+ form_data[[github_username_entry_id]] <- github_username
+ form_data[[tutorial_id_entry_id]] <- tutorial_id
+
+ # Submit to Google Form
+ response <- httr::POST(form_url, body = form_data, encode = "form")
+
+ # Check response
+ if (httr::status_code(response) %in% c(200, 302)) {
+ output$submission_status <- renderText({
+ paste("Quiz submitted successfully at", Sys.time(),
+ "\nModule:", tutorial_id,
+ "\nYour submission hash:", learnrhash_submission)
+ })
+ } else {
+ output$submission_status <- renderText({
+ paste("Submission may have failed. Please save this hash and contact your instructor:",
+ learnrhash_submission)
+ })
+ }
+
+ }, error = function(e) {
+ # Fallback: show hash to student
+ state <- learnr::get_tutorial_state()
+ fallback_hash <- digest::digest(state, algo = "sha256")
+
+ output$submission_status <- renderText({
+ paste("Error submitting quiz. Please save this hash and contact your instructor:",
+ fallback_hash)
+ })
+ })
+})
+```
\ No newline at end of file
diff --git a/modules/md-02-quiz/data/ds4owd-002-country-residence-count.csv b/modules/md-02-quiz/data/ds4owd-002-country-residence-count.csv
new file mode 100644
index 0000000..8e19c5d
--- /dev/null
+++ b/modules/md-02-quiz/data/ds4owd-002-country-residence-count.csv
@@ -0,0 +1,44 @@
+iso3,name,n
+AUT,Austria,1
+BEN,Benin,1
+BGD,Bangladesh,2
+BOL,Bolivia,3
+BRA,Brazil,2
+BWA,Botswana,1
+CAN,Canada,4
+CHE,Switzerland,15
+CHN,China,2
+CMR,Cameroon,2
+COD,Congo Democratic Republic,1
+CZE,Czechia,2
+DEU,Germany,5
+ECU,Ecuador,1
+ESP,Spain,2
+ETH,Ethiopia,12
+FRA,France,3
+GBR,United Kingdom,4
+GHA,Ghana,15
+IDN,Indonesia,1
+IND,India,3
+IRL,Ireland,1
+IRN,Iran,1
+ITA,Italy,1
+KEN,Kenya,7
+MWI,Malawi,12
+NER,Niger,1
+NGA,Nigeria,24
+NLD,Netherlands,3
+NPL,Nepal,1
+PRT,Portugal,2
+SDN,Sudan,2
+SEN,Senegal,2
+SLE,Sierra Leone,1
+SSD,South Sudan,2
+TUN,Tunisia,1
+TZA,Tanzania,1
+UGA,Uganda,15
+UKR,Ukraine,1
+USA,United States,9
+YEM,Yemen,1
+ZAF,South Africa,13
+ZWE,Zimbabwe,2
diff --git a/modules/md-02-quiz/github_usernames.csv b/modules/md-02-quiz/github_usernames.csv
new file mode 100644
index 0000000..a38fa9b
--- /dev/null
+++ b/modules/md-02-quiz/github_usernames.csv
@@ -0,0 +1,146 @@
+github_username,first_name
+massarin,Nicolo
+rainbow-train,Rainbow
+kpeckeref,Kaitlin
+jmfoss03,Jeffrey
+dspalthoff,Daniel
+madalitsokanache,Madalitso
+tesssadurham,Tessa
+ambuehlb,benjamin
+getenehmoges,Geteneh
+dkabanyana-cyber,Diane
+aditya-khedkar,Aditya
+faraharbi,Farah
+gaduku,Godwin
+mejbahce1991,Mejbah Uddin
+djamphie,Kwasi
+emmanuellmhango,emmanuel
+soziee,Masozi
+severin-ek,Sévérin
+fundilek,Fundile
+traviskunnen,Travis
+phumlileamanda,Phumlile
+ellentafm,Ellen
+eugene-6203,Eugene
+stacianordin,Stacia
+collo2004,Collins
+dapeguero,Daniela
+melita235,Melita Nathania
+clwanga183,Isaac
+yozgoesdigital,Jos
+iggonz,Iggo
+aditiowthar,Aditi
+elizabeth-tilley,Elizabeth
+bwana3010,Jackline
+barbygk,Barbara
+alazarnegash-horecha,Alazar
+mushana-stack,Mushana Joseph
+hopechilunga,Hope
+quishqa,Mario
+prakash4272,Prakash
+beckeinstein,Benjamin
+bensi4,Waffo Benedicte
+fadilah-hub,Fadila
+almamykonte,Almamy
+kobina-afful,Kobina
+onyangomoriswanyama,Moris Wanyama
+oliverwale94,Oliver
+ksumona,Sumona
+seyrama,Seyram
+elishaokoth,Elisha
+matlove23,Matthews
+eacquah-arch,Ebenezer
+aravind-soman,Aravind
+kjrezek,Kyle
+ssiima,Syson
+shafsharif,Shafkat
+carleytru,Carley
+paul103-cloud,Paul
+montoyna,Natalia
+biyiemmy,Emmanuel
+joseph6348,Joseph Lee
+karezek,Kaitlyn
+foma4tune,foma
+crh00,Chris
+iamsilvia,Sílvia
+bettyghg,Betelhem Gebeyehu
+mesenbet-fentie,Mesenbet Fentie
+rafaellabaracho,Rafaella
+tshepi-sys,Tshephang
+munjame,Mundrugo
+chiwanzamunashe,Munashe
+frantisek-ficek,František
+andrema123-git,Mwansa Andrew
+ike76,Isaac
+berti83,Alberto
+andrealescano,Andrea
+rebecca-lk,Rebecca
+pascarini,Sri Pascarini
+adesijivictoria,Victoria
+collins1125,Collins
+sarah78016,Sarah
+rayprinz99,Ismail
+g-njoroge,George
+musabasha,Maibasha
+jngalamu,Julius
+dustingarrick,Dustin
+fnboadu,Frank
+miller-meghan,Meghan
+kosgey-001,kosgey
+wondibernega,Wondiber Nega
+0920458603,Abiel Teshome
+mosisabekele,Mosisa Bekele
+squiebble,Ranya
+michaelnacquah,Michael
+johnbrogan-alt,John
+salgadosebastian-glitch,Sebastian
+sgetahun,Samuel Tenaw
+hingamercy50-cmyk,Mercy
+laigarve,Laia
+bttgcm,Giacomo
+roh2o,Rocio
+tangqiqing,Qiqing
+prabhatjoshi007,Prabhat
+tmoneytmali,Thabiso
+asimenye99,Doreen
+imegit,Augustine
+kunzrp,Richard
+adgomezs,Adriana
+watnafu,Wondafrash Atnafu
+adheesh20,Adheesh
+stefanie123456,Stefanie
+hawahmugisha,Hawah
+gervaismomo42,Gervais
+ebeidomer-byte,Omer
+davismajara,Davis
+promise707-lab,Promise
+blessingrebecca26,Blessing
+big-gen,Nnaemeka
+mmasomoma,mmasom
+visionary210,Isaiah
+otoosakyidavid,David
+baadedotun,Adedotun
+clairegrand,Claire
+wisjay,Wisdom
+pjosephy,Taylor
+astute2011,Kabir
+harlod-max,Harlod
+irshadadi-luc,SHADADI
+snowty930,Sinoxolo
+assumpta-hub,Assumpta
+reahmq2018-oss,Reem
+willis-254,William
+mercyncube,Mercy
+fernando-pm,Fernando
+rewarda58,Reward
+yousefia601,Ali
+chekwube-web,Chekwubechukwu Victory
+qzahra08,Qazi Aniqua
+gloajugwo,GLORIA
+ocheaikpa,Ochea
+faizaaudri03,Faiza Tabassum Haque
+analystkemi,Blessing
+betadetective,Beta
+redd-om,Olivia
+mmumba266,Moses
+galacticasparagus,Galactica
diff --git a/modules/md-02-quiz/md-02-quiz.Rmd b/modules/md-02-quiz/md-02-quiz.Rmd
new file mode 100644
index 0000000..905f81a
--- /dev/null
+++ b/modules/md-02-quiz/md-02-quiz.Rmd
@@ -0,0 +1,406 @@
+---
+title: "Module 2: Data Visualization"
+output: learnr::tutorial
+runtime: shiny_prerendered
+description: "Test your understanding of data visualization concepts covered in Module 2"
+resource_files:
+ - github_usernames.csv
+ - _github_username.Rmd
+ - _participation.Rmd
+ - _submission.Rmd
+tutorial:
+ id: "md-02-quiz"
+---
+
+```{r setup, include=FALSE}
+library(learnr)
+library(dplyr)
+library(ggplot2)
+library(gapminder)
+library(palmerpenguins)
+library(knitr)
+library(gradethis)
+library(learnrhash)
+library(httr)
+library(sf)
+library(rnaturalearth)
+# Try to load rnaturalearthdata with fallback
+tryCatch({
+ library(rnaturalearthdata)
+}, error = function(e) {
+ # If rnaturalearthdata isn't available, install it or use fallback
+ tryCatch({
+ if (!requireNamespace("remotes", quietly = TRUE)) {
+ install.packages("remotes")
+ }
+ remotes::install_github("ropensci/rnaturalearthdata")
+ library(rnaturalearthdata)
+ }, error = function(e2) {
+ warning("rnaturalearthdata not available, some functionality may be limited")
+ })
+})
+library(readr)
+library(here)
+library(tidyr)
+library(countrycode)
+
+# Enable exercise checking
+tutorial_options(
+ exercise.eval = FALSE,
+ exercise.checker = gradethis::grade_learnr
+)
+
+knitr::opts_chunk$set(echo = FALSE, warning = FALSE)
+
+# Prepare data for Question 7
+gapminder_summary_continent_year <- gapminder |>
+ group_by(continent, year) |>
+ summarise(
+ lifeExp = mean(lifeExp),
+ .groups = "drop"
+ )
+
+# Load world map data and course participant data for Question 8
+# Use error handling in case rnaturalearthdata is not available
+world <- tryCatch({
+ ne_countries(scale = "medium", returnclass = "sf")
+}, error = function(e) {
+ # Fallback: try downloading the data
+ tryCatch({
+ ne_download(scale = "medium", type = "countries", category = "cultural", returnclass = "sf")
+ }, error = function(e2) {
+ # Last resort: create a simple placeholder
+ warning("Unable to load world map data, using placeholder")
+ data.frame(iso_a3 = character(0), name_long = character(0))
+ })
+})
+
+# Load and prepare participant data
+participant_data <- read_csv(
+ "data/ds4owd-002-country-residence-count.csv",
+ show_col_types = FALSE
+)
+
+# Join the data (for initial setup)
+world_participants <- world |>
+ left_join(participant_data, by = c("iso_a3" = "iso3")) |>
+ mutate(
+ n = replace_na(n, 0)
+ )
+```
+
+## Introduction
+
+This weekly quiz is designed to support your learning in the ds4owd course. It will test your understanding of the concepts covered in Module 2, including data visualization with ggplot2, boxplots, histograms, and different types of variables.
+
+## Multiple Choice Questions
+
+### Poll 1: Boxplot - Thick Line
+
+```{r boxplot-display-1, echo=FALSE, fig.width=7, fig.asp=0.618}
+ggplot(data = gapminder,
+ mapping = aes(x = continent,
+ y = lifeExp)) +
+ geom_boxplot() +
+ theme_minimal(base_size = 14)
+```
+
+```{r poll1}
+question_radio(
+ "What does the thick line inside the box of a boxplot represent?",
+ answer("The mean of the observations"),
+ answer("The middle of the box"),
+ answer("The median of the observations", correct = TRUE),
+ answer("None of the above"),
+ incorrect = "Think about which measure of central tendency is typically shown in a boxplot.",
+ correct = "Correct! The thick line inside the box represents the median, which divides the data into two equal halves.",
+ allow_retry = TRUE,
+ random_answer_order = TRUE
+)
+```
+
+### Poll 2: Boxplot - Interquartile Range
+
+```{r boxplot-display-2, echo=FALSE, fig.width=7, fig.asp=0.618}
+ggplot(data = gapminder,
+ mapping = aes(x = continent,
+ y = lifeExp)) +
+ geom_boxplot() +
+ theme_minimal(base_size = 14)
+```
+
+```{r poll2}
+question_radio(
+ "What percentage of observations are contained inside the box of a boxplot (interquartile range)?",
+ answer("25%"),
+ answer("Depends on the median"),
+ answer("50%", correct = TRUE),
+ answer("None of the above"),
+ incorrect = "The box represents the interquartile range (IQR), which contains the middle portion of the data.",
+ correct = "Correct! The box contains 50% of the observations - from the 25th percentile (Q1) to the 75th percentile (Q3).",
+ allow_retry = TRUE,
+ random_answer_order = TRUE
+)
+```
+
+### Poll 3: Median Definition
+
+```{r poll3}
+question_radio(
+ "What is the median of a set of observations?",
+ answer("The median is the most frequently occurring value in a dataset."),
+ answer("The median is the sum of all values in a dataset divided by the number of observations."),
+ answer("The median is the point above and below which half (50%) of the observations falls.", correct = TRUE),
+ answer("The median is the square root of the sum of the squares of each value in a dataset."),
+ incorrect = "The median is a measure of central tendency that divides the data.",
+ correct = "Correct! The median is the middle value that divides the data into two equal halves.",
+ allow_retry = TRUE,
+ random_answer_order = TRUE
+)
+```
+
+### Question 4: Histogram Definition
+
+```{r q4}
+question_radio(
+ "What is a histogram?",
+ answer("A plot that displays the relationship between two continuous variables using points"),
+ answer("A graphical representation of the distribution of numerical data using bars to show frequency of values in intervals", correct = TRUE),
+ answer("A plot that shows the median, quartiles, and outliers of a dataset"),
+ answer("A circular chart divided into sectors showing proportions of categories"),
+ incorrect = "A histogram is specifically designed to show the distribution of a single numerical variable.",
+ correct = "Correct! A histogram uses bars to show how frequently values fall within specified intervals (bins) for numerical data.",
+ allow_retry = TRUE,
+ random_answer_order = TRUE
+)
+```
+
+### Question 5a: Variable Types - Discrete
+
+```{r q5a}
+question_checkbox(
+ "Which of the following are examples of discrete numerical variables? (Select all that apply)",
+ answer("Number of students in a classroom", correct = TRUE),
+ answer("Height of a person"),
+ answer("Roll of a dice", correct = TRUE),
+ answer("Temperature in degrees Celsius"),
+ answer("Number of cars in a parking lot", correct = TRUE),
+ answer("Weight of a package"),
+ incorrect = "Discrete variables are countable and typically represent whole numbers. Continuous variables can take any value within a range.",
+ correct = "Correct! Discrete variables represent countable quantities that are typically whole numbers.",
+ allow_retry = TRUE
+)
+```
+
+### Question 5b: Variable Types - Continuous
+
+```{r q5b}
+question_checkbox(
+ "Which of the following are examples of continuous numerical variables? (Select all that apply)",
+ answer("Number of pages in a book"),
+ answer("Length of a room", correct = TRUE),
+ answer("Time taken to complete a task", correct = TRUE),
+ answer("Number of siblings"),
+ answer("Body weight", correct = TRUE),
+ answer("Shoe size"),
+ incorrect = "Continuous variables can take any value within a range, including decimals. Discrete variables are countable.",
+ correct = "Correct! Continuous variables can take any value within a range and include measurements like length, weight, and time.",
+ allow_retry = TRUE
+)
+```
+
+## Coding Exercises
+
+### Question 6: Understanding Barplots
+
+Run the code below to create a barplot showing the count of penguins by species:
+
+```{r q6-setup}
+# Ensure penguins data is available
+data(penguins, package = "palmerpenguins")
+```
+
+```{r q6-exercise, exercise=TRUE, exercise.eval=FALSE, exercise.setup="q6-setup"}
+ggplot(data = penguins,
+ mapping = aes(x = species)) +
+ geom_bar()
+```
+
+```{r q6-question}
+question_radio(
+ "Why don't we need to supply a y-axis mapping when using geom_bar()?",
+ answer("The y-axis defaults to zero for all bars"),
+ answer("geom_bar() automatically counts the number of observations for each x value", correct = TRUE),
+ answer("The y-axis is randomly generated"),
+ answer("geom_bar() uses the row numbers as y values"),
+ incorrect = "Think about what statistical transformation geom_bar() performs on the data.",
+ correct = "Correct! geom_bar() performs a statistical transformation (stat_count) that automatically counts the number of observations for each category on the x-axis.",
+ allow_retry = TRUE,
+ random_answer_order = TRUE
+)
+```
+
+### Question 7: Create a Timeseries Plot
+
+Complete the code below to create a timeseries plot showing life expectancy by continent over time. You need to:
+
+1. Add the correct geom functions to create both lines and points
+2. The aesthetic mappings are already provided
+
+```{r q7-setup}
+# Prepare the summarized data
+gapminder_summary_continent_year <- gapminder |>
+ group_by(continent, year) |>
+ summarise(
+ lifeExp = mean(lifeExp),
+ .groups = "drop"
+ )
+```
+
+```{r q7-exercise, exercise=TRUE, exercise.eval=FALSE, exercise.setup="q7-setup"}
+# Complete this code by adding geom_line() and geom_point()
+ggplot(data = gapminder_summary_continent_year,
+ mapping = aes(x = year,
+ y = lifeExp,
+ color = continent))
+```
+
+```{r q7-solution, include=FALSE}
+ggplot(data = gapminder_summary_continent_year,
+ mapping = aes(x = year,
+ y = lifeExp,
+ color = continent)) +
+ geom_line() +
+ geom_point()
+```
+
+```{r q7-code-check, include=FALSE}
+grade_this_code(
+ correct = "Excellent! You've successfully created a timeseries plot showing life expectancy trends by continent over time.",
+ incorrect = "Not quite. {code_feedback()} Remember to add both geom_line() and geom_point() to create the lines and points."
+)
+```
+
+### Question 8: Analyze Course Participant Distribution
+
+Let's explore where ds4owd course participants are located around the world.
+
+#### Part A: View Participant Counts by Country
+
+First, let's look at the participant data sorted by the number of participants:
+
+```{r q8a-setup}
+# Load and prepare participant data
+participant_data <- read_csv(
+ "data/ds4owd-002-country-residence-count.csv",
+ show_col_types = FALSE
+)
+
+# Add continent information using countrycode package
+residence <- participant_data |>
+ mutate(
+ continent = countrycode(iso3, "iso3c", "continent")
+ ) |>
+ arrange(desc(n))
+```
+
+```{r q8a-display, exercise=TRUE, exercise.eval=FALSE, exercise.setup="q8a-setup"}
+# Display the participant data sorted by count (n)
+residence |>
+ select(name, continent, n)
+```
+
+#### Part B: Group Participants by Continent
+
+Now, complete the code below to calculate the total number of participants per continent. Fill in the blank with the correct column name to group by:
+
+```{r q8b-exercise, exercise=TRUE, exercise.eval=FALSE, exercise.setup="q8a-setup"}
+# Fill in the blank: group by which column?
+residence |>
+ group_by(________) |>
+ summarise(
+ total_participants = sum(n),
+ number_of_countries = n_distinct(iso3)
+ ) |>
+ arrange(desc(total_participants))
+```
+
+```{r q8b-solution, include=FALSE}
+residence |>
+ group_by(continent) |>
+ summarise(
+ total_participants = sum(n),
+ number_of_countries = n_distinct(iso3)
+ ) |>
+ arrange(desc(total_participants))
+```
+
+```{r q8b-code-check, include=FALSE}
+grade_this_code(
+ correct = "Perfect! You've successfully grouped the participants by continent to see the distribution across different regions.",
+ incorrect = "Not quite. {code_feedback()} You should group by 'continent' to aggregate the data by continental regions."
+)
+```
+
+#### Part C: Visualize on a World Map
+
+You can also prepare maps with `ggplot2`. It's beyond the scope of the class to teach you the foundations of spatial data in R, but a popular package to work with spatial data is the `sf` (Simple Features) R Package. The `rnaturalearth` R Package facilitates world mapping by making [Natural Earth](https://www.naturalearthdata.com/) map data more easily available to R users.
+
+Let's visualize the participant data on a world map (**it may be slow, give it a minute**):
+
+```{r q8c-setup}
+# world map data already loaded
+
+# Load and prepare participant data
+participant_data <- read_csv(
+ "data/ds4owd-002-country-residence-count.csv",
+ show_col_types = FALSE
+)
+
+# Join the data and add hover text
+world_participants <- world |>
+ left_join(participant_data, by = c("iso_a3" = "iso3")) |>
+ mutate(
+ n = replace_na(n, 0),
+ hover_text = paste0(
+ name_long, ": ", n, " participant", ifelse(n == 1, "", "s")
+ )
+ )
+```
+
+```{r q8c-exercise, exercise=TRUE, exercise.eval=FALSE, exercise.setup="q8c-setup"}
+# Create a world map showing participant counts
+ggplot(data = world_participants) +
+ geom_sf(aes(fill = n), color = "white", size = 0.1) +
+ scale_fill_gradient(
+ low = "#f0f0f0",
+ high = "#2c3e50",
+ name = "Participants",
+ breaks = c(0, 5, 10, 15, 20, 25)
+ ) +
+ theme_minimal() +
+ theme(
+ legend.position = "right",
+ axis.text = element_blank(),
+ axis.ticks = element_blank(),
+ panel.grid = element_blank()
+ ) +
+ labs(
+ title = "ds4owd Course Participants by Country"
+ )
+```
+
+## Details
+
+**Important**: Please enter your GitHub username below and click "Submit Quiz" at the end to record your completion.
+
+```{r child="_github_username.Rmd"}
+```
+
+```{r child="_participation.Rmd"}
+```
+
+```{r child="_submission.Rmd"}
+```
+
+You've completed the quiz!