Reproducible Reports with Quarto

Applied Data Science - Session 3

Prof. Dr. Claudius Gräbner-Radkowitsch

Europa-Universität Flensburg

2026-09-28

Debrief

Last week

  • Recap R in the tidyverse style
  • How to analyse hotel pricing in Vienna via basic data transformations
  • There have been no questions from Moodle

Two weeks with no class — 5 and 12 October

Report 1 will not fill both — use them for recap.

Today’s ‘question’

You have the answer already

Four-star hotels, centre against 1–2 km out: €43 more per night.

  • Present results via reports or presentations - not R scripts or code.

How do you write it down so it is still right after the data changes?

Quarto addresses this challenge

  1. What a Quarto document is — header, text, chunks
  2. How the render is different to what happens in your console
  3. What possibilities that opens — numbers, references, citations
  4. Formats, and the errors you will meet

And at the end: Report 1.

What a Quarto document is

Three kinds of content

YAML header — settings for the whole document

Text — prose, in Markdown

Code chunks — R that runs when the document is built

Plus inline code — a computed value inside a sentence

---
title: "Hotel prices in Vienna"
format: html
---

## What we found

Four-star hotels in the centre cost more
than those one to two kilometres out.

```{r}
hotels <- read_csv("data/hotels-vienna.csv")
gap <- median(centre$price) - median(out$price)
```

The difference is `r gap` euros per night.

Starting one

  • File → New File → Quarto Document
  • See live demo for details

Where the file sits is important

Usually the project root is easiest, reports/ subdirectory for larger projects.

The YAML header

---
title: "The title of our work"
author: "Claudius Gräbner-Radkowitsch"
date: today
format:
  html:
    toc: true
    number-sections: true
execute:
  warning: false
  message: false
bibliography: references.bib
---
  • Indentation matters — spaces, never tabs
  • Full list of options

The text: Markdown

You already write it

You type You get
## Findings a section heading
**central** central
*roughly* roughly
- one
- two
a bulleted list
[Moodle](https://...) a link
`price` price — code, not prose

Best learned on the go — there is a command for everything.

The code: chunks

Making one

  • Ctrl/Cmd + Alt + I inserts one
#| label: chunk-anatomy
#| message: false
nrow(only_hotels)
[1] 253
  • Give it a label — you will thank yourself in the error panel

Chunk options

Option Effect
echo: false run it, show only the output
eval: false show it, do not run it
include: false run it, show nothing — the setup chunk
label: a name, needed for cross-references

Per chunk — or document-wide, in the YAML execute: block.

The setup chunk

Always first, always the same shape:

#| label: setup
#| include: false
library(tidyverse)
library(here)

hotels <- read_csv(here("data", "hotels-vienna.csv"))
  • Packages and data in one place

The render is not your console

Render starts a fresh R session

  • No objects. No loaded packages. Nothing from your current session.
  • No RStudio: no panes, no viewer, nobody to click
  • Your document renders all week — and fails on the new laptop

It always dependeds on your environment, never on the file.

So these never go in a chunk

View(hotels)              # nothing to show it on
install.packages("here")  # re-installs on every render
setwd("~/Desktop/ADS")    # invisible state
  • View() is for you, now — not for the document
    • To show data in the report: head(), or a flextable
  • Install packages in the console, once
  • Use relative paths and the here-package

The rules that follow

  1. Every package loaded in the document, with library()
  2. Every object created in the document
  3. No absolute paths, no setwd()
  4. Nothing interactive — no View(), no install.packages()

The test that catches it

Session → Restart R, then Render

Twenty seconds. The difference between reproduces and reproduced once.

Before every submission.

Where does R look for your data?

The most common reason a report dies

hotels <- read_csv("C:/Users/Anna/Desktop/Uni/ADS/data/hotels-vienna.csv")
  • Encodes your username, your OS, your September folder
  • Breaks on every other machine — including yours, next year

A relative path is relative to the document

applied-data-science/
├── applied-data-science.Rproj
├── data
|     └──hotels-vienna.csv
└── session03.qmd        ← "data/hotels-vienna.csv"  ✓
applied-data-science/
├── data/hotels-vienna.csv
└── R/
    └── session03.qmd      ← same line, now broken  ✗
  • Console → runs from the project root
  • Render → runs from the document’s folder
  • Same code, two answers

here()

library(here)

here()                             # the folder with your .Rproj
here("data", "hotels-vienna.csv")  # built from there

hotels <- read_csv(here("data", "hotels-vienna.csv"))

Relative to the project, not the document. Nothing machine-specific written down.

From today, the standard

Survives your .qmd moving into a subfolder. Report 1 asks for it.

Tell it where you are

One line, in your setup chunk, above everything else:

here::i_am("session03.qmd")   # or "reports/session03.qmd"
library(here)
  • here() otherwise guesses the root — and guesses silently
  • i_am() states it. No .Rproj needed.
  • Wrong project → it stops, and says so

First line of every document

Every file with paths. All semester. Report 1 included.

Wrong project, said out loud

Error:
! Could not find associated project in working
  directory or any parent directory.
- Path in project: reports/session03.qmd
- Current working directory: /Users/anna/Desktop

Compare the two paths. That is the whole diagnosis.

So where does the document live?

Your choice now — paths no longer depend on it.

  • One document? Project root. All three reports are this.
  • Several? A folder — reports/
  • Twelve .qmd in the root is a root you cannot read

Name it for the contents

You would not call data/ “readr”.

Ensuring consistency

Three weeks later

  • Number typed into paragraph one
  • Airport hotels still in the data
  • Fix the filter · re-run · paste the new table
  • Forget the sentence at the top
  • Any two copies of a number eventually disagree

The fix is not “be more careful”

Keep one copy. Let the document compute the rest.

A number in a sentence

Written badly:

We analysed 253 hotels in Vienna.

Written properly — same on the page, different in the source:

We analysed `r nrow(only_hotels)` hotels in Vienna.

We analysed 253 hotels in Vienna.

The house rule

Every number in your prose is inline R code

Not one typed digit. All semester, all three reports.

Referring to things

“As the chart below shows”

  • It may not be below — the layout decides, not you

Give it a name instead.

Label plus caption

#| label: fig-bands
#| fig-cap: "Four-star hotels: median price by distance band."
ggplot(four, aes(band, median_price)) +
  geom_col(fill = "#69AACD") +
  labs(x = NULL, y = "Median price (EUR)") +
  theme_classic()

@fig-bands in the text → a live, numbered reference: As Figure 1 shows…

Figure 1: Four-star hotels: median price by distance band.

Two rules

  • Label must start with fig- or tbl-
  • No caption, no number → no reference

Captions for a flextable

From #| tbl-cap:, never from flextable().

Citations

One key, formatted output

@book{bekes2021data,
  title     = {Data Analysis for Business, Economics, and Policy},
  author    = {Békés, Gábor and Kézdi, Gábor},
  year      = {2021},
  publisher = {Cambridge University Press}
}

Write [@bekes2021data] → (Békés and Kézdi 2021), plus a bibliography of only what you cited.

Google Scholar → the quotation-mark icon → BibTeX. Check what you paste.

Zotero and other bib managers export bib entries!

One source, many formats

The same .qmd, different format:

format: You get
html a web page — the default, and enough for Report 1
pdf a document for printing — needs LaTeX, once
docx Word, for the co-author who insists
revealjs these slides

Second entry → the Render button grows a dropdown.

Before you try PDF

quarto install tinytex in the terminal, once.

When it breaks

1 · Something is missing

Fehler: Objekt 'four_star' nicht gefunden
Ausführung angehalten

You built it in the console. The render has never seen it.

Restart R, render. Whatever breaks is what is missing from the file.

Base R speaks German, the tidyverse does not

Error: object 'four_star' not found — same error, English install.

2 · The file is not where you said

Error:
! 'data/hotels-vienna.csv' does not exist in
  current working directory:
  '/Users/anna/applied-data-science/R'.

The best error message you will get all semester — it prints where it looked.

Compare that folder with where the file is. Then i_am().

3 · The header will not parse

ERROR: Validation of YAML front matter failed.
ERROR: In file session03.qmd
(line 3, columns 1--7) Field "format" has empty value
2: title: "Where should we build?"
3: format:
         ~

It names the line and points a ~ at the spot. Look one line further in.

A tab instead of spaces says so explicitly: tab characters must not be used.

4 · Nothing failed, and it is still wrong

As ?fig-bands shows, the premium is concentrated …
  • Render succeeded. No error anywhere.
  • ? = the reference found nothing to point at
  • Missing caption, or a label without fig- / tbl-

The dangerous class of bug

Read the output, not just the render log.

Reading any of them

  • The line number is where R noticed — not where you broke it
  • The log names the chunk, if you labelled it
  • Read the first error only — three are usually one cause
  • Restart R between attempts, or you debug a stale session

Live coding

Exercise

The board briefing

  • One short report: where should we build?
  • Every number inline · one figure · one table, both cross-referenced
  • Cite the data

HTML is enough. PDF only if you already have LaTeX.

Report 1

Issued today

  • Individual · pass/fail · required for exam admission
  • Task sheet and data: Moodle, from today
  • Hand back: a zip of the project
  • It must reproduce on my machine
  • Due Sunday 18 October, 23:59
  • One revision across all three reports

Start it this week

Not because it is long — the first render elsewhere is the one that fails.

Until session 4

  • Report 1 — start early, submit via Moodle
  • Read R4DS ch. 28, “Quarto”
  • Optional: the messy import — a real German Excel export
  • Anything shaky so far? The two free weeks are the moment

Session 4: Git and GitHub — version control without the command line.