
Writing Your Thesis with quarto-UHHthesis
Source:vignettes/quarto-writing-guide-en.Rmd
quarto-writing-guide-en.RmdThis guide covers everything you need to know about writing your thesis with Quarto and the UHHthesis template. It assumes you have already installed the template and configured your metadata (see the Getting Started guide).
Markdown Basics
Quarto files (.qmd) use Markdown for text formatting. If
you are new to Markdown, here is a quick reference for the most common
elements.
Links
For a more complete Markdown reference, see the Quarto Markdown Basics documentation.
Sections and headings
Use Markdown headings for thesis sections:
# Chapter Title (level 1 -- e.g., Introduction, Methods)
## Section (level 2 -- e.g., Study Site)
### Subsection (level 3 -- e.g., Sampling Design)
#### Sub-subsection (level 4)All levels up to ### appear in the table of contents by
default (toc-depth: 3).
To create a section without a number (e.g., for the
References heading), add {.unnumbered}:
This is already used in the template for the abstract, abbreviations, and back matter sections.
Cross-references
Cross-references are a key feature for academic writing. Quarto uses
the @ prefix with type-specific labels.
Figures:
Figure labels must start with fig-. The label is set
either in the chunk option (#| label: fig-location) or in
the image syntax ({#fig-location}).
Tables:
Table labels must start with tbl-.
Equations:
Equation labels must start with eq-.
Sections:
For section cross-references, simply put the section title in square brackets.
Important: Label names should use hyphens (not underscores) to separate words, e.g.,
fig-base-fignotfig_base_fig. Underscores will break cross-references.
Note: Only figures and tables with a caption can be numbered and cross-referenced. If a figure or table has no caption, it will not receive a number.
Citations and bibliography
How it works
The UHHthesis template uses BibTeX for managing
references. You store your references in
bib/references.bib, and Pandoc’s built-in citation
processor (citeproc) automatically formats them
according to the citation style defined in _quarto.yml (via
the .csl file).
The reference list is placed automatically where the file
chapter/96-references.qmd appears in the chapter order. You
do not need to write anything in this file — it works
automatically.
BibTeX entry format
Each reference in references.bib looks like this:
@article{May1976,
author = {May, R. M.},
title = {Simple mathematical models with very complicated dynamics},
journal = {Nature},
volume = {261},
number = {5560},
pages = {459-467},
year = {1976},
doi = {10.1038/261459a0}
}The first field after the opening brace (May1976) is the
citation key — this is what you use to cite the
reference in your text.
Common entry types: @article, @book,
@inproceedings, @phdthesis,
@techreport, @manual, @misc.
Citation syntax
| Markdown | Output | Use case |
|---|---|---|
@May1976 |
May (1976) | Author as part of the sentence |
[@May1976] |
(May, 1976) | Parenthetical citation |
[-@May1976] |
(1976) | Suppress the author name |
[@May1976; @RN410] |
(May, 1976; Post and Forchhammer, 2002) | Multiple citations |
[@May1976, p. 461] |
(May, 1976, p. 461) | Citation with page number |
Example in running text:
Changing the citation style
The citation formatting is controlled by the .csl file
specified in _quarto.yml. The default is SAGE Harvard
style. To use a different style:
Find your desired style at https://www.zotero.org/styles or https://github.com/citation-style-language/styles
Download the
.cslfile and place it in thebib/folder-
Update
_quarto.yml:
Reference managers
Using a reference manager saves significant time. Recommended options:
-
Zotero (free, open source) — https://www.zotero.org/
- Install the Better BibTeX
plugin to automatically export and sync your library to a
.bibfile. - Zotero can import references directly from your browser with one click.
- Install the Better BibTeX
plugin to automatically export and sync your library to a
-
RStudio Visual Editor — RStudio’s visual editing
mode has a built-in citation tool. Switch to visual mode (click the
“Visual” button at the top of the editor), then use Insert >
Citation to search and insert references from your
.bibfile, DOI lookup, or a connected Zotero library.
Citing R and packages
At the end of your Material and Methods chapter, you should cite R and all packages you used. Use inline R code to insert version numbers dynamically:
All analyses were performed using the statistical software R
(version 4.5.2)
[@R-base]. Tables were generated using the packages 'knitr'
(version 1.51) [@R-knitr], 'kableExtra'
(version 1.4.0) [@R-kableExtra], and
'flextable' (version 0.9.10) [@R-flextable].
Figures were produced with 'ggplot2'
(version 4.0.1) [@R-ggplot2].To generate the BibTeX entries for your R packages automatically, add
a code chunk in your methods chapter (or in index.qmd):
```r
#| label: generate-package-refs-en
#| include: false
knitr::write_bib(
c("base", "knitr", "kableExtra", "flextable", "ggplot2"),
file = "bib/packages.bib"
)
```Then make sure both .bib files are listed in
_quarto.yml:
Important: When you add a new package to your analysis, also add it to the
knitr::write_bib()call so that its citation entry is created automatically.
Images
Insert external images using Markdown syntax. Add a caption and a label for cross-referencing:
- The caption goes inside
![...]. - The label
{#fig-location}enables cross-referencing with@fig-location. -
width="50%"scales the image to half the page width.
Note: Images must have a caption to be numbered and cross-referenced.
R-generated figures
Figures produced by R code are placed inside code chunks with
label and fig-cap options.
Scatter plot with ggplot2:
```r
#| label: fig-scatter
#| fig-cap: "Relationship between horsepower and fuel economy."
#| out-width: "100%"
library(ggplot2)
ggplot(mtcars, aes(x = hp, y = mpg)) +
geom_point() +
geom_smooth(method = "lm", col = "red", se = FALSE) +
labs(x = "Gross Horsepower", y = "Miles Per Gallon") +
theme_minimal()
```Boxplot with ggplot2:
```r
#| label: fig-boxplot
#| fig-cap: "Fuel economy differences between transmission types."
#| out-width: "60%"
#| fig-height: 3
library(ggplot2)
ggplot(mtcars, aes(x = factor(am, labels = c("Automatic", "Manual")), y = mpg)) +
geom_boxplot(fill = "steelblue", alpha = 0.7) +
labs(x = "Transmission", y = "Miles Per Gallon") +
theme_minimal()
```Tables
There are several ways to create tables. This section covers the most common approaches that work well with this template’s dual PDF/DOCX output.
Markdown tables
Write tables directly in Markdown. Add a caption below the table with
: caption and a label in curly brackets:
| Column A | Column B | Column C |
|:-------------|:----------------:|---------------:|
| left-aligned | center-aligned | right-aligned |
| $123 | $456 | $789 |
: This is a Markdown table. {#tbl-md}Reference with @tbl-md. Markdown tables work well for
simple, hand-written tables but become cumbersome for larger
datasets.
Tables with knitr and kableExtra
For tables generated from R data, use knitr::kable()
with the chunk option tbl-cap:
```r
#| label: tbl-kable1
#| tbl-cap: "This table was produced with knitr."
library(knitr)
library(kableExtra)
df <- mtcars[1:5, 1:6]
if (knitr::is_latex_output()) {
kable(df, booktabs = TRUE) |>
kable_styling(font_size = 9, latex_options = "hold_position")
} else {
kable(df, longtable = TRUE, booktabs = TRUE)
}
```The if/else block ensures appropriate formatting for
both PDF and DOCX output. PDF uses LaTeX-specific options from
kableExtra, while DOCX uses the simpler default format.
You can add grouped headers, striped rows, and footnotes:
```r
#| label: tbl-kable2
#| tbl-cap: "Motor car data with grouped column headers."
library(knitr)
library(kableExtra)
df <- mtcars[1:5, 1:6]
if (knitr::is_latex_output()) {
kable(df, booktabs = TRUE) |>
kable_styling(position = "center", font_size = 9) |>
add_header_above(c(" " = 1, "Performance" = 2, "Design" = 2, "Weight" = 1)) |>
footnote(general = "Data source: mtcars dataset.")
} else {
kable(df, longtable = TRUE, booktabs = TRUE) |>
add_header_above(c(" " = 1, "Performance" = 2, "Design" = 2, "Weight" = 1))
}
```When to use: Well-established, widely documented. A good default choice if you are already familiar with it.
Tables with flextable
The flextable package produces identical-looking tables in both PDF and DOCX without any conditional logic. This makes it the most convenient option for this template’s dual-output workflow.
Install it once:
install.packages("flextable")Basic example:
```r
#| label: tbl-flex1
#| tbl-cap: "This table was produced with flextable."
library(flextable)
df <- mtcars[1:5, 1:6]
flextable(df) |>
theme_booktabs() |>
autofit()
```Customised example with formatting:
```r
#| label: tbl-flex2
#| tbl-cap: "Summary statistics by cylinder count."
library(flextable)
library(dplyr)
summary_df <- mtcars |>
group_by(cyl) |>
summarise(
n = n(),
mean_mpg = round(mean(mpg), 1),
sd_mpg = round(sd(mpg), 1),
mean_hp = round(mean(hp), 1)
)
flextable(summary_df) |>
set_header_labels(
cyl = "Cylinders",
n = "N",
mean_mpg = "Mean MPG",
sd_mpg = "SD MPG",
mean_hp = "Mean HP"
) |>
theme_booktabs() |>
autofit() |>
align(align = "center", part = "all") |>
font(fontname = "Times New Roman", part = "all") |>
fontsize(size = 9, part = "all")
```Key flextable features:
- No conditional logic needed — the same code produces consistent output in PDF and DOCX.
-
theme_booktabs()gives a clean academic look (similar to LaTeX booktabs). -
autofit()adjusts column widths automatically. - Full control over fonts, alignment, borders, conditional formatting, merged cells, and footnotes.
- Supports grouped headers, multi-row spanning, and complex layouts.
Tip: See the flextable book for a comprehensive guide with many examples.
Tables with gt
The gt package provides a modern, expressive grammar for building tables. DOCX support has been added more recently and is now functional for most use cases.
```r
#| label: tbl-gt1
#| tbl-cap: "This table was produced with gt."
library(gt)
df <- mtcars[1:5, 1:6]
gt(df, rownames_to_stub = TRUE) |>
tab_options(
table.font.size = px(12)
)
```When to use: If you prefer a tidyverse-style API and want advanced features like sparklines, colour scales, or inline plots. Note that some advanced formatting options may render differently between PDF and DOCX.
Which package should I use?
| Package | DOCX | Same code for both? | Best for | |
|---|---|---|---|---|
| Markdown | ✓ | ✓ | ✓ | Small, hand-written tables |
| kable/kableExtra | ✓ | ✓ | ✗ (needs if/else) |
Familiar workflow, many online examples |
| flextable | ✓ | ✓ | ✓ | Best for dual PDF/DOCX output |
| gt | ✓ | ✓ | mostly | Modern API, rich formatting |
Recommendation: For this template,
flextable is the most convenient choice because it
produces consistent output in both formats without any conditional code.
If you are already comfortable with kable/kableExtra, that works well
too — just remember to use the if/else block shown
above.
Mathematical equations
Inline math — use single dollar signs:
Display math — use double dollar signs:
Numbered equations with labels — add
{#eq-label} after the closing $$:
Reference with @eq-mean. Only number equations that are
referenced in the text.
More examples:
Important: Do not leave a space between the
$and the mathematical notation.
Chemical formulas
Use LaTeX math mode with \mathrm{} to prevent italic
typesetting:
- Water: $\mathrm{H_2O}$
- Carbon dioxide: $\mathrm{CO_2}$
- Methane: $\mathrm{CH_4}$
- Chromite: $\mathrm{Fe_2^{2+}Cr_2O_4}$Useful symbols for chemistry
| Symbol | Markdown | Example |
|---|---|---|
| Subscript | $\mathrm{CH_4}$ |
CH₄ |
| Superscript (charge) | $\mathrm{O^-}$ |
O⁻ |
| Reaction arrow | $\longrightarrow$ |
→ |
| Reversible arrow | $\rightleftharpoons$ |
⇌ |
| Resonance arrow | $\leftrightarrow$ |
↔︎ |
| Delta | $\Delta$ |
Δ |
| Bullet (hydrate) | $\bullet$ |
• |
Inline R code
You can embed R expressions directly in text to insert computed values:
This is particularly useful in the Material and Methods chapter for citing software versions automatically (see Citing R and packages).
Note: For inline R code to work, the
.qmdfile must contain at least one R code chunk (even a hidden one), so that Quarto uses knitr as the computation engine. The template already includes the necessary setup chunks.
Code chunks and their options
Code chunks use the ```{r} fence with YAML-style options
prefixed by #|:
```r
#| label: fig-my-plot
#| fig-cap: "A descriptive caption."
#| echo: false
#| warning: false
#| out-width: "80%"
plot(1:10)
```Commonly used chunk options:
| Option | Description | Default |
|---|---|---|
label |
Unique chunk identifier | — |
echo |
Show the R code in output | false |
eval |
Execute the code | true |
warning |
Show warnings | false |
message |
Show messages | false |
include |
Include chunk output at all | true |
cache |
Cache results to speed up re-rendering | false |
fig-cap |
Figure caption | — |
tbl-cap |
Table caption | — |
out-width |
Output width | — |
results |
How to treat results ("asis" for raw
output) |
— |
The defaults for echo, warning, and
message are set globally in _quarto.yml under
execute:, so you generally don’t need to repeat them in
every chunk.