Prof. Marc Los Huertos • Pomona College
What is Rmd? Anatomy YAML Header Markdown Prose Code Chunks Chunk Options Inline R The Setup Chunk Images Citations Rendering Troubleshooting
What this module covers. An R Markdown file (
.Rmd) weaves prose, code, and output into a single reproducible document. When you click Knit, knitr runs every chunk, captures its output, and pandoc converts everything to HTML, PDF, or Word. This module walks through every part of an Rmd file from scratch — YAML headers, markdown syntax, chunk options, inline R, and the rendering pipeline — so you understand not just what to write but why it works.
A plain .R script runs code and prints results to the
Console. A .Rmd file does the same thing, but also lets you
write formatted prose around that code — headings, paragraphs,
bullet lists, equations — and produce a polished output document that a
reader who has never opened RStudio can read.
The three technologies involved are:
| Layer | Tool | Role |
|---|---|---|
| Text markup | Markdown | Headings, bold, lists, links, equations |
| Code execution | knitr | Runs R chunks, captures output and plots |
| Document conversion | pandoc | Converts the combined result to HTML/PDF/Word |
You never call pandoc or knitr directly. Clicking
Knit (or running rmarkdown::render())
triggers all three in sequence.
💡 Create your first Rmd now In RStudio: File → New File → R Markdown…. Choose HTML output. RStudio generates a template with all three sections already present — read it, then delete everything below the setup chunk and start fresh.
Every Rmd file has exactly three kinds of content, always in this order at the top:
{r setup, include=FALSE} knitr::opts_chunk$set(echo = TRUE, warning = FALSE)
{r my-analysis} x <- c(1, 4, 9, 16, 25) mean(x)
These three elements — YAML, chunks, and prose — can appear in any order after the header, interleaved as many times as needed. The YAML block must be the very first thing in the file.
The YAML header controls the document’s metadata and output format.
It is delimited by triple-dashes (---) and must appear at
the very top of the file, before any other content.
---
title: "Air Quality Analysis"
author: "Marc Los Huertos"
date: "2024-03-15"
output: html_document
---
Hard-coding the date means it goes stale. Use inline R instead so the date updates every time you knit:
date: "Compiled `r format(Sys.Date(), '%Y-%m-%d')`"
The output: field determines what pandoc produces. The
most common options:
| output value | Produces | Requires |
|---|---|---|
html_document |
Self-contained HTML file | nothing extra |
pdf_document |
PDF via LaTeX | a LaTeX installation (TinyTeX) |
word_document |
.docx Word file |
nothing extra |
github_document |
Markdown for GitHub | nothing extra |
output:
html_document:
toc: true # table of contents
toc_float: true # floating sidebar TOC
toc_depth: 3 # include h1, h2, h3 headings
number_sections: true # auto-number headings
theme: flatly # Bootswatch CSS theme
highlight: tango # syntax highlighting style
self_contained: true # embed all CSS/JS — one portable file
df_print: paged # paginated data frames
code_folding: hide # show "Code" buttons, hide by default
⚠️ YAML is whitespace-sensitive Indentation in YAML
is exactly two spaces — not tabs, not four spaces. A misaligned
line causes a cryptic parse error and the document will not knit. If you
see Error in yaml::yaml.load(), the problem is almost
always indentation or a missing colon.
knit: functionThe modules in this course use a custom knit: field to
redirect the output HTML to a specific folder. This is what lets the
knit button send the file directly to the docs/ folder
without any manual copying:
knit: (function(inputFile, encoding) {
rmarkdown::render(
inputFile,
encoding = encoding,
output_file = file.path(dirname(inputFile),
"../docs/RGuides/02_RMarkdown_knitr.html")
)
})
Without this, clicking Knit places the HTML in the same folder as the
Rmd. The file.path(dirname(inputFile), "../docs/...")
pattern navigates relative to the Rmd’s location — so the path works on
any machine regardless of the absolute path to the project.
📁 dirname() and relative paths
dirname(inputFile) returns the folder the Rmd lives in.
“../docs/RGuides/…” then navigates one level up
(..) and into docs/RGuides/. This means the
Rmd and the docs folder must be siblings — both children of the same
project root — for the path to resolve correctly.
Between and around chunks, you write plain text with lightweight markdown formatting. Pandoc converts this to HTML or whatever output format you chose.
# Level 1 heading (one #)
## Level 2 heading (two ##)
### Level 3 heading (three ###)
Headings also create anchor links. Adding {#my-id} after
the heading text lets you link to it:
## Results {#results}
See the [Results section](#results) for details.
**bold text**
*italic text*
`inline code` — use for function names, variable names, file paths
- unordered list item
- another item
- nested item (two spaces of indent)
1. ordered list item
2. second item
[link text](https://example.com)
> A blockquote — useful for key questions or callouts.
--- (three dashes = horizontal rule)
| Column A | Column B | Column C |
|----------|----------|----------|
| value 1 | value 2 | value 3 |
| value 4 | value 5 | value 6 |
The colons in the separator row control alignment:
| Left | Center | Right |
|:---------|:--------:|---------:|
| text | text | text |
💡 For data frames, use knitr::kable() instead Never
type a markdown table by hand for data. Use
knitr::kable(df) or kableExtra — it generates
the table automatically from your data so it updates when the data
changes.
R Markdown supports LaTeX math using $ for inline and
$$ for display:
The mean is $\bar{x} = \frac{1}{n} \sum_{i=1}^{n} x_i$.
$$
\text{PM}_{2.5} = \beta_0 + \beta_1 T + \varepsilon
$$
Renders as:
The mean is \(\bar{x} = \frac{1}{n} \sum_{i=1}^{n} x_i\).
A code chunk is a fenced block that knitr executes. The output — printed values, tables, plots — is inserted into the document immediately below the chunk.
Every chunk has the same structure:
```{r chunk-label, option1 = value, option2 = value}
# your R code here
x <- 1 + 1
x
```
```{r —
three backticks, open brace, the letter r, a space, then
the label.``` —
three backticks, nothing else.Three ways:
Ctrl+Alt+I
(Windows/Linux) or Cmd+Option+I (Mac)Whatever R would print to the Console also appears in the document:
# Expressions that print their result automatically
42
## [1] 42
c(1, 2, 3)
## [1] 1 2 3
summary(c(2.1, 3.4, 2.8, 4.1, 3.9))
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 2.10 2.80 3.40 3.26 3.90 4.10
Assignments do not print unless you explicitly print the object or wrap in parentheses:
x <- 10 # silent — nothing appears below this line
x # now it prints
## [1] 10
(y <- 20) # wrapping assignment in () also prints
## [1] 20
Any plot created inside a chunk is captured and embedded in the document:
distance_m <- c(10, 25, 50, 100, 200, 400)
pm25_ug_m3 <- c(38, 29, 21, 15, 11, 8)
plot(distance_m, pm25_ug_m3,
xlab = "Distance from highway (m)",
ylab = expression(PM[2.5] ~ (µg/m^3)),
pch = 19, col = "#4a7c5e",
main = "PM2.5 vs Distance from Source")
lines(distance_m, pm25_ug_m3, col = "#4a7c5e", lwd = 1.5)
Particulate matter decreases with distance from the highway.
Chunk options control what knitr does with each chunk: whether to
show the code, whether to run it, how large to make the figure. They go
inside the {r label, ...} header, separated by commas.
FALSE hides code but
still runs it and shows output.
FALSE shows code as a formatted block but
does not execute it.
FALSE runs the chunk
silently — code and output both hidden. Use for setup chunks.
message() output? Set FALSE to suppress
library loading messages.
FALSE to suppress, but check warnings
interactively first — never hide problems you haven’t understood.
FALSE means an error stops the knit. Set
TRUE to show the error in the output and continue knitting
— useful in teaching documents.
fig.height to control aspect ratio.
“100%” to fill
the column, or a percentage to shrink it.
‘hide’ suppresses printed output. ‘asis’
passes raw HTML/LaTeX through (for kable). ‘hold’ collects
all output and prints at the end of the chunk.
Rather than listing chunk headers in a code block (which knitr would try to parse), here is a reference table of the most useful combinations:
| Goal | Options to set |
|---|---|
| Show code and output (default) | nothing — this is the default |
| Show output only, hide code | echo = FALSE |
| Show code only, don’t run | eval = FALSE |
| Run silently, show nothing | include = FALSE |
| Show plot only, hide code and messages | echo = FALSE, message = FALSE |
| Show error in output without stopping knit | error = TRUE |
| Show figure with caption at a specific size | fig.cap = "...", fig.width = 6, fig.height = 4 |
Each option goes inside the chunk header after the label, separated by commas:
# Example: a results table — output only, no code shown
# ```{r results-table, echo=FALSE}
# Example: install instructions — show code but never run
# ```{r install-packages, eval=FALSE}
# Example: setup — run silently, nothing in output
# ```{r setup, include=FALSE}
The next three chunks are identical code but with different options — compare what appears in the rendered output:
# echo=TRUE (default) — you see this code AND the output below
sqrt(144)
## [1] 12
## [1] 13
# results='hide' — code appears, output is suppressed
sqrt(196)
fig.show — controlling multi-plot chunksWhen a chunk produces more than one plot, fig.show
controls whether they share a figure environment or each get their
own:
```{r two-plots, fig.show='hold', fig.cap="Both plots side by side."}
# hold — both plots collected and placed together in one figure
hist(rnorm(200))
hist(rexp(200))
```
``` r
# asis (default) — each plot placed immediately where it is produced
hist(rnorm(200))
```
First plot.
``` r
hist(rexp(200))
```
Second plot.
Note the fig.cap as a character vector
— when fig.show = 'asis' produces multiple figures from one
chunk, supply a caption per plot:
{r figcap-vector-demo, fig.show='hold', fig.width=3.5, fig.height=3, fig.cap=c("PM2.5 — roughly normal.", "PM10 — right-skewed.")} set.seed(1) hist(rnorm(300, mean = 12, sd = 4), main = "PM2.5", xlab = "µg/m³", col = "#4a7c5e", border = NA) hist(rexp(300, rate = 0.08), main = "PM10", xlab = "µg/m³", col = "#c8832a", border = NA)
ref.label — reusing a chunk without repeating coderef.label runs a previous chunk again without copying
its code. This is useful when you want to show code in one place and
output in another, or produce the same plot at two different sizes:
```{r my-plot, echo=TRUE, fig.show='hide'}
# Define and show the code here — suppress the figure with fig.show='hide'
plot(1:10, (1:10)^2, pch = 19, col = "#4a7c5e",
xlab = "x", ylab = expression(x^2))
```
Some prose explaining the plot...
results = 'asis' — passing raw HTML to the outputThe default results = 'markup' wraps printed output in a
code block. results = 'asis' passes the output directly
into the document as raw HTML or markdown — required any time you
generate tables or headings programmatically:
# knitr::kable() generates an HTML table — needs results='asis' to render
# Without it, you'd see raw HTML tags as plain text
knitr::kable(
data.frame(
Site = c("Kern", "Mojave", "Coast"),
PM2.5 = c(12.1, 8.4, 18.0),
n = c(5L, 4L, 6L)
),
caption = "Summary table generated inside a chunk."
)
| Site | PM2.5 | n |
|---|---|---|
| Kern | 12.1 | 5 |
| Mojave | 8.4 | 4 |
| Coast | 18.0 | 6 |
⚠️ kable() inside a for loop requires results=‘asis’
If you loop over groups and call knitr::kable() inside the
loop, you must set results=‘asis’ on that chunk or
the tables will appear as raw HTML text. The same applies to any
function that emits raw HTML — kableExtra, gt,
DT::datatable().
Inline R lets you embed a computed value directly in a sentence, so
the number updates automatically every time you knit. The syntax is a
single backtick, the letter r, a space, an R expression,
and a closing backtick:
The mean PM2.5 was `r round(mean(pm25_week), 1)` µg/m³ across the study period.
Anything that evaluates to a single printable value works:
arithmetic, function calls, object lookups, format() calls
for formatting.
The source text below contains inline R — look at the rendered output:
Source:
We monitored PM2.5 at 7 sites between
March 04 and March 10, 2024.
The weekly mean was 14.3 µg/m³
(median: 9.7 µg/m³;
max: 42.3 µg/m³ on Thursday).
Renders as:
We monitored PM2.5 at 7 sites between March 04 and March 10, 2024. The weekly mean was 14.3 µg/m³ (median: 9.7 µg/m³; max: 42.3 µg/m³ on Thursday).
🔗 Why inline R matters for reproducibility If you type a number directly into prose — “the mean was 14.3 µg/m³” — and later discover a data error and rerun the analysis, the number in the prose stays wrong while your table updates. Inline R ensures the prose number is always derived from the same computation as everything else.
x <- 12345.6789
# Too many decimals for prose
x
## [1] 12345.68
# Rounded
round(x, 2)
## [1] 12345.68
# Formatted with thousands separator
format(x, big.mark = ",", nsmall = 2)
## [1] "12,345.68"
# Scientific notation suppressed
format(1.23e-5, scientific = FALSE, digits = 4)
## [1] "0.0000123"
# Percentage
paste0(round(0.734 * 100, 1), "%")
## [1] "73.4%"
⚠️ Keep inline R expressions short Inline R is great
for round(mean(x), 1). It is not meant for multi-step
calculations. Compute your value in a chunk first, store it in a named
object, then reference that object inline. Debugging a broken inline
expression is much harder than debugging a broken chunk.
Every Rmd should begin with a setup chunk immediately after the YAML header. It does three things: sets global chunk options, loads all packages, and optionally loads data.
```{r setup, include=FALSE}
# 1. Global chunk options — apply to every chunk unless overridden locally
knitr::opts_chunk$set(
echo = TRUE, # show code by default
warning = FALSE, # suppress warnings globally
message = FALSE, # suppress package-load messages
fig.width = 7, # default figure width (inches)
fig.height = 4 # default figure height (inches)
)
# 2. Load all packages here — never scatter library() calls through the doc
library(tidyverse)
library(lubridate)
library(knitr)
library(kableExtra)
# 3. Optionally load data here so it is available to all later chunks
# df <- read_csv("data/field_data.csv")
```
The label setup is special — knitr always runs this
chunk first, regardless of where it appears in the file. The option
include=FALSE means none of this appears in the output: no
code, no messages, no output.
If library(ggplot2) is inside chunk 7 and the document
fails during knit at chunk 5, you may spend time wondering why ggplot2
“isn’t loaded” — when the real error is earlier and ggplot2 never got a
chance to load. A single setup chunk makes the dependency list visible
and ensures it runs first.
A local option on a single chunk overrides the
global default from opts_chunk$set(). Use this to make a
specific chunk behave differently without changing all chunks:
There are two ways to embed an image: the plain markdown syntax for
simple cases, and knitr::include_graphics() for anything
that needs chunk options (sizing, captions, cross-references).

{width=70%}
The path is relative to the Rmd file’s location.
{width=70%} is a pandoc attribute that scales the image in
HTML output. This approach is fine for decorative images but gives you
no chunk-level control.
knitr::include_graphics() — the preferred approach```{r site-map, echo=FALSE, fig.cap="Sensor deployment locations, Spring 2024.",
out.width="80%", fig.align="center"}
knitr::include_graphics("figures/site_map.png")
```
Use out.width (not fig.width) for images
loaded from disk — fig.width controls the size of
generated R plots; out.width controls the display
size of any figure in the output HTML.
The path is always relative to the Rmd file. If your project looks like:
project/
reports/
my_analysis.Rmd ← Rmd lives here
figures/
site_map.png
data/
field_data.csv
Then the correct path inside the Rmd is
"../figures/site_map.png" — one level up (..),
then into figures/. The same logic applies to data
files.
# Rmd is in reports/; figure is in figures/ at the project root
knitr::include_graphics("../figures/site_map.png")
# If figures/ is a subfolder of the same folder as the Rmd:
knitr::include_graphics("figures/site_map.png")
knitr::include_graphics() accepts .png,
.jpg/.jpeg, .gif, and
.svg for HTML output. For PDF output, use .png
or .pdf — .gif and .svg are not
supported by LaTeX.
💡 Screenshots and field photos For screenshots
(e.g. of RStudio, an instrument interface, a map): save as
.png (not .jpg — JPEG compression blurs text).
Aim for 150–200 dpi at the intended display size. For field photos where
file size matters, .jpg is fine.
R Markdown uses pandoc-citeproc to manage citations.
You provide a .bib file (BibTeX format) and reference
entries inline with @key syntax. Pandoc assembles the
bibliography automatically at the end of the document.
.bib fileA .bib file is a plain-text file containing reference
entries. Each entry has a type (@article,
@book, etc.), a cite key you invent, and fields:
@article{smith2022pm25,
author = {Smith, Jane and Jones, Robert},
title = {Particulate Matter Trends in Southern California},
journal = {Environmental Science \& Technology},
year = {2022},
volume = {56},
number = {4},
pages = {2341--2350},
doi = {10.1021/acs.est.1c07890}
}
@book{wickham2023r4ds,
author = {Wickham, Hadley and Cetinkaya-Rundel, Mine and Grolemund, Garrett},
title = {R for Data Science},
edition = {2},
year = {2023},
publisher = {O'Reilly Media},
url = {https://r4ds.hadley.nz}
}
@manual{r-base,
title = {R: A Language and Environment for Statistical Computing},
author = {{R Core Team}},
organization = {R Foundation for Statistical Computing},
address = {Vienna, Austria},
year = {2024},
url = {https://www.R-project.org/}
}
Save this as references.bib in the same folder as your
Rmd (or a bib/ subfolder — adjust the path in YAML
accordingly).
💡 Getting BibTeX entries without typing them Most
journal websites have a “Cite” or “Export citation” button — choose
BibTeX format. Google Scholar has a quotation-mark icon → BibTeX. Zotero
and Mendeley both export .bib files directly. The only
thing you need to edit is the cite key (the first field after the
opening brace) — make it memorable: smith2022pm25, not
smith2022a.
bibliography: to the YAML header---
title: "Air Quality Analysis"
author: "Marc Los Huertos"
output: html_document
bibliography: references.bib
csl: apa.csl # optional — citation style (APA, MLA, etc.)
link-citations: true # make in-text citations clickable links
---
Without csl:, pandoc uses its built-in Chicago
author-date style. Download .csl files for other styles
from the Zotero Style
Repository.
Particulate matter exposure is linked to cardiovascular disease [@smith2022pm25].
Smith and Jones [-@smith2022pm25] found that PM2.5 declined 40% over two decades.
For an introduction to R, see @wickham2023r4ds [p. 42].
Multiple citations: [@smith2022pm25; @r-base].
| Syntax | Renders as |
|---|---|
[@key] |
(Smith and Jones 2022) |
[-@key] |
(2022) — suppress author name |
@key |
Smith and Jones (2022) — narrative citation |
[@key, p. 42] |
(Smith and Jones 2022, p. 42) |
[@key1; @key2] |
(Smith 2022; Jones 2021) |
Pandoc places the formatted reference list at the end of the
document by default. To control placement — for example, before
a footer — insert a heading with the {#refs} div exactly
where you want it:
## References
::: {#refs}
:::
---
*Compiled on `r Sys.Date()`.*
It is good practice to cite the R packages you use.
knitr::write_bib() generates BibTeX entries for any
installed packages automatically:
# Run once to generate/update the bib file for the packages you use
knitr::write_bib(
c("base", "rmarkdown", "knitr", "tidyverse", "lubridate", "ggplot2"),
file = "references.bib"
)
Then cite as normal: [@R-ggplot2],
[@R-tidyverse]. The R- prefix is the key
format write_bib() produces.
📚 nocite — bibliography entry with no in-text
citation To list a source in the bibliography without citing it
in the prose — a “Further reading” entry — add a nocite
field to the YAML header:
nocite: | @wickham2023r4ds, @r-base
These appear in the reference list even though no @key appears in the body text.
# Render to the default output format specified in YAML
rmarkdown::render("reports/my_analysis.Rmd")
# Render to a specific format regardless of YAML
rmarkdown::render("reports/my_analysis.Rmd",
output_format = "pdf_document")
# Render and save to a specific path
rmarkdown::render("reports/my_analysis.Rmd",
output_file = "outputs/my_analysis.html")
When you click Knit, RStudio starts a new, empty R session to run your document. It does not use the objects already in your Environment pane. This is the most common source of “it works in the Console but fails to knit” confusion:
⚠️ Your Environment is not your document’s
environment If you ran df <- read_csv(…) in the
Console and forgot to put it in a chunk, df exists in your
environment but not in the knit session. The document will error with
object ‘df’ not found. The fix: every object the document
needs must be created by a chunk inside the document.
knitr executes chunks strictly top to bottom. An
object created in chunk 5 is not available in chunk 3, even if you
created it in the Console first. If you get
object not found, check whether the object is created
before it is used.
# This chunk creates the object
site_data <- tibble::tibble(
site = c("Kern", "Mojave", "Coast"),
pm25 = c(12.1, 8.4, 18.0)
)
# This chunk uses it — works because it comes AFTER the chunk that creates it
site_data
## # A tibble: 3 × 2
## site pm25
## <chr> <dbl>
## 1 Kern 12.1
## 2 Mojave 8.4
## 3 Coast 18
| Action | R session | Chunks run | Use for |
|---|---|---|---|
| Knit | Fresh, empty | All, top to bottom | Final output, submission |
| Run All (Ctrl+Alt+R) | Current session | All, top to bottom | Development — your objects are available |
| Run chunk (Ctrl+Shift+Enter) | Current session | Just this chunk | Iterative development |
Source on a .R file |
Current session | — | Running a plain R script |
💡 Development workflow While building a document, use Run chunk to iterate quickly (you have access to your environment). Before submitting or sharing, always do a full Knit from scratch to confirm the document is truly self-contained.
When a knit fails, RStudio shows the error in the R Markdown tab. The format is always:
Quitting from R02_RMarkdown_knitr.Rmd:45-52 [chunk-label]
Error in ... : error message here
The numbers 45-52 are the line numbers
where the failing chunk starts and ends. Go to that line in your Rmd to
find the problem. The [chunk-label] confirms which chunk it
was — another reason to always label your chunks.
# 1. Is every object the document needs created INSIDE a chunk?
# (Not just in your Console environment)
# 2. Are all packages loaded with library() inside a chunk?
# (library() calls in the Console do nothing for the knit session)
# 3. Is every file path correct relative to the Rmd's location?
# (The knit session's working directory is the folder the Rmd lives in)
getwd() # run in Console to see where your Rmd's working directory is
# 4. Are all chunk labels unique?
# (Duplicate labels cause an immediate error before any code runs)
# 5. Does the chunk header use commas between options, not semicolons?
# CORRECT: ```{r my-chunk, echo=FALSE, fig.width=6}
# WRONG: ```{r my-chunk; echo=FALSE; fig.width=6}
The knit session’s working directory is the folder the Rmd
lives in — not your RStudio project root, and not wherever you
last called setwd(). This means all relative file paths in
read_csv(), source(), etc. should be relative
to the Rmd file, not to the project root.
# If your Rmd is at: project/reports/my_analysis.Rmd
# And your data is at: project/data/field_data.csv
# Then the correct relative path in the Rmd is:
df <- read_csv("../data/field_data.csv") # one level up, then into data/
# NOT:
df <- read_csv("data/field_data.csv") # wrong — that looks for
# project/reports/data/ which doesn't exist
Error in yaml::yaml.load(string, ...) :
Scanner error: ...
This means the YAML header is malformed. Common causes:
title: My: Report fails;
title: "My: Report" worksError: attempt to use zero-length variable name
or
Unterminated chunk
These usually mean a chunk fence is wrong:
CORRECT opening: ```{r my-label}
WRONG — missing r: ```{my-label}
WRONG — extra space: ``` {r my-label}
CORRECT closing: ```
WRONG — has text: ``` r
WRONG — two ticks: ``
Error in library(ggplot2) : there is no package called 'ggplot2'
The knit session installs nothing automatically. Install missing
packages in the Console with install.packages("ggplot2"),
then knit again. Never put install.packages() in a chunk
that will be evaluated during knit — it re-installs the package every
time.
setup, use include=FALSE, load all packages
and set global options here. knitr always runs it first.
opts_chunk$set() and override per-chunk only
when needed.
fig.show=‘hold’ collects plots; ‘asis’
places each immediately. Use a character vector for
fig.cap when one chunk produces multiple figures. Use
ref.label= to reuse a chunk without repeating code.
results=‘asis’ is required for programmatic
tables. Any function that emits raw HTML —
knitr::kable(), kableExtra, gt —
needs this option or its output appears as raw text.
1.23457^{4} in prose instead of typing a number. The value
updates automatically when data changes.
knitr::include_graphics() for images.
It respects chunk options (out.width, fig.cap,
fig.align). Paths are relative to the Rmd file, not the
project root.
.bib file and a YAML
bibliography: field. Cite with [@key] in prose; use
knitr::write_bib() to generate entries for R packages
automatically.
read_csv(), knitr::include_graphics(), and
bibliography: are relative to the Rmd file’s location.
dplyr and
tidyrggplot2 for publication-quality figures