Chapter 10 ggplot2

Function ggplot from package ggplot2 (Wickham 2016) provides a high-level interface to creating graphs, essentially by composing all their ingredients and constraints in a single expression. It implements the “grammar for graphics” by Wilkinson (2006), and is the plotting package of choice in the tidyverse.

Before ggplot 3.0.0 came out, the approach to plotting spatial data was to fortify it, meaning encode all the geometries as atomic vectors in a data.frame, keeping an ID column to register which coordinate belonged to which geometry, and repeating all non-geometry attributes for each geometry coordinate. This worked reasonably well for points and lines, but not very well for polygons with holes.

Since ggplot 3.0.0 and package sf, this runs much smoother; ggplot has received a geom_sf function that could take an sf object and calls st_as_grob on each feature geometry to get an object that can directly be added to the plot. In addition to that, it takes care of automated datum transformations or projections if different objects have differing coordinate reference systems, and adds by default a graticule and degree axis tic labels.

Moreno and Basille (2018a), Moreno and Basille (2018b) and Moreno and Basille (2018c) published three guest blogs on explaining the capabilities of ggplot for making beautiful maps with sf and ggplot2.

10.1 geom_sf

We will introduce the affordances of geom_sf here step by step. We use a projected version of nc

system.file("gpkg/nc.gpkg", package="sf") %>% read_sf() %>% 
    st_transform(32119) -> nc.32119

and create a first ggplot by

ggplot() + geom_sf(data = nc.32119) 

It is attractive to think that

ggplot(nc.32119) + geom_sf()

would also work, but it doesn’t – it only works if the geometry column is named geometry, which is not always the case (sf objects may have more than one geometry column).

If we want to get rid of the axis tics and grid lines, we could use

ggplot() + geom_sf(data = nc.32119) + theme_void() +
  theme(panel.grid.major = element_line(color = "white"))

A first ggplot2 plot with polygons colored by attributes (as in figure 1.2) is created by

ggplot() + geom_sf(data = nc.32119) + aes(fill = BIR74) +
    scale_fill_gradientn(colors = viridis::viridis(20))

10.1.1 facet plots

10.1.2 multiple geometries in a single map

10.1.3 graticule control

10.2 using stars objects with ggplot2

Package stars comes with a geom_stars function that is much more limited in scope than geom_sf. In essence, it creates a call to geom_raster in case of raster data with a regular grid, to geom_tile for other raster data, or to geom_sf if the stars object has simple feature geometries. It also creates the mapping of dimension names to x and y-coordinates and set the first array name as the fill variable. This means that the aspect ratio still needs to be controlled (coord_equal()) and that a facet_wrap is needed to display multiple rasters. An example is shown in figure 10.1.

system.file("tif/L7_ETMs.tif", package = "stars") %>% read_stars() -> x
ggplot() + geom_stars(data = x) + 
    coord_equal() + 
    facet_wrap(~band) + 
    scale_fill_viridis() + 
    theme_void() +
example of geom_stars

Figure 10.1: example of geom_stars

geom_stars has a parameter, downsample, which can be used to downsample particular dimensions. Here we downsample a 90m x 90m raster to a 900m x 900m raster:

ggplot() + geom_stars(data = x, downsample = c(10,10,1)) + 
    coord_equal() + 
    facet_wrap(~band) + 
    scale_fill_viridis() + 
    theme_void() +


Wickham, Hadley. 2016. Ggplot2: Elegant Graphics for Data Analysis. Springer.

Wilkinson, Leland. 2006. The Grammar of Graphics. Springer Science & Business Media.

Moreno, Mel, and Mathieu Basille. 2018a. Drawing Beautiful Maps Programmatically with R, Sf and Ggplot2 - Part 1: Basics.

Moreno, Mel, and Mathieu Basille. 2018b. Drawing Beautiful Maps Programmatically with R, Sf and Ggplot2 — Part 2: Layers.

Moreno, Mel, and Mathieu Basille. 2018c. Drawing Beautiful Maps Programmatically with R, Sf and Ggplot2 — Part 3: Layouts.