Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ Contents (in addition to `base`):
These same four are **also** refreshed to latest on every Codespace create by codespace-starter's `postCreateCommand`. Baking them here pre-installs the dependency tree (so that refresh is a quick update, not a cold build) and is a fallback if GitHub is unreachable. Add further course packages to **both** places (here and the postCreateCommand) following the same pattern.
- A basic **Python data-science stack** so students can work in Python alongside R (numpy, pandas, matplotlib, seaborn, scikit-learn, statsmodels, jupyter, ipykernel). Installed with `uv` into a venv at `/opt/venv` from a fully-pinned lockfile — `student/requirements.lock`, generated from `student/requirements.txt` via `uv pip compile` (edit the `.txt` and recompile to bump). Notable choices, all build-test-verified: the venv uses the **system** CPython (`uv venv --python /usr/bin/python3`, not a managed download); it's the default `python` on `PATH`, `--seed`ed (has its own `pip`), and made **group-writable** (`staff`, like R's site-library) so a student can `pip install` more packages. A `python3` Jupyter kernel ("Python (data science)") is registered system-wide, so Python works in VS Code notebooks and in Quarto `.qmd` chunks — Quarto runs Python-only docs via the **jupyter** engine, so **reticulate is not needed** (and isn't installed; `RETICULATE_PYTHON` is still set so reticulate bridges to this venv if someone does install it). Footprint: ~150 MB compressed / negligible Codespace-creation time (baked into the image, restored by the prebuild).
- **Observable** for interactive JavaScript visualisation. Quarto's bundled `{ojs}` cells render Observable Plot / OJS inside `.qmd` documents (pass R/Python data in via `ojs_define()`) — this needs **nothing extra**, it's part of the baked Quarto (build-test verified). Separately, **Observable Framework** (`@observablehq/framework`, pinned; adds the `observable` CLI for `create`/`preview`/`build`) is installed for building standalone data-app/dashboard projects — ~84 MB on disk, smoke-tested via `observable --version`.
- A **mapping / census stack** for NYT-style tract maps: `sf` (vector geodata — links against the GDAL/PROJ/GEOS/udunits system libs that `base` bakes for exactly this) and `tidycensus` (ACS/decennial data + geometry in one call; pulls in `tigris`). Live `tidycensus` queries need a free per-student Census API key. Interactive maps come free from the pieces already here: `leaflet` draws `sf` objects, with CARTO basemap tiles instead of Mapbox (no token). The smoke test does an offline `st_sample()` on a CRS-tagged polygon to verify the GDAL/PROJ/GEOS linkage end to end.
- A **mapping / census stack** for NYT-style tract maps: `sf` (vector geodata — links against the GDAL/PROJ/GEOS/udunits system libs that `base` bakes for exactly this) and `tidycensus` (ACS/decennial data + geometry in one call; pulls in `tigris`). Live `tidycensus` queries need a free per-student Census API key — the Census API rejects keyless requests. Interactive maps come free from the pieces already here: `leaflet` draws `sf` objects, with CARTO basemap tiles instead of Mapbox (no token). The smoke test does an offline `st_sample()` on a CRS-tagged polygon to verify the GDAL/PROJ/GEOS linkage end to end. Rounded out by the rest of the Kyle Walker toolkit: `mapgl` (MapLibre/Mapbox GL htmlwidgets — WebGL vector maps with no token via `maplibre()` + CARTO styles), `crsuggest` (suggests the right projected CRS), and `idbr` (Census International Data Base; same Census API key as tidycensus). `mapboxapi` is deliberately excluded — it needs a per-student Mapbox account/token.
- **Interactive web-viz + Shinylive**, for "fancy" interactive websites that still publish to **static** hosting (GitHub Pages). R htmlwidgets — `plotly`, `leaflet`, `DT`, `crosstalk` (installed via pak, ~70 MB) — and their Python counterparts `plotly`/`altair`/`folium`/`itables` (in `requirements.lock`) emit self-contained client-side JS. `shiny` + `shinylive` (both R and Python) compile Shiny apps to WebAssembly (webR/Pyodide) so even reactive apps run with no server. (Interactive charts *inside* Quarto docs work via these widgets or `{ojs}`; Shinylive embeds via the per-project `quarto-shinylive` extension.)

Does NOT include:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ The `student` image carries both languages students use:
- **R** — the rocker/tidyverse foundation, plus the PPBDS course packages (`tutorial.helpers`, `vscode.tutorials`, `misc.tutorials`, `primer.tutorials`), the `arf` console, Quarto, and `httpgd`.
- **Python** — a basic data-science stack installed with [`uv`](https://docs.astral.sh/uv/) into `/opt/venv` from a pinned lockfile (`student/requirements.lock`): numpy, pandas, matplotlib, seaborn, scikit-learn, statsmodels, jupyter, ipykernel. It's the default `python` on `PATH`, with a registered Jupyter kernel — so students can use Python in VS Code notebooks or in Quarto `.qmd` chunks (Quarto runs Python via the jupyter engine; no reticulate needed). The venv is group-writable, so students can `pip install` more packages.
- **Observable** — Quarto's `{ojs}` cells render interactive [Observable Plot](https://observablehq.com/plot/) / OJS in `.qmd` documents out of the box (no install); plus the [Observable Framework](https://observablehq.com/framework/) CLI (`observable`) for building standalone data-app projects.
- **Mapping / census** — `sf` + `tidycensus` (with `tigris`) for census-tract maps: pull ACS data and geometry in one call, render static maps with `ggplot2` or interactive ones with `leaflet` over free CARTO basemap tiles (no Mapbox token). Live census queries need a [free Census API key](https://api.census.gov/data/key_signup.html).
- **Mapping / census** — `sf` + `tidycensus` (with `tigris`) for census-tract maps: pull ACS data and geometry in one call, render static maps with `ggplot2` or interactive ones with `leaflet` over free CARTO basemap tiles (no Mapbox token). Plus the rest of the [Kyle Walker](https://walker-data.com) toolkit: `mapgl` (WebGL vector maps via MapLibre — token-free with `maplibre()` + CARTO styles), `crsuggest` (pick the right CRS), and `idbr` (international Census data). Live census queries need a [free Census API key](https://api.census.gov/data/key_signup.html).
- **Interactive web viz + Shinylive** — for fancy interactive sites on static hosting: R htmlwidgets (`plotly`, `leaflet`, `DT`, `crosstalk`) and Python (`plotly`, `altair`, `folium`, `itables`) emit self-contained client-side JS; **Shinylive** (`shiny` + `shinylive`, R & Python) runs Shiny apps as WebAssembly, so they too deploy to GitHub Pages with no server.

Both are baked into the image, so they cost ~nothing at Codespace-creation time (the prebuild restores them).
Expand Down
14 changes: 12 additions & 2 deletions student/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,18 @@ RUN R -q -e 'pak::pkg_install(c("plotly", "leaflet", "DT", "crosstalk", "shiny",
# API key for live tidycensus queries. P3M Linux binaries, so this is fast.
# The interactive path needs nothing more: leaflet (above) draws sf objects,
# and free CARTO basemap tiles substitute for Mapbox.
RUN R -q -e 'pak::pkg_install(c("sf", "tidycensus"))' \
&& R --vanilla -e 'for (p in c("sf","tidycensus","tigris")) if (!requireNamespace(p, quietly = TRUE)) stop("smoke test failed to load: ", p)' \
#
# Plus the rest of the Kyle Walker toolkit:
# - mapgl: MapLibre/Mapbox GL htmlwidgets — WebGL vector maps (the NYT
# look) with NO token via maplibre() + CARTO styles; publishes
# static to GitHub Pages like every other htmlwidget here.
# - crsuggest: suggests the right projected CRS for a dataset — the one-
# function answer to the #1 beginner mapping confusion.
# - idbr: Census International Data Base (population pyramids, country
# time series); uses the same Census API key as tidycensus.
# Deliberately NOT mapboxapi: it requires a per-student Mapbox account/token.
RUN R -q -e 'pak::pkg_install(c("sf", "tidycensus", "mapgl", "crsuggest", "idbr"))' \
&& R --vanilla -e 'for (p in c("sf","tidycensus","tigris","mapgl","crsuggest","idbr")) if (!requireNamespace(p, quietly = TRUE)) stop("smoke test failed to load: ", p)' \
&& R --vanilla -e 'library(sf); p <- st_sfc(st_polygon(list(rbind(c(0,0), c(1,0), c(1,1), c(0,1), c(0,0)))), crs = 4326); pts <- st_sample(p, 10); stopifnot(length(pts) == 10); cat("sf geometry ops OK\n")'

USER root
Expand Down