Reports with R Markdown
Reviewed & published by Brayan K
R Markdown is a document format that mixes Markdown prose with runnable R code chunks, so that a single "knit" produces a reproducible report — HTML, PDF, or Word — where every number, table, and plot is generated straight from your data.
Part of the free R course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.
By the end of this lesson you'll write the YAML header, add code chunks and inline R, control output with chunk options, and knit a polished, reproducible report.
What You'll Learn in This Lesson
- How the YAML header configures the document
- How to write and run R code chunks
- How to weave results into prose with inline R
- How chunk options (echo/eval/fig) shape output
- How to knit to HTML, PDF, or Word
- Why R Markdown beats a plain script for reports
1️⃣ The YAML Header and Markdown Body
Every .Rmd file opens with a YAML header between two --- lines that sets the title, author, and most importantly the output format. Below it you write ordinary Markdown — headings with #, bold with **...**, and bullet lists.
---
title: "Monthly Sales Report"
author: "Your Name"
date: "2026-06-18"
output: html_document
---
# Overview
This is a paragraph of **Markdown**. You write prose normally and
drop in R wherever you need numbers, tables, or plots.
## A bullet list
- Markdown handles formatting
- R chunks handle computation
- One "Knit" turns it all into a polished document2️⃣ Code Chunks and Inline R
A code chunk opens with a fenced header — three backticks then {r} — and closes with three backticks. Knitr runs the code and inserts the result. For a single value inside a sentence, use inline R: a backtick, the letter r, your expression, then a closing backtick.
${fence}{r}
# This is a CODE CHUNK. The header ${fence}{r} opens it; ${fence} closes it.
# When you knit, R RUNS this code and drops the result into the report.
sales <- c(120, 135, 150, 165)
mean(sales)
${fence}
You can label a chunk and set OPTIONS in its header:
${fence}{r summary-stats, echo=FALSE}
# echo=FALSE -> hide the CODE, show only the OUTPUT
summary(sales)
${fence}
${fence}{r the-plot, fig.width=6, fig.height=4}
# fig.width / fig.height control the plot size in the output
plot(sales, type = "b", main = "Monthly Sales")
${fence}You can weave R results into a SENTENCE with inline code.
Write a backtick, the letter r, an expression, then a closing backtick:
The average sale was `r mean(sales)` units, across
`r length(sales)` months.
When knitted, that line becomes:
The average sale was 142.5 units, across 4 months.
Inline R is perfect for figures that must always match the data —
no more copy-pasting numbers that go stale when the data updates.3️⃣ Chunk Options and Knitting
Each chunk header can carry options that shape what appears: echo=FALSE hides the code, eval=FALSE skips running it, and fig.width/fig.height size plots. Set document-wide defaults in a setup chunk, then knit to HTML, PDF, or Word.
# Common chunk options (set per-chunk in the ${fence}{r ...} header):
#
# echo = TRUE/FALSE show or hide the source code
# eval = TRUE/FALSE run the chunk or skip it
# include = FALSE run it, but show NEITHER code nor output
# warning = FALSE suppress warnings in the report
# message = FALSE suppress package-load messages
# fig.cap = "..." add a figure caption
#
# Set defaults for the WHOLE document in a setup chunk near the top:
${fence}{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE, warning = FALSE, message = FALSE)
${fence}
# Then knit:
# - Click the "Knit" button in RStudio, OR
# - rmarkdown::render("report.Rmd")
# - Change output: pdf_document in the YAML to get a PDF instead.Your turn. Fill in the TODO blanks, save as report.Rmd, and knit it.
# 🎯 YOUR TURN — fill in the blanks, save as report.Rmd, then Knit in RStudio.
---
title: "My First Report"
author: "TODO: your name"
output: html_document
---
# Sales Summary
${fence}{r}
sales <- c(100, 120, 90, 140)
# print the total with sum(sales)
sum(sales)
${fence}
The highest sale was `r max(sales)` units.
${fence}{r, echo=FALSE}
# echo=FALSE hides this code but still shows the bar plot
barplot(sales, main = "Sales by Month")
${fence}
# 👉 Click "Knit" in RStudio. You should get an HTML page with a
# heading, the total (450), an inline max (140), and a bar chart
# whose code is hidden because of echo=FALSE.Mini-Challenge: A Reproducible Report
Assemble a complete mini-report from the spec: YAML, a setup chunk, a data frame, an inline total, and a captioned plot. Then change one number and re-knit to feel the power of reproducibility.
# 🎯 MINI-CHALLENGE: a reproducible mini-report.
#
# Create report.Rmd that knits to HTML and contains:
#
# 1. A YAML header with a title, your name, and output: html_document.
# 2. A setup chunk (include=FALSE) that sets echo = FALSE globally.
# 3. A chunk that builds this data frame:
# df <- data.frame(month = month.abb[1:4], rev = c(50, 65, 40, 80))
# 4. An inline sentence stating the total revenue using `r sum(df$rev)`.
# 5. A chunk that plots revenue: barplot(df$rev, names.arg = df$month)
# 6. fig.cap = "Quarterly revenue" on that plotting chunk.
#
# Knit it. Re-run after changing one number and watch EVERY figure
# (table, inline total, chart) update automatically — that's the win.
# write your .Rmd hereCommon Errors (and the fix)
- Broken YAML indentation — ❌ misaligned keys or tabs. ✅ Use consistent spaces; keep key: value tidy.
- Unclosed code chunk — ❌ forgetting the closing three backticks. ✅ Every ```{r} needs a matching ```.
- Relying on your global environment — ❌ knitting starts a fresh session; objects from your console aren't there. ✅ Create everything inside chunks.
- PDF knit fails — ❌ no LaTeX installed. ✅ Run tinytex::install_tinytex() once.
Pro Tips
- 💡 Table of contents: add toc: true under html_document for auto navigation.
- 💡 Parameterize: a params: block lets one template render many reports (per region, per month).
- 💡 Go further: the same engine powers flexdashboard, xaringan slides, and the modern Quarto.
📋 Quick Reference — R Markdown
| Task | Syntax |
|---|---|
| Output format | output: html_document |
| Open a code chunk | ```{r} |
| Inline R | `r mean(x)` |
| Hide code | ```{r, echo=FALSE} |
| Global options | knitr::opts_chunk$set(...) |
| Render from code | rmarkdown::render("report.Rmd") |
🎉 Lesson Complete!
- ✅ The YAML header sets title, author, and output format
- ✅ Code chunks (```{r}) run R and embed results
- ✅ Inline R (`r expr`) drops values into prose
- ✅ Chunk options like echo and fig.width shape output
- ✅ Knit to HTML/PDF/Word for one reproducible report
Practice quiz
What lives in the YAML header between the two --- lines?
- The R code chunks
- Document metadata like title, author, and output format
- The bibliography
- Only the page title
Answer: Document metadata like title, author, and output format. The YAML header sets title, author, date, and the output format.
How do you open an R code chunk in R Markdown?
- <r>
- Three backticks followed by {r}
- #{r}
- [[r]]
Answer: Three backticks followed by {r}. A chunk opens with three backticks then {r} and closes with three backticks.
What does the chunk option echo=FALSE do?
- Runs the code but hides the source, showing only output
- Skips running the chunk
- Hides both code and output
- Adds a caption
Answer: Runs the code but hides the source, showing only output. echo=FALSE hides the source code while still showing the result.
What does eval=FALSE do to a chunk?
- Hides the output
- Hides the code
- Shows the code but does not run it
- Caches the chunk
Answer: Shows the code but does not run it. eval=FALSE displays the code without executing it.
What does include=FALSE do?
- Shows code but not output
- Shows output but not code
- Adds the chunk to the table of contents
- Runs the chunk but shows neither code nor output
Answer: Runs the chunk but shows neither code nor output. include=FALSE runs the chunk for side effects but hides code and output.
How do you embed a single computed value inside a sentence?
- Inline R: a backtick, the letter r, an expression, a backtick
- A {r} block
- Using <<r>> tags
- With paste() only
Answer: Inline R: a backtick, the letter r, an expression, a backtick. Inline R drops one value into prose with `r expr`.
Which function sets document-wide chunk defaults?
- rmarkdown::render()
- knitr::opts_chunk$set()
- yaml::set()
- options(chunk = ...)
Answer: knitr::opts_chunk$set(). knitr::opts_chunk$set() in a setup chunk sets global defaults.
How do you produce a PDF instead of HTML?
- Rename the file to .pdf
- Use eval=FALSE
- Change output: to pdf_document in the YAML
- Call print()
Answer: Change output: to pdf_document in the YAML. Set output: pdf_document in the YAML header (a LaTeX engine is needed).
Which function renders an .Rmd report from code?
- rmarkdown::render("report.Rmd")
- knit_now()
- source("report.Rmd")
- render.csv()
Answer: rmarkdown::render("report.Rmd"). rmarkdown::render() knits the document without the RStudio button.
Why prefer R Markdown over a script with pasted results?
- It runs faster
- It uses less memory
- It needs no packages
- It is reproducible: numbers regenerate from data each knit
Answer: It is reproducible: numbers regenerate from data each knit. Code, output, and prose live in one file, so re-knitting updates every figure.
Continue this course
- Previous: Interactive Apps with Shiny
- Next: Closures & Function Factories — Return functions that remember their environment for reusable behavior
- Quick reference: R cheat sheet
Frequently asked questions
What is the YAML header at the top of an .Rmd file?
The block between the two --- lines is YAML metadata that controls the whole document. It sets the title, author, and date that appear at the top, and crucially the output format — html_document, pdf_document, or word_document — which tells knitr what kind of file to produce. You can also configure themes, a table of contents (toc: true), and parameters here. Think of it as the document's settings panel, written in simple key: value pairs.
What's the difference between a code chunk and inline R?
A code chunk is a block opened with ```{r} and closed with ```; knitr runs the whole block and inserts its output (text, table, or plot) into the report. Inline R, written as a backtick followed by r and an expression, drops a single computed value straight into a sentence — perfect for figures like 'sales rose by `r pct`%'. Use chunks for analysis and plots; use inline R so the prose numbers always match the data.
What do the echo, eval, and include chunk options do?
These control what readers see. echo=FALSE runs the code but hides the source, showing only results — ideal for a clean report. eval=FALSE shows the code but does not run it, useful for illustrating syntax. include=FALSE runs the chunk for its side effects (like loading packages) but shows neither the code nor its output. Set sensible defaults once in a setup chunk with knitr::opts_chunk$set(), then override per chunk as needed.
Why use R Markdown instead of just running a script and pasting results?
Because it is reproducible. In R Markdown the code, its output, and your narrative live in one file, so the numbers in your prose are generated from the data every time you knit. There is no copy-paste step to forget, and no risk of a chart showing last month's figures. Re-knit after the data changes and the entire document — tables, plots, and inline values — updates itself. That single source of truth is why R Markdown underpins reports, dashboards, slides, and even whole books.