The columns hold, e.g., the share of electric cars (ecar) and EU election 2019 vote shares per Cologne district.
Here’s a first basic map
# a simple first mapggplot() +geom_sf(data = attributes_cologne)
Making a plan
This map will be our canvas for the session. We will cover five building blocks:
THE MAP: adding attributes, choosing colors/palettes, adding layers
THE LEGEND: position, sizes, display
THE ENVIRONMENT: choosing from themes and building your own
THE META-INFORMATION: titles and sources
THE EXTRAS: scales and compass
If you are working on your maps, the ggplot2 cheatsheets will help you with an overview of scales, themes, labels, facets, and more.
THE MAP: a basis
# easy fill with a fixed colorggplot() +geom_sf(data = attributes_cologne,fill ="steelblue",color ="white" )
THE MAP: add the aesthetics
We’ll concentrate on mapping the share of electric cars per district.
ggplot() +geom_sf(data = attributes_cologne,# map the attribute to fill coloraes(fill = ecar) ) +# choose a continuous color scalescale_fill_continuous()
THE MAP: color palette
Are you having trouble choosing the right color? Some excellent tutorials exist, e.g. by Michael Toth.
ggplot() +geom_sf(data = attributes_cologne,aes(fill = ecar) ) +# readable with color vision deficienciesscale_fill_viridis_c(option ="plasma")
THE MAP: fine-tuning
ggplot() +geom_sf(data = attributes_cologne,aes(fill = ecar),# remove district borderscolor =NA ) +scale_fill_viridis_c(option ="plasma",# flip the scale directiondirection =-1 )
Save and reuse
Maps produced with ggplot2 are standard R objects (they are lists). We can assign them to reuse, plot later, and keep adding layers.
Furthermore, ggsave() automatically detects the file format from the extension. You can also control height, width, and dpi — particularly useful for publication-ready graphics.
You can handle everything concerning the legend within the scale_*.
ggplot() +geom_sf(data = attributes_cologne,aes(fill = ecar),color =NA ) +scale_fill_viridis_c(option ="plasma",direction =-1,# add a legend titlename ="E-Car Share",# adjust legend displayguide =guide_legend(# turn it horizontaldirection ="horizontal",# put labels under the legend barlabel.position ="bottom" ) )# check the help file for more options: ?guide_legend
THE ENVIRONMENT: get rid of everything?!
The theme controls all non-data displays. Instead of removing everything, try the built-in themes.
# use the cologne_map object as basecologne_map +# remove all non-data inktheme_void()# ... or try another built-in theme:# theme_bw()# theme_gray()# theme_light()# see all options: ?theme
THE ENVIRONMENT: build your own theme
cologne_map +theme_void() +theme(# bold all text elementstitle =element_text(face ="bold"),# move legend to bottomlegend.position ="bottom",# change background colorpanel.background =element_rect(fill ="lightgrey") )
THE META-INFORMATION: adding labs
Always include and cite your data sources. labs() lets you add titles, subtitles, and captions directly to the map.
Our code has already grown. Without going into too much detail, the following slides showcase some more changes you can make to your maps.
A map is never finished until you decide not to work on it anymore.
Facet maps: data preparation
facet_wrap() creates small multiples — one panel per group. The data must be in long format first.
# pivot the six party columns into one long columncologne_parties <- attributes_cologne |> tidyr::pivot_longer(cols =c(cdu, spd, greens, afd, left, fdp),# new column holding the party namenames_to ="party",# new column holding the vote share valuevalues_to ="vote_share" )# each district now appears six times — once per partycologne_parties |> sf::st_drop_geometry() |> dplyr::select(id, party, vote_share) |>head(8)
# A tibble: 8 × 3
id party vote_share
<dbl> <chr> <dbl>
1 202 cdu 32.6
2 202 spd 12.1
3 202 greens 26.7
4 202 afd 5.5
5 202 left 2.9
6 202 fdp 12.9
7 201 cdu 19
8 201 spd 14.7
To add labels, we need regular X/Y columns — not geometries. We use sf::st_centroid() to find polygon centers, then sf::st_coordinates() to extract the coordinates.