11 Writing reports in R

In Chapter 5 and Chapter 6 we’ve learned how to make crime maps, but almost every analysis also needs text, charts and other things to help the audience understand the main messages. In this chapter we will learn how to use a tool called Quarto to produce structured reports in Positron and export them to multiple formats, including HTML, Word and PDF.
- Open Positron or – if you already have Positron open – start a new R session by clicking the Restart R (⟳) button in the Console panel. This makes sure no code you ran previously will interfere with the work you do in this chapter.
- Make sure you are working in the crime mapping project workspace you created in Section 1.5. In the top-right corner of the Positron window, you should see a folder icon and the words
crime_mapping. If not, click the File menu, then Open Folder … and choose thecrime_mappingfolder.
11.1 Introduction
We have practised producing useful maps in R so that people can use them to make decisions about understanding and responding to crime problems. But maps are only one part of most spatial analysis. In practice, maps are usually part of a larger report in which you as an analyst will explain what your maps show and perhaps make recommendations about what decisions people should make.
You are probably used to creating graphics in one piece of software (such as a map in R or a chart in Excel) and then importing or pasting those graphics into another program (such as Word) to include them in a written report. This way of working is often fine, but it has some important shortcomings. For example, if you want to make a change to a graphic (maybe to correct a typo), you then have to import it into your writing program again. More importantly, it can become hard to keep track of which version of a graphic you need to import and you may end up including the wrong version of a file.
The same problem applies to numbers that you might calculate in statistical software such as R. You might calculate a statistic such as the mean number of burglaries in local council wards, then paste the result into Word to include it in your report. But if you then realise later on that there is a problem with your data and re-run your code, it would be very easy (especially in a long report) to forget that you needed to update the mean value presented in the report. The risk of making errors like this is particularly high if you are asked to update an existing report based on new data. Perhaps the worst aspect of this problem is that you will never know for sure if the numbers in your final report are correct, unless you go back and check every one of them in whatever program you used to generate the numbers in the first place. So whenever you present your analysis you will have the nagging doubt that some of the results might be incorrect.
We can describe this risk of a report containing obsolete charts or incorrect statistics by saying that it is not reproducible – if we were asked to go back and demonstrate each stage in producing the report to prove that we had done everything correctly, it would be very hard to do so. This is important because the reports that analysts write about crime are so often used to make decisions about how to respond to crime. An error in copying and pasting a number from R or Excel into Word could lead to police officers being deployed to the wrong place, or the wrong local council being given funding to install crime-prevention measures.
Watch this video to learn more about writing reproducible documents using what is known as literate coding.
What is a key feature of a computational notebook?
Why is literate coding recommended for reproducible workflows?
Which of the following best describes Quarto notebooks?
In this chapter we will learn to use Quarto to write reports directly in Positron, integrating data, maps and statistics so that they remain up to date.
Reports made with Quarto can include lots of different calculations, graphics, etc. For example, the report Stop and Search in London was created entirely in Quarto. This whole book is also written in Quarto. But in this chapter we’ll keep things simple by producing a very short report that only includes one figure. You can view the finished version of the report that we will use as an example in this chapter. The report combines a sentence of explanatory text, a map produced by R and an automatically numbered cross-reference.
In this chapter, we will learn how to:
- structure a report using Markdown;
- create and configure a Quarto document;
- add inline R code and R code chunks to Quarto documents;
- control which code and output appear in a finished report;
- label and cross-reference maps and tables; and
- render a reproducible report in different formats.
11.2 Markdown
Markdown is a way of formatting plain text so that a computer can convert it into different file formats. For example, Quarto can convert Markdown documents into Word, PDF, PowerPoint and many other formats.
a Markdown
document
… can be
processed into …
Word
PowerPoint
other formats
Markdown is extremely simple. It uses plain-text characters to represent common text formatting such as titles, emphasised text and so on. For example, the Markdown text:
produces the output:
Introduction
In this chapter we will learn to use a tool called Quarto to write reports directly in Positron.
In this example, the character # followed by a space at the start of a line means that line should be shown as a first-level heading and the asterisks (* – we could also have used the underscore character _) around the word Quarto indicate that it should be emphasised (typically with italic text).
In Markdown we use the hash character # followed by a space to indicate that a line should be formatted as a top-level heading. The space after the # is important – if you write #Introduction instead of # Introduction then Quarto will not recognise that line as representing a heading and it will not be formatted properly.
Markdown is designed to be easy to read and easy to write. It is perfectly possible, for example, to read the unformatted Markdown text in Code 11.1. Since Markdown files (which have the file extension .md) are plain text, it’s also possible to open them on virtually any computer. Markdown is very widely used on the web – using underscores to mark out italic text and asterisks to mark out bold text even works in messaging apps such as Telegram and WhatsApp.
In Markdown you describe the structure of a document, not its appearance. The appearance of the document (which fonts it uses, what margins the pages have and so on) is determined by the template Quarto uses to convert Markdown files into documents of different types. This can save you a lot of time, because you don’t need to specify fonts and other formatting. Instead, you can concentrate on the structure of your argument rather than the details of formatting.
You can create your own templates for documents (for example if you want to create documents that match a particular corporate style), but in this course we will use Quarto’s built-in formats.
You should not try to fine-tune the visual appearance of a document produced from Markdown-formatted text by (for example) changing a second-level heading to a third-level heading because you want the heading text to be slightly smaller. Keeping the structure of your document (defined using Markdown) separate from its visual appearance has several benefits that are important, but not immediately obvious. For example, screen reading software used by blind or partially sighted people will read out the structure of a document rather than the visual appearance. So if, for example, you were to use Markdown syntax for code text to change the font in the headings in a Markdown document, it is possible that would make the document much harder for people using a screen reader to make sense of.
If you want to change the visual appearance of a piece of Markdown-formatted text, you should change the template that is used to convert that text into a Word document, PDF, web page, etc.
Use Markdown to describe the structure of a document, not its appearance.
11.2.1 Markdown document structure
To create paragraphs in Markdown, you simply split text with a blank line. So this Markdown text:
produces the output:
In this chapter we will learn to use a tool called Quarto to write reports directly in Positron. Markdown is a way of formatting plain text so that a computer can convert it into different file formats.
because there is no blank line between the first and second sentences. We can split this into two paragraphs just by adding a blank line:
which produces the output:
In this chapter we will learn to use a tool called Quarto to write reports directly in Positron.
Markdown is a way of formatting plain text so that a computer can convert it into different file formats.
Headings
There are six levels of headings available in Markdown documents, although it is very unlikely that you will need all six. Headings are specified by adding one or more # characters to the start of the line, followed by a space:
produces:
First-level heading
Second-level heading
Third-level heading
Headings should have at least one blank line above and below them, so that they stand out from the surrounding code. I usually leave three blank lines before a second-level heading and two blank lines before other headings, with exactly one blank line after every type of heading.
Lists
Markdown supports two types of list: ordered lists and unordered lists. You can make an ordered list by putting each list item on a new line and starting each line with a number followed by a full stop (.). You make an unordered list in the same way, but starting each line with an asterisk:
produces:
- A list of items
- for which the ordering
- of items is important
- A list of items
- for which the ordering
- of items is not important
Quotes
If you want to insert a quote into your Markdown document, you can do that by putting a greater-than (>) symbol followed by a space at the start of each line of the quote:
produces
In this chapter we will learn to use a tool called Quarto to write reports directly in Positron.
11.2.2 Inline elements
As well as using Markdown to describe the structure of a document, you can use it to mark up particular text within a paragraph. We’ve already seen how to do this using _to emphasise text_ (usually displayed in italics). We can also **strongly emphasise** text, which will usually appear in bold. Note that the _, * or ** characters must be touching a word on exactly one side:
some _emphasised_ textproduces some emphasised textsome_emphasised_textdoes not produce emphasised textsome _ emphasised _ textdoes not produce emphasised text
We can add links to a document using the format [link text](URL). For example, the text:
produces the link:
There are several other Markdown codes for describing different elements within a document, including images, videos and segments of code. You can find out more about what’s possible with Markdown on the Markdown Basics page of the Quarto website.
11.2.3 Previewing Markdown in Positron
Positron can preview a Markdown document while you work. To try this:
- Click the File menu, then click New File ….
- Type
markdown_practice.mdin the box marked Select File Type or Enter File Name…, then press ReturnReturn. - Save the file in the
outputdirectory of yourcrime_mappingworkspace. - Add some Markdown headings, paragraphs and lists using the syntax we have just learned.
- Click the Preview button at the top-left of the editor.
As you edit the file, you can see an updated preview at any time by clicking the Preview button again.
By default, Positron renders Markdown files into HTML files (web pages). You can also produce many other formats. One common format you might want to produce is a PDF file. To create PDF files with Positron, your computer has to have a version of software called TeX installed. If you’ve never heard of TeX, you can install it automatically using the tinytex R package. To install TeX, run this R code once in the R Console:
TeX should now be installed on your computer.
Note that you only have to install TeX once on each computer you use, so you should not include tinytex::install_tinytex() in any code scripts that you write.
Which of the following is the correct way to create a first-level heading in Markdown?
How do you create an unordered list in Markdown?
What is the correct way to strongly emphasise text in Markdown?
11.3 Quarto
Markdown allows you to create static documents in Positron. But to create a report that includes maps, tables and other outputs from R, we need to use Quarto. Quarto is built into Positron, so you can create Quarto documents in much the same way as Markdown documents.
Quarto is a system that converts Markdown documents that contain chunks of code written in R or Python, runs the code and then integrates the Markdown text and the code results into one or more output files. Quarto can produce web pages, Word documents, PDF files, presentations, websites, e-books and other formats.
A Quarto file is just like a Markdown document except that it has the file extension .qmd rather than the extension .md. The .qmd extension tells Positron that a file will contain a mixture of text formatted with Markdown and code that produces tables, charts and so on.
In the rest of this chapter we will develop the code needed to create a report on homicides in Medellín, Colombia. To get started:
- Click the File menu in Positron, then click New File ….
- Type
chapter_11.qmdin the box marked Select File Type or Enter File Name…, then press ReturnReturn. - Save the file in the
outputdirectory of yourcrime_mappingworkspace.
Note that we are saving this file in the output directory, not the R directory. This is because Positron will save the outputs produced from a Quarto file in the same directory as the Quarto file itself.
Positron opens .qmd files in a source editor, where you can see the Markdown and code that make up the document. Keeping the source visible will help you understand exactly how the report is structured.
Quarto documents start with a header that provides some basic information about the document, such as the title. Replace the contents of chapter_11.qmd with this simple header:
The header is written in yet another programming language called YAML. You don’t need to know the details of YAML to write headers for Quarto documents. Two things you do need to know, though:
- The three dashes (
---) are important, because they tell Quarto that the content inside the dashes is the document header. These dashes must appear at the start of a line and be the only characters on that line. - Indentation matters in YAML. Every line takes the form
key: valueand in most cases the key must be at the very start of the line. Lines in YAML are not limited to 80 characters, so you should not break a single value (such as the document title) over multiple lines.
What is the key difference between a Markdown (.md) and a Quarto (.qmd) file?
What is the main role of the YAML header in a Quarto document?
What is one benefit of using Quarto over traditional word processors like Microsoft Word?
11.3.1 R code in Quarto
Quarto will process everything in a Quarto document after the header (marked with ---) as Markdown text. The only exception is when you include sections of code in a Quarto document.
You can include R code inside a line of Markdown text (known as inline code) and the result of that code will be included in the document output. Inline R code begins with a backtick character (`) followed by a lower-case r and a space, and ends with another backtick. For example, add the following sentence beneath the header in chapter_11.qmd:
Which would produce the output:
This report was written on 3 October 2026
Where you do (and don’t) put spaces matters a lot when writing a Quarto document. For example, the inline R code in Code 11.2 must have a space after the r at the start of the code chunk but must not have a space between the ` and the r, otherwise Quarto will not recognise it as inline R code. So `r works, but ` r does not.
Putting R code inline is fine for simple pieces of code, but longer pieces of code included inline would become difficult to read (and therefore difficult to debug). Fortunately, we can put as much code as we like in a code chunk. To add an R code chunk to a Quarto document, type ```{r} (three backticks followed immediately by {r}) on a line on its own, add the R code on the following lines, then close the chunk with ``` (three more backticks) on a line on its own. Positron will highlight the chunk so that it stands out from the surrounding Markdown text.
We can use code chunks to run longer pieces of code that would be difficult to read if the code were inline. For example, if you wanted to load a data file of crime data, filter it for crimes occurring in a particular month and then count the number of rows, you could do the calculation in a code chunk and then include the result inline:
If Positron does not highlight a code chunk, check that you saved the file with a .qmd extension and typed the opening and closing backticks correctly.
To help keep track of code chunks, we can label them. Add #| label: immediately below the opening line of the chunk, followed by a short label containing letters, numbers and dashes (-). For example, the chunk in Code 11.3 already has the label count-homicides, specified by #| label: count-homicides. Labels appear in error messages and make it easier to find which part of a document needs attention.
The package that converts Quarto documents into other formats is called knitr – actually, it’s a bit more complicated than that, but one of the nice things about Quarto is you don’t need to worry about what’s happening behind the scenes.
The default Quarto template is set up so that the final document that is produced from your Quarto file will include both the code that you include in any code chunks and the output that the code produces. For example, we can use code like this to get our Medellín homicides report started:
---
title: "Medellín homicides map"
author: "John Smith"
date: "today"
format:
html:
embed-resources: true
---
```{r}
#| label: setup
# Load packages
pacman::p_load(here, httr2, sf, sfhotspot, tidyverse)
# Create the directory for the original downloaded data
dir.create(here("data", "raw"), recursive = TRUE, showWarnings = FALSE)
# Download the original data
request(
"https://mpjashby.github.io/crimemappingdata/medellin_homicides.csv"
) |>
req_perform(path = here("data", "raw", "medellin_homicides.csv"))
# Load data
medellin_homicides <- here("data", "raw", "medellin_homicides.csv") |>
read_csv2() |>
# Remove rows with missing coordinates
drop_na(longitud, latitud) |>
# Convert the data to an SF object
st_as_sf(coords = c("longitud", "latitud"), crs = "EPSG:4326")
```
```{r}
#| label: count-homicides
# Count number of homicides in February 2019
homicide_count <- medellin_homicides |>
filter(year(fecha_hecho) == 2019, month(fecha_hecho) == 2) |>
nrow()
```
There were `r scales::comma(homicide_count)` homicides recorded in February 2019.
But that code produces the following output. That’s probably not what you want because it has the raw R code in it as well as the output from that code:
We can control the results of code chunks using chunk options, sometimes called knitr options. We put these on the first line of each code chunk, with each option on a separate line and each line starting with the characters #| (referred to as a hash-pipe). Note that for Quarto to recognise a line of code as a Quarto chunk option, the line must come immediately after the opening line of the code chunk (```{r}) with no blank lines between them, and #| must be followed by a space.
To specify that the code in our R code chunks should not be printed in the final document, we can set the chunk option #| echo: false. To specify that both the R code and the output produced by that code (e.g. charts, tables, etc.) should not be shown, we can set the chunk option #| include: false.
If we change the code in Code 11.4 to set #| include: false to suppress both code and output from the first code chunk and set #| echo: false for the second code chunk, the output becomes much more like the report we want:
If a code chunk produces a chart or map, then we do want to show the output (although not the code), so in that case we should not set #| include: false – we do not need to set #| include: true because it is the default.
Since we probably don’t want any chunks in our code to include the code in our final document, we could end up setting the chunk option #| echo: false for every code chunk. In a long or complicated document, this would get tedious. Fortunately, we can set chunk options globally (i.e. for all chunks in a document) by setting them in the YAML document header. To do this, we add a key called execute to the header. Instead of giving the execute key a value such as true or false, we instead indent the next line of the header by exactly two spaces and then set the chunk option echo: false. If we wanted to set multiple global chunk options here, we would put each one on a new line, all of the lines indented by two spaces from the start of each document.
You might have noticed in Code 11.5 that instead of using read_csv() to load the data from the file medellin_homicides.csv, we are using a function called read_csv2(). That’s because the file uses semicolons (;) to separate the columns, rather than commas. This is a common convention in countries that use a comma as the decimal mark (most countries in Europe and South America, as well as some elsewhere).
If you use read_csv() to load a semicolon-delimited file, the values from all the columns on each row appear together in a single column. When you load a dataset and unexpectedly see it has been loaded as one column containing many semicolons, inspect the original file and consider using read_csv2() instead.
Add the setup chunk in Code 11.6 to chapter_11.qmd.
```{r}
#| label: setup
#| include: false
# Load packages
pacman::p_load(here, httr2, sf, sfhotspot, tidyverse)
# Download the original data
request(
"https://mpjashby.github.io/crimemappingdata/medellin_homicides.csv"
) |>
req_perform(path = here("data", "raw", "medellin_homicides.csv"))
request(
"https://mpjashby.github.io/crimemappingdata/medellin_comunas.gpkg"
) |>
req_perform(path = here("data", "raw", "medellin_comunas.gpkg"))
# Load data
medellin_homicides <- here("data", "raw", "medellin_homicides.csv") |>
read_csv2() |>
# Remove rows with missing coordinates
drop_na(longitud, latitud) |>
# Convert the data to an SF object
st_as_sf(coords = c("longitud", "latitud"), crs = "EPSG:4326")
medellin_boundary <- here("data", "raw", "medellin_comunas.gpkg") |>
read_sf() |>
janitor::clean_names() |>
st_transform("EPSG:3115")
```- Some rows in this dataset have missing coordinates.
st_as_sf()will produce an error if there are missing coordinates, so we usedrop_na()to remove them first. - Since the column names are called
longitudandlatitud, we know that we should use the WGS84 coordinate reference system, which has the CRS code EPSG:4326.
We transform the neighbourhood boundaries to EPSG:3115 because it is a suitable projected CRS for Medellín. See Section 6.2.1 for how to select a projected CRS whose units make distance-based parameters easy to specify.
Which function should you use to load a CSV file that uses semicolons to separate its columns?
What does it usually mean if read_csv() loads every row into one column containing many semicolons?
Some of the R code we write produces progress messages or warnings that we will not want to include in our Quarto documents. For example, hotspot_kde() normally prints progress messages while it estimates crime density. Those messages are useful to an analyst but would distract a reader of the finished report. When we need to run code that both:
- produces messages that we do not want to include in the final report, and
- produces output that we do want to include in the final report,
we can split the code into two separate code chunks, storing the result of the code in the first chunk in an object that we then refer to in the second chunk. The first chunk runs the code that produces the messages, but we set #| include: false so that neither the code nor the messages appear in the final report. The second chunk runs the code that produces the output we want to include in the report, and we do not set #| include: false for that chunk.
Add this code chunk to the chapter_11.qmd file. Note that for this chunk we are setting #| include: false to suppress the messages that would otherwise be produced by hotspot_kde(). Remember that there must be at least one blank line between each code chunk in Quarto documents.
```{r}
#| label: calculate-density
#| include: false
# Calculate crime density
medellin_homicide_density <- medellin_homicides |>
st_transform("EPSG:3115") |>
# `hotspot_kde()` prints progress messages by default, but `include: false`
# prevents them from appearing in the finished report
hotspot_kde(bandwidth_adjust = 0.33, cell_size = 500) |>
hotspot_clip(medellin_boundary, quiet = TRUE)
```Using #| include: false can be useful to stop an output document being littered with R messages and warnings. However, it will also stop you seeing warnings that might be important in highlighting problems you need to fix. If code in a Quarto code chunk is not producing the results you expect, the first thing you should do is remove #| include: false from the chunk so that you can see any warnings or messages that you might need to act upon. Once the code is running as you want it to, you can add #| include: false back again.
11.3.2 Maps, charts and tables in Quarto documents
Almost all the documents you produce in Quarto will include one or more maps, charts or tables. Quarto includes tools for providing captions for figures and tables, as well as the ability to refer to them elsewhere in a document.
Maps, charts and tables in Quarto documents are usually the output produced by a chunk of R code. For example, we might use hotspot_map() to make a map. To turn a code chunk into a figure we can reference, we need to add two chunk options at the start of the code chunk. We use the #| label chunk option to specify what text we will use throughout the rest of the document to refer to the figure or table produced by that code chunk. Note that chunk labels for figures and tables must begin with either fig- for figures (charts and maps) or tbl- for tables. For example, we might label a map with the label #| label: fig-homicides-map or a table with the label #| label: tbl-robbery-counts. Note that chunk labels can contain letters, numbers and dashes (-), but not spaces or other characters.
The second chunk option we should add is either the #| fig-cap chunk option (for charts and maps) or the #| tbl-cap argument, to create a caption for the chart, map or table. Note that captions should be enclosed in quotes, e.g. #| tbl-cap: "This is the table caption".
Add this code to the chapter_11.qmd Quarto file:
@fig-homicides shows the density of homicides in Medellín, Colombia, from 2010 to 2019.
```{r}
#| label: fig-homicides
#| message: false
#| fig-cap: "Density of homicides in Medellín, 2010 to 2019"
#| fig-alt: "Density map of recorded homicides in Medellín, Colombia, from 2010 to 2019. Darker blue indicates higher estimated density, with the strongest concentration in the central urban area and smaller concentrations to the north and west. Comuna boundaries are outlined over a pale street map; the shaded surface represents density rather than individual incidents."
# Note we don't have to set `#| include: true` for this code chunk, because that
# is the default. We do, however, have to set `#| message: false` to suppress
# the message about a coordinate system already being present when we add the
# boundary layer to the map.
# Plot a basic density map
hotspot_map(
medellin_homicide_density,
basemap_type = "cartolight",
caption = "Homicide data: Alcaldía de Medellín (CC-BY-SA)"
) +
geom_sf(data = medellin_boundary, colour = "grey25", fill = NA)
```Once we have set the label and the caption for a code chunk, we can use that label to insert cross-references into our document. For example, in Code 11.7 you can see that the code chunk that creates the map of homicides in Medellín has the chunk option #| label: fig-homicides. In the same listing, just before the code chunk, the figure produced by that chunk is referenced in the text using the code @fig-homicides. You can see in the output below that the cross-reference @fig-homicides has been changed to the text ‘Figure 1’, that the cross-reference is a hyperlink (to the part of the document containing the map) and that the map now has a caption that starts ‘Figure 1’.
You might have noticed we also added the chunk option #| fig-alt to the code chunk that produces the map. This is because we are producing an HTML document, and HTML documents should be accessible to people who use assistive technology such as screen readers. The #| fig-alt chunk option allows us to provide a short description of the figure that will be read out by a screen reader. You can find out more about accessibility in Quarto documents on the Quarto website.
What happens if you set the option #| echo: false in a Quarto code chunk?
Why is it useful to name code chunks in Quarto?
What happens if you set the option #| include: false in a Quarto code chunk?
11.4 Rendering Quarto
Once you’ve written the text for your document and added the code needed to produce statistics, tables and figures, it’s time to convert your Quarto file to a document in the format you need. This process is called rendering (or sometimes knitting) the document.
In Positron you can render a Quarto document by clicking the Preview button at the top-right of the editor. If you cannot see this button, check that you saved the file with a .qmd extension. By default, Quarto will produce an HTML file (a web page) and open it in Positron’s Viewer.
You can control the output format by changing the format: value in the YAML header of your Quarto document. The default is format: html, but you can also use format: pdf to produce a PDF file, format: docx to produce a Word document, format: epub to produce an e-book or format: pptx to produce a PowerPoint presentation. There are many other output formats available.
If you have a choice of which format to produce a report in, I would suggest you choose HTML because it can do things (like include interactive maps made with leaflet) that Word and PDF format cannot, and can easily be read on mobile devices. Well-formatted HTML documents are also much more accessible to people who need assistive technology such as screen readers for blind and partially sighted people. If, for whatever reason, you cannot choose HTML, I recommend choosing PDF format since it is readable on almost all computers, even those that do not have Word installed on them. Only produce reports in Word format if you are specifically required to submit something in that format.
Whatever format you choose, the output file will be saved in the same folder as your .qmd file and will have the same file name but with a different file extension (.html, .pdf, .docx, etc.). If you render the document again, Quarto will overwrite the previous output file.
When you render a Quarto document, Quarto starts a fresh R session and runs all the code in the file so that it can combine the results with the document text. The document can use only packages loaded and objects created inside that document. Objects you created interactively in Positron’s R Console are not available. This may be frustrating at first, but it reveals missing steps and helps keep the report reproducible.
Since rendering runs all the code in the document, that code may produce an error. The error will appear in the Terminal tab in Positron and will identify the code chunk in which the problem occurred. Meaningful chunk labels make these messages easier to follow. Read the message, find the named chunk and then use the techniques we learned in Chapter 8 to fix the issue.
11.4.1 Making self-contained HTML documents
Web pages written in HTML typically make use of images, videos and other resources stored in separate files. In fact, the web page you’re reading now makes use of resources stored in 51 separate files. This works well on the web, since it allows resources to be shared between lots of HTML files, which reduces how much data has to be stored and transmitted across networks. But it works less well when you want to send an HTML report to someone else over email, since it can be hard to keep track of all the external files associated with a particular HTML file.
To deal with this problem, we can tell Quarto that when it creates an HTML report, all the necessary data and other resources should be embedded inside the HTML file itself. This makes the HTML file larger, but easier to manage. To make HTML reports produced by Quarto self-contained in this way, we can change the format section of the header of a Quarto document from simply format: html to instead specify exactly what settings we want to be used to create that HTML file:
There are lots of other ways we can use the format section of the header in a Quarto document to fine-tune how the resulting document works. You can find out more in the HTML section of the Quarto website.
What happens when Quarto renders a document containing R code?
What does embed-resources: true do for an HTML report?
11.5 In summary
In this chapter we have learned how to use Markdown to create structured text and integrate that text with code and results in a Quarto report. This makes our work reproducible and reduces the risk of mistakes caused by copying statistics and graphics into software such as Word.
It also means we can produce periodic reports with updated data very easily, since we can just choose the data we want the report to be based on using filter() at the start of our file and render the document. This can save a huge amount of time in producing reports such as performance bulletins or monthly summaries of crime in an area.
We have practised how to:
- structure reports using Markdown headings, paragraphs, lists and inline elements;
- configure a Quarto document using a YAML header;
- add inline R code and labelled code chunks;
- control code, messages and output using chunk options;
- label and cross-reference figures and tables; and
- render self-contained reports in different formats.
To consolidate these skills, make the following changes to the chapter_11.qmd report you have developed throughout this chapter:
- Render the file as a self-contained HTML report.
- Render the file in at least one other format, such as Word. If you have installed tinytex, compare the PDF and HTML versions.
- Restart R, then render the document again to check that it does not depend on objects in your previous R session.
Your complete chapter_11.qmd file should now look like this:
---
title: "Medellín homicides map"
author: "John Smith"
date: "today"
format:
html:
embed-resources: true
fig-cap-location: top
execute:
echo: false
---
```{r}
#| label: setup
#| include: false
# Load packages
pacman::p_load(here, httr2, sf, sfhotspot, tidyverse)
# Create the directory for the original downloaded data
dir.create(here("data", "raw"), recursive = TRUE, showWarnings = FALSE)
# Download the original data into the project
request(
"https://mpjashby.github.io/crimemappingdata/medellin_homicides.csv"
) |>
req_perform(path = here("data", "raw", "medellin_homicides.csv"))
request(
"https://mpjashby.github.io/crimemappingdata/medellin_comunas.gpkg"
) |>
req_perform(path = here("data", "raw", "medellin_comunas.gpkg"))
# Load homicide data from the local copy
medellin_homicides <- here("data", "raw", "medellin_homicides.csv") |>
read_csv2() |>
drop_na(longitud, latitud) |>
st_as_sf(coords = c("longitud", "latitud"), crs = "EPSG:4326")
medellin_boundary <- here("data", "raw", "medellin_comunas.gpkg") |>
read_sf() |>
janitor::clean_names() |>
st_transform("EPSG:3115")
```
```{r}
#| label: calculate-density
#| include: false
# Calculate crime density
medellin_homicide_density <- medellin_homicides |>
st_transform("EPSG:3115") |>
# `hotspot_kde()` prints progress messages by default, but `include: false`
# prevents them from appearing in the finished report
hotspot_kde(bandwidth_adjust = 0.33, cell_size = 500) |>
hotspot_clip(medellin_boundary, quiet = TRUE)
```
@fig-homicides shows the density of homicides in Medellín, Colombia, from 2010 to 2019.
```{r}
#| label: fig-homicides
#| message: false
#| fig-cap: "Density of homicides in Medellín, 2010 to 2019"
#| fig-alt: "Density map of recorded homicides in Medellín, Colombia, from 2010 to 2019. Darker blue indicates higher estimated density, with the strongest concentration in the central urban area and smaller concentrations to the north and west. Comuna boundaries are outlined over a pale street map; the shaded surface represents density rather than individual incidents."
# Note we don't have to set `#| include: true` for this code chunk, because that
# is the default. We do, however, have to set `#| message: false` to suppress
# the message about a coordinate system already being present when we add the
# boundary layer to the map.
# Plot a basic density map
hotspot_map(
medellin_homicide_density,
basemap_type = "cartolight",
caption = "Homicide data: Alcaldía de Medellín (CC-BY-SA)"
) +
geom_sf(data = medellin_boundary, colour = "grey25", fill = NA)
```
Save chapter_11.qmd by pressing .
You can also download a second complete example report, which produces a table rather than a map, to practise these skills with a different output. This file uses the gt package to make a professional table, which we will learn more about in Chapter 14. You can find these examples and reusable templates in Appendix G.
There is a lot more you can do with Quarto. To find out more, refer to these resources.
Answer these questions to check you have understood the main points covered in this chapter. Write between 50 and 100 words to answer each question.
- Why is reproducibility important in writing reports, and why does non-reproducible analysis risk providing decision makers with the wrong information?
- How does Markdown help structure a report, and what are some key Markdown formatting features?
- What role does the YAML header play in a Quarto document, and how can it be customized?
- What are chunk options in Quarto, and how do they affect the final output of a report?
- How does Quarto improve the workflow of integrating tables, charts, and maps into reports?
