misc.tutorials is an R package of "normal" (post-infrastructure) learnr tutorials. It is governed by the base tutorial guide and adds only what is specific to this package below.
These tutorials inherit the base tutorial guide — the default contract for authoring any normal data science tutorial in this ecosystem, at claude-md/tutorials/CLAUDE.md in the PPBDS/ai-rules repo (locally: ../ai-rules/claude-md/tutorials/CLAUDE.md). Read it before working on any tutorial here. It is the source of truth for everything common to all such tutorials:
- the AI-era philosophy — students create artifacts by prompting an AI agent, not by typing code into learnr exercise chunks;
- the workflow — student work lives in
analysis.qmd; they render withquarto renderin a bash terminal and view the result via Live Server; - exercise rhythm, the
question_text()question types, knowledge-drop discipline, CP/CR andshow_file()evidence; echo = FALSE, test-chunk discipline, code-chunk labeling, the setup-chunk skeleton, data handling, and formatting conventions.
misc.tutorials is one of the packages the base guide governs by default — it is not an exception (those are vscode.tutorials and tutorial.helpers). In the base guide's normal-vs-modeling split, every tutorial here is a normal tutorial: we mostly don't care which code does what — we care about the output. The modeling tutorials (code-visible, slow-down-and-look) live in primer.tutorials, tutorial 05 and higher.
Precedence. On workflow and shared conventions, the base guide wins. On misc.tutorials-specific content this file wins. Any departure from the base guide must be an explicit, on-the-record override stated here — never a silent difference. (The base guide already carries the Choosing topics (misc.tutorials-specific) section; this file does not repeat it.)
Override — explicit data/ scaffold in r4ds-1 and r4ds-2 only. The base guide (§4, Introduction step 3) says to state the goal and confirm with bash ls. The first two r4ds tutorials instead spell out the commands — getwd(), dir.create("data"), list.files() in the R Terminal — because students arrive fresh from the infrastructure tutorials and should see exactly what is happening. r4ds-2 adds the transition note: "We will soon stop giving you commands like these and just have AI do it." From r4ds-3 on, every tutorial (including census, baseball, …) follows the base guide's goal-stated + bash-ls form. (This narrowing is one instance of the pacing gradient recorded below.)
Override — no interpretation exercises. The base guide (§4, Analysis path) requires a dedicated interpretation exercise after each significant visualization, asking students to write one or two sentences about what the plot shows. misc.tutorials does not follow this rule. The tutorials here are structured around AI-assisted artifact creation; students steer the analysis and judge the output, but are not asked to write prose interpretations in the QMD. Knowledge drops carry the interpretive commentary instead. Do not add interpretation exercises to any tutorial in this package.
A collection of tutorials covering material from two companion texts:
- R for Data Science (2e) — the
r4ds-1…r4ds-5tutorials. - Analyzing US Census Data by Kyle Walker — the
censustutorial.
The organizing theme is storage technology. Each tutorial sources its data from a different sort of storage — delimited files, spreadsheets, databases, Arrow files, spatial formats, and web APIs — and then works with that data using the tidyverse. The storage technology is the spine of each tutorial; the subject-area domain (music, births/basketball, baby names/flights, crypto, wildfires/film rankings, census demographics) is chosen to suit it.
The division of the R for Data Science material into five tutorials (r4ds-1 … r4ds-5) is reasonable but arbitrary — the same material could be split into more or fewer. Treat the count as a convenience, not a fixed boundary, when deciding whether to split a long tutorial or merge two short ones. This has already happened once: in August 2026 r4ds-4 had grown to 51 exercises, and its prediction-market half was split out as the prediction-markets tutorial, leaving 32 and 25. Note what the split did to the numbering — prediction-markets is a peer of r4ds-4, not a successor to r4ds-5, so it took a topic name rather than an r4ds-6 slot. Prefer a topic name for any future split, since a tutorial's id becomes the name of every student's repo and renumbering the sequence would break repos that already exist.
The class workflow: students complete the first four vscode.tutorials infrastructure tutorials — Workspace, Workflow, Code, and Quarto — and then do r4ds-1 through r4ds-5 as their first data-science practice. Two standing consequences:
- Prerequisite contract. The r4ds tutorials may assume exactly what those four tutorials teach (the base guide's Assumed skills boundary) and nothing more. A skill the sequence needs but the four do not teach — driving an AI agent, whatever else — is a gap: fix it in
vscode.tutorials, or scaffold it explicitly inr4ds-1/r4ds-2; never assume it silently. (R packages are not part of this contract: the student environment guarantees every package the tutorials need is preinstalled, so tutorials never include install exercises.) - Pacing gradient.
r4ds-1is the student's first post-infrastructure tutorial and goes slowest: more explanation, smaller setup steps, explicit commands where later tutorials just state goals.r4ds-2is slightly faster.r4ds-3–r4ds-5may assumer4ds-1andr4ds-2are complete and move at full speed. The explicitdata/scaffold override (above) is one instance of this gradient.
| Tutorial | Storage technology | Key packages | Data |
|---|---|---|---|
r4ds-1 |
Delimited files (CSV) | readr, maps | music.csv |
r4ds-2 |
Spreadsheets | readxl | us_births_1994_2014.xlsx, nba_recruits.xlsx |
r4ds-3 |
Databases | DBI, dbplyr, duckdb | *.duckdb |
r4ds-4 |
Arrow / Parquet | arrow | daily_prices.parquet, coin_metadata.parquet, categories.parquet |
r4ds-5 |
Spatial / web | jsonlite, leaflet, purrr, httr2, rvest | wildfires.geojson, imdb_snapshots.rds |
census |
Web API | tidycensus, sf | *.rds |
baseball |
R data package (Lahman) | Lahman, tidyverse | Lahman::Teams, Lahman::Batting, Lahman::People |
ducks |
Delimited files (CSV) | sf, maps, ggridges | mallards.csv |
sharks |
Delimited files (CSV) | maps | attacks.csv, attacks.rds, attacks_clean.csv |
spiderman |
Delimited files (CSV) | tidyverse | films.rds, spiderman_rt_clean.csv |
movies |
Delimited files (CSV) | tidyverse | movies.csv |
prediction-markets |
Arrow / Parquet | arrow | markets.parquet, history.parquet, groups.parquet, market_groups.parquet |
ducks, sharks and spiderman are project-tier tutorials (see the next section);
movies and prediction-markets each build a single page. Note that ducks, sharks,
spiderman and movies all read plain CSV: per the project tier's topic-driven, not a
new storage technology override, they are organized around a domain rather than around a
storage technology they introduce. prediction-markets is the one topic-named tutorial
that does share a storage technology with an r4ds-* tutorial, because it was split out
of r4ds-4 rather than written fresh.
movies and spiderman both draw on Rotten Tomatoes data, which is worth revisiting —
two tutorials on the same source is thin justification for two tutorials.
baseball is the first of a newer tier of tutorials (topics like baseball, stocks, Bitcoin, weather, US maps) whose distinguishing feature is that the final artifact is a project — not a single published analysis.qmd page. A "project" is any multi-file Quarto/R artifact a student creates and publishes: a simple multi-page website (baseball's form), but equally a Shiny app, a Quarto dashboard, or similar. Students are assumed to have done the vscode.tutorials material for whichever project type a tutorial uses, so the project mechanics are not re-taught. The following base-guide defaults are written for the single-page model and are overridden on the record for this tier (the first three are general to every project type; the fourth is specific to the website form baseball uses):
- A project, not
analysis.qmd. The student builds a multi-file project with its own config (e.g._quarto.yml) and a natural place for each topic, rather than one evolvinganalysis.qmd. The base guide's "one evolving working chunk per topic" maps onto "one unit of the project per topic" — for a website, one page per topic (home-runs.qmd,sluggers.qmd); for a dashboard, one card/section; for Shiny, one view. Site/app-wide settings likeexecute: echo: falsego in the project config once, not in each file's YAML. - Students write AI-drafted prose as project content. The TODO asks that students add text to the project; they draft framing/landing prose with AI and submit it via
show_file()on the relevant file. This is not the forbidden interpretation exercise. The no-interpretation-exercises override still holds: we never ask a student to write graded prose explaining what a plot shows. Writing the project's framing copy is artifact-content creation — words the project genuinely needs — and our shown answer is a model paragraph of that copy. Keep prose tasks to framing, not per-plot interpretation. - Topic-driven, not a new storage technology. Per the TODO ("tutorials now are about concepts, not books"), this tier is organized around a domain plus its gold-standard R data infrastructure, and need not introduce an unused storage technology.
baseballdoes not: its "storage" is simply the Lahman R data package. The storage-spine framing in What this package is applies to ther4ds-*/censustutorials; for this tier the spine relaxes to "domain + canonical data source." Still teach the data ecosystem in knowledge drops (for baseball: Lahman as the season-level gold standard, with Retrosheet/Statcast/baseballr as the finer-grained frontier). - Website form (baseball's project type). A Quarto website:
_quarto.yml+index.qmd+ one analysis page per topic. Render the whole site with barequarto render; open_site/index.htmlwith Live Server (output lives in_site/)..gitignoreignores/_site/,/.quarto/,/*_files/, and (after the caching arc)/*_cache/. A page's#| cache: truechunk creates a top-level<page>_cache/directory — same caching arc as the base guide, on a per-page chunk. The Summary publishes the whole project withquarto publish gh-pages(no filename) and its final evidence isshow_file("index.qmd"). Other project types will have their own analogous specifics (a dashboard's_quarto.ymlformat: dashboard, a Shiny app'sapp.R/shinyapps.iodeploy); record them here as they are built.
This is misc.tutorials' content model — how it picks each tutorial's subject. The base guide routes topic selection to each project; this is the routed section. Other projects' models differ (the Primer fixes its topics as the four Cardinal Virtues), so this lives here, not in the base guide.
Tutorials are organized around storage technologies (the spine — see above) paired with prominent data sources and real data science domains: US Census data, baseball, stock data, Bitcoin, and other subject areas where students learn what analysts actually use. When adding a tutorial, pick a storage technology not yet covered (or a meaningfully different facet of one), choose a domain that suits it, and follow the base guide's structure.
Each tutorial should teach:
- The gold-standard data sources for that area.
- The main R packages, APIs, file formats, and vocabulary students should mention to AI.
- Common data patterns, data quality issues, and standard analytical questions in that domain.
- A reproducible workflow that ends with a small published Quarto artifact.
Prefer datasets that hide a discoverable anomaly. The best data here is rich enough that a simple analysis looks fine but misses something, leaves clues that something is off, and rewards a further step — usually a plot — that reveals and then explains the mystery. The r4ds-1 Billboard data is the exemplar: only the time-series plot of each song's weekly ranking exposes the strange discontinuity around week 20. Actively search for more datasets with this feature when choosing topics; it generally means reaching for richer / larger datasets rather than small, clean ones. (See the base guide's Analysis path for how to build the discovery into the exercise sequence. Other data choices for these tutorials are still under discussion.)
A tutorial's data lives in a data/ directory inside that tutorial's own folder — inst/tutorials/<name>/data/<file>, sitting next to tutorial.Rmd and at the same level as the images/ directory (if there is one). This is now the base-guide default (§6, Data handling); the rationale — the package's own code becomes identical to the student's code — lives there. Every file-based tutorial has been migrated to this layout; inst/extdata/ and the old re-download machinery are gone. This section records the misc.tutorials-specific mechanics:
- The package's setup and test chunks read data with the exact relative path a student writes:
read_csv("data/music.csv"), not../../extdata/r4ds-1/music.csv. Both resolve todata/<file>because a tutorial knits with its own folder as the working directory, and the student'sanalysis.qmdsits in a repo with its owndata/. Our answer chunks and the student's prompts now match exactly. - Student-facing download URLs point at the same in-tutorial location on GitHub:
.../raw/refs/heads/main/inst/tutorials/<name>/data/<file>. Students download into their own project'sdata/directory and readdata/<file>. - Each
data/directory carries aREADME.txtdocumenting the provenance of its files. These provenance notes are kept in the repo but not installed with the package:.Rbuildignoreholds the rule^inst/tutorials/[^/]+/data/README\.txt$, which strips the READMEs from the build while the data files themselves still ship. - Download-instruction style depends on the tutorial's place in the sequence (per the base guide's Match the download instruction rule). The five
r4ds-*tutorials are a student's first data-science tutorials, so they may hand students an explicit, workingdownload.file("<url>", "data/<file>")command. The project-tier tutorials (baseball,ducks,movies, …) andcensuscome later, so they just point students at the stable URL and let them choose how to fetch it (download.file()or AI).
New work should add data under inst/tutorials/<name>/data/, reference it as data/<file>, point the student download URL at .../inst/tutorials/<name>/data/<file>, and drop a provenance data/README.txt.
Consequence — CRAN. Because the data now ships inside inst/tutorials/, it cannot be stripped at build time the way inst/extdata/ was, so the package exceeds CRAN's size limit and is not CRAN-distributable — an accepted trade-off (see TODO.txt: "we can't put the repo on CRAN. But who really cares?"). The old CRAN-stripping machinery (an R/zzz.R data_manifest/.onAttach() re-download hook, an inst/extdata/ rule in .Rbuildignore, and a test-data-urls.R check) has been removed; R/zzz.R no longer exists and utils was dropped from DESCRIPTION Imports.
Exception — tutorials whose data is an R package. When a tutorial's data ships inside an R package (e.g. baseball uses Lahman), there is no file to host: students install.packages() and library() the package, and the tutorial's test chunks reference the package's tables directly (Teams, Batting, People). Such a tutorial has no data/ directory, no download step, and no R/zzz.R manifest entry — just add the package to DESCRIPTION Suggests. This is more honest about how analysts in that domain actually work (loading the canonical data package) and is the default for the project tier where it applies. (baseball already follows this, so it needs no migration.)
The tutorial data files are large. As of August 2026 inst/ alone is 118 MB and the working tree is about 207 MB — and one tutorial dominates: r4ds-3 is 72 MB, almost all of it atus.duckdb (47 MB) and seda_2025.duckdb (27 MB), with r4ds-5 (19 MB, mostly wildfires.geojson) and ducks (10 MB) next. This is no longer just a devtools::check() size NOTE; it is a real install cost every student pays at the start of the course. When adding or replacing data, prefer the smallest file that still supports the analysis, and treat a multi-tens-of-MB addition as a decision needing justification rather than a default. Subsetting atus.duckdb is the single biggest available win. Under the data/-in-tutorial convention the package ships its data and is not CRAN-distributable (see Data handling above) — a trade-off we accept in exchange for the package's code matching the student's code. The old CRAN-stripping machinery (the .Rbuildignore extdata rule and the R/zzz.R re-download hook) has been removed entirely.
The test chunks that depend on data files skip_on_cran() (see tests/testthat/test-tutorials.R); that stays regardless, since the point is simply not to run heavy data code on CRAN's checkers.
Per the base guide, every package library()-ed in a tutorial must be listed in DESCRIPTION (Imports or Suggests) or GitHub Actions R CMD check fails. This package keeps only tutorial.helpers under Imports (utils was dropped along with R/zzz.R — see Data handling); every tutorial-specific package (arrow, DBI, duckdb, readxl, sf, tidycensus, leaflet, plotly, …) lives under Suggests. When a new tutorial adds a library, add it to Suggests.
Standard base-guide checks apply (rmarkdown::render() for a quick syntax pass, devtools::check() before any PR, learnr::run_tutorial() for the student view). devtools::check() may report a size NOTE — see CRAN / build size above.
Active TODOs live in TODO.txt (data set selection, workflow questions, display options, and new-tutorial ideas). Consult it before starting non-trivial work, and keep it current.