Session 1: Quarto for Spatial Reporting
Making the map is usually the last step. The method is everything before it.
A spreadsheet can tell you how many clinics Yucatán has. Only location can tell you:
The new idea this term is joining tables by geometry rather than by a shared id.
| You learn | So you can judge | |
|---|---|---|
| 1 | Quarto for spatial reporting | what a reader actually receives |
| 2 | coordinates and CRS | whether an analysis measures in metres or degrees |
| 3 | sf objects, joins, choropleths |
whether a map shows a rate, or just population |
| 4 | joins by location, distance, buffers | whether nearest and within mean what you intended |
| 5 | rasters and zonal statistics | whether resolution and aggregation fit the question |
Everything is done in R and Quarto rather than in ArcGIS or QGIS.
All of these come from the data in your data/ folder, and you will build them yourself.
“Calculate the distance from every Mexican municipality to the nearest hospital.”
You will get fifteen lines of clean, well-commented sf code in about four seconds.
It will run. It will produce 2,469 numbers.
The question is whether those numbers mean what you think they mean.
None of these is a coding question. Every one of them changes the answer, and none of them throws an error.
Note
By the end of these sessions you should be able to ask for an analysis like this, read what comes back, say where it is wrong, fix it, and defend the version you hand in.
Tizimín, one municipality in Yucatán.
It contains 129 clinics.
Ask for the distance to the nearest hospital. The obvious code takes the centroid.
It answers 30 km.
But 126 of the 129 are right there, in the town.
The code is right. The question was wrong: nobody lives at the centroid.
The centroid has a distance to every clinic, not just the nearest.
| 30.0 km | to the nearest clinic |
| 33.6 km | median of all 129 |
| 33.8 km | mean of all 129 |
| 41.8 km | to the farthest |
Nearest, median or mean — they are all between 30 and 42 km. Picking a different statistic does not help.
The problem is not which summary we take. It is where we measured from.
The centroid’s square kilometre holds one person. The town’s holds 3,875.
Every populated square kilometre of Tizimín, grouped by how many people live in it.
50,070 people are 0.3 km from a clinic. 26,156 are 22.8 km away. That is the finding.
The computer did not get 30 km wrong. We asked it to measure from a square kilometre where one person lives.
Every correction along the way was a question, not a function: measure from where people are, group by community rather than by polygon.
And the answer was never one number — 0.3 km for 50,070 people, 22.8 km for 26,156.
Over these sessions you should be able to ask for an analysis like this, see what is wrong with it, fix it, and defend what you hand in.
By the end, you will have a Quarto document that renders a map of Mexico.
Every line of code in these slides runs on your machine, provided your folders look like this:
ciencia_datos_2/
├── data/
│ ├── gadm41_MEX_shp/ <- Mexico boundaries (GADM)
│ ├── denue/ <- DENUE point data
│ └── mex_formats/ <- the same states as .geojson and .gpkg
└── session1/
└── my_notes.qmd <- you work here
Code in these slides reads ../data/... — up one level, then into data. Keep that shape and everything copies and pastes without edits.
Every .qmd file has exactly three kinds of content:
--- fencesLet’s build one together, from an empty RStudio window.
Nothing open yet — just the Console on the left and an empty Environment on the right.
Note Quarto Document and Quarto Presentation are separate entries. Today: Document.
RStudio gives you a template document. Headings look like headings; code chunks look like boxes.
The same file, shown as raw text. ## Quarto is a heading; ```{r} opens a chunk.
Visual
Source
Note
Everything in these slides is written in Source. When something goes wrong, Source is where you find out why.
Delete the sample text. Keep the YAML header, one heading, and one chunk.
Warning
Save before you render. An unsaved document has no folder, so relative paths like data/... have nothing to be relative to.
The tab now reads example.qmd, and the tooltip shows the Render shortcut: Shift+Cmd+K (Shift+Ctrl+K on Windows).
Plain prose between the chunks. This is the part that makes it a report and not a script.
Inside a chunk, # starts a comment — exactly as in any R script.
The green ▶ runs the chunk. Output appears inline, under the chunk, and in the Console.
The circled button inserts a new chunk — or press Option+Cmd+I (Alt+Ctrl+I on Windows). Learn this shortcut; you will use it constantly.
Prose, code, and output — one document, reproducible from source. That is the whole point.
format: html — what gets producedtoc: true — table of contentstoc-depth: 2 — how many heading levelstoc-title: — rename itYAML is whitespace-sensitive. Two spaces of indentation mean something; a tab breaks it.
toc-depth DoesThe same document, rendered three times. Only toc-depth changes.
toc-depth: 1
toc-depth: 2
toc-depth: 3
Each level deeper adds the next rank of headings — #, then ##, then ###. The default is 3.
This is how we include code in our documents.
Both the code and its output appear.
Only the output, with the code hidden.
Only the code, without running it.
Many times you will have seen annoying library messages:
To keep them out of the document, you should do:
---
title: "Statistical Analysis Report"
author: "Your Name"
date: "2024-11-05"
format: html
toc: true
toc-title: "Contents"
---
# Introduction
This is an example.
This is an equation: $E=mc^{2}$
```{r}
#| echo: true
#| eval: false
summary(mtcars)
```
```{r}
#| warning: false
#| message: false
library(dplyr)
```Run these once, in the Console — not in your document. One line at a time:
Warning
sf is the one that can fail. It needs GDAL, GEOS and PROJ underneath. On Mac and Windows the binary from CRAN includes them; on Linux install libgdal-dev, libgeos-dev and libproj-dev first.
The rest, in the order you will meet them:
install.packages("spData") # example world data (today)
install.packages("cowplot") # plot themes (today)
install.packages("ggspatial") # map layers and scale bars (today)
install.packages("patchwork") # plots side by side (Session 3)
install.packages("classInt") # choropleth class breaks (Session 3)
install.packages("viridis") # colour scales (Session 3)
install.packages("leaflet") # interactive maps (Session 3)
install.packages("terra") # rasters (Session 5)
install.packages("tidyterra") # rasters with ggplot (Session 5)
install.packages("exactextractr") # zonal statistics (Session 5)sf Is Worse Than dplyrIt reports the geometry type, the bounding box and the full CRS on every single read.
Important
You need both. quiet = TRUE silences sf’s own reporting; the chunk options silence R’s warnings and messages. They are different channels.
This is the part that is not in a normal Quarto tutorial.
A wide canvas. Mexico fills it.
A tall canvas. Same map, same code — but smaller, with space wasted.
embed-resources: The TrapYou build an interactive map. It works on your laptop. You email your reader the .html file on its own, the way you would send any attachment.
They see a blank white box.
An HTML file by default links to its JavaScript, CSS, and images, which sit in a _files folder next to it. Send the HTML alone and every link breaks.
This inlines everything into a single, larger, self-sufficient file.
Important
Set embed-resources: true, then send the .html file on its own. Nothing else needs to travel with it: no _files folder, no images. For anything you send to anyone this setting is not optional. We build a leaflet map in Session 3, which is usually when it bites.
echo and eval decide what the reader seeswarning and message keep package chatter out of a reportfig-width and fig-height set the canvas a map is drawn onembed-resources: true, then send the single .html filesf layer reads quietly with quiet = TRUE, and geom_sf() draws itPopescu Data Science II — Session 1: Quarto for Spatial Reporting