| Year | GDP per capita (US$) | Life expectancy |
|---|---|---|
| 2019 | 9,030 | 75.8 |
| 2020 | 7,074 | 74.5 |
| 2021 | 7,972 | 73.0 |
| 2022 | 9,281 | 74.9 |
| 2023 | 10,378 | 75.8 |
Lecture 11 - Quarto in Practice
quarto render builds a document; quarto preview keeps a live one openLast class you rendered one HTML page. Today:
.bib filefreeze: rendering without re-running everything| You type | You get |
|---|---|
**bold**, *italic* |
bold, italic |
~~scratch that~~ |
|
[text](url) |
a link |
 |
an image |
`code` |
code |
> quote |
a blockquote |
2^10^, H~2~O |
210, H2O |
footnote[^1] |
a numbered footnote |
$\mu = \frac{1}{n}\sum x_i$ inline, $$ ... $$ for display# Heading 1
This is a paragraph[^1].
## Heading 2
This is *italic*, this is `code`,
this is ~~strikethrough~~.
This is a [link](https://www.emory.edu).
Equation: $\mu = \frac{1}{n} \sum_{i=1}^{n} x_i$
List:
- Item 1
- Item 2
- Subitem 1
[^1]: This is a footnote.
| Header 1 | Header 2 | Header 3 |
|:---------|:--------:|---------:|
| Cell 1 | Cell 2 | Cell 3 |Heading 1
This is a paragraph1.
Heading 2
This is italic, this is code, this is strikethrough.
This is a link. Equation: \(\mu = \frac{1}{n} \sum_{i=1}^{n} x_i\)
List:
| Header 1 | Header 2 | Header 3 |
|---|---|---|
| Cell 1 | Cell 2 | Cell 3 |
.ipynb notebooks as they are--execute re-runs the code firstquarto check jupyter diagnoses it; the QUARTO_PYTHON variable fixes it.qmd is nicer to writeThe same notebook, rendered. More details here
quarto install tinytex)--execute to re-run them:.bib file is plain text: one entry per source, each with a citation key (here, nash1950equilibrium)@nash1950equilibrium → Nash (1950)[@nash1950equilibrium] → (Nash 1950)[@nash1950equilibrium, p. 48] → (Nash 1950, 48)csl: apa.csl (thousands of styles).bib file.bib files that stay in sync@A citation points outside your document; a cross-reference points inside it. Label the chunk, then use the label:
The last line renders as Rainfall peaks in March (Figure 1)
Tables take the label underneath, after a colon:
fig-, tbl-, eq-, sec-, lst-label: rainfall), the caption has no number@rainfall prints “(rainfall?)” with a citation warning@sec- also needs number-sections: true in the YAML[-@fig-rain] prints the bare number, for use inside bracketsSo never number by hand. A typed “Figure 3” is wrong once you add a Figure 2
practice.qmd in VS Codetitle, author, format: html, and bibliography: references.bib## heading, a paragraph, a bulleted list, and a small Markdown tableplt.plot) with these chunk options:
#| echo: true and #| eval: true#| fig-cap: "Your caption here"#| label: fig-myplot@fig-myplotreferences.bib file with one BibTeX entry (grab one from Google Scholar)@keyChunk options are on last class’s table. @fig- references point at fig- labels
pandas release changed one defaultRendering re-computes: every render re-runs every chunk, changed or not
Your document did not change. Its surroundings did:
A package upgrade changes a default
An API returns today’s data instead of October’s
A random draw with no seed
Code that reads the clock or today’s date
A different machine with different versions
We want controlled re-execution: code re-runs only when the source changes
freeze: re-run only when the source changesPut this in _quarto.yml for a project:
freeze only works inside a project, when you run quarto render with no file namequarto render report.qmd always re-runs the code, frozen or not_freeze/freeze: auto: new code, new results. No change, same resultsfreeze: true: never re-run. For archival work, like a submitted paperfreeze: false: the default, always re-run_freeze/, so whoever clones your repository gets your numbersfreeze does and does not doWhat it does
What it does not do
_freeze/pandas to the version you testedSo freeze postpones the problem. Module 08 pins the environment with uv and containers. Until then, use freeze: auto, commit _freeze/, and list your versions in the README
.qmd can become a PDF handoutThe YAML sets the format; headings do the rest:
# starts a section, ## starts a new slideembed-resources: true puts images and fonts into one self-contained file::: fenced divs handle layout: columns, centred text, font sizesInstall the course template with:
Try on your own:
simple-slides.qmd and render ittheme: moon, theme: serif):::{.columns}{.smaller} class to a slide with a lot of textBoth are free:
| Method | How it works | When to use |
|---|---|---|
| GitHub Pages | Enable in repo settings, serves from a branch | Permanent hosting, custom domain |
| Githack | Paste the GitHub link to any .html file |
Quick sharing, no setup |
You met GitHub Pages in module 02. With Githack, push your HTML, paste its URL at raw.githack.com and share the link
Every Quarto website has the same files:
| File | Purpose |
|---|---|
_quarto.yml |
Site config: title, navigation, theme |
index.qmd |
Home page (required) |
*.qmd |
Other pages: about, posts, docs |
styles.css |
CSS overrides (optional) |
.qmd becomes a page, with navigation, footer and theme from _quarto.yml_quarto.yml_quarto.yml and index.qmdproject:
type: website
output-dir: docs
website:
title: "DATASCI 350"
repo-url: https://github.com/danilofreire/datasci350
navbar:
left:
- href: syllabus-web.qmd
text: Syllabus
- href: lectures.qmd
text: Lectures
- href: assignments.qmd
text: Assignments
page-footer:
left: "Copyright 2026, Danilo Freire."
execute:
freeze: auto
format:
html:
theme:
light: cosmo
dark: darkly
toc: trueQuarto publishes to GitHub Pages with one command:
gh-pages branchmain, free of rendered HTMLhttps://username.github.io/repo-name/output-dir: docs, render, push, and choose main → /docs in the Pages settings. The course site works this way.qmd and run the command againparameters-P:-P does nothingreport.qmd---
title: "Country profile"
format: html
jupyter: python3
---
```{python}
#| tags: [parameters]
country = "Brazil"
```
```{python}
#| echo: false
import pandas as pd
import matplotlib.pyplot as plt
profiles = pd.read_csv("data/country_profiles.csv")
one = profiles[profiles["country"] == country]
one = one.sort_values("year")
```
# `{python} country`
This report uses indicators for `{python} country`.
## Life expectancy over time
```{python}
#| echo: false
fig, ax = plt.subplots(figsize=(7, 3.5))
ax.plot(one["year"], one["life_expectancy"])
plt.show()
```data/country_profiles.csv`{python} country` is inline code: it puts a Python value into your text-P, and the document followsRendered with the default, country = "Brazil":
| Year | GDP per capita (US$) | Life expectancy |
|---|---|---|
| 2019 | 9,030 | 75.8 |
| 2020 | 7,074 | 74.5 |
| 2021 | 7,972 | 73.0 |
| 2022 | 9,281 | 74.9 |
| 2023 | 10,378 | 75.8 |

Two of the ten countries. The report draws one, chosen by the parameter
One country, with its own file name:
Or all of them, with the shell loop from module 02:
Terminal
Three renders, three files:
"$c": two of the ten names contain a space--output, every render overwrites report.htmlYour final project has this shape: one repository, one analysis, many countries
Download the report and run it from the terminal.
report.qmd and country_profiles.csvreport.qmd in a new folder. Put the CSV in a data folder beside itOr download both from the terminal:
Terminal
Hints:
-P, and it takes name:value--output, your second render writes over the firstThree errors you will see this term:
Terminal
l.172 is a line in the generated .tex, not your .qmdWhich Python does Quarto run? Ask it:
Terminal
Compare that path with which python3. If they differ, that is your error. Fixes:
Terminal
ModuleNotFoundError for a package you installedQUARTO_PYTHON, or else python3 on your PATHjupyter:, or one Quarto picksjupyter kernelspec list shows your kernels. Add the current environment with:In VS Code, the Render button uses the interpreter chosen with Python: Select Interpreter, not the one active in your terminal
You can now build:
_freeze/ folder that keeps your results until you change themquarto publish gh-pagesAnd why each matters:
freeze: auto separates “I changed the code” from “the world changed”@ references number everything for you_quarto.ymlYour final project uses this toolkit. Module 06 adds scripted data collection, and module 08 pins the environment
ollama pull llama3.2:1b (1.3 GB). The classroom wifi cannot handle 25 downloads at once-PThe complete practice.qmd:
---
title: "My Quarto Document"
subtitle: "A simple example"
author: "Danilo Freire"
date: "2026-09-30"
format: html
bibliography: references.bib
---
## Introduction
This is a simple Quarto document.
As @nash1950equilibrium showed, games have equilibria.
This is @fig-sine.
- One bullet
- Another bullet
| Tool | Use |
|--------|-----------------|
| Quarto | Documents |
| Git | Version control |
```{python}
#| echo: true
#| eval: true
#| fig-cap: "Sine function"
#| label: fig-sine
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y = np.sin(x)
plt.plot(x, y)
plt.xlabel("x")
plt.ylabel("sin(x)")
plt.show()
```Render with:
The rendered output:
Key points:
#| label: fig-sine gives the figure a cross-reference label@fig-sine in the text creates a clickable link to itbibliography: references.bib tells Quarto where to find BibTeX entries@key cites from the .bib file; the reference list is added automatically at the endYour folder should look like this before you render anything:
Steps 3 to 6, in order:
Notice:
report.html for Brazil, the default in the tagged cell--output, the Japan render would have overwritten the Brazil oneSouth Africa needs quotes. Unquoted, the shell splits the name, the filter matches nothing, and the render stops with a ValueErrorYou never edited the report. You changed the input, which is the point of a parameter
To go further, change the default from Brazil to India and render with no options