Skip to content
R for the Rest of Us Logo

Labelling ggplot2 Maps (02_03)

This lesson is locked

Get access to all lessons in this course.

Transcript

Click on the transcript to go to that point in the video. Please note that transcripts are auto generated and may contain minor inaccuracies.

Your Turn

Open the 02_03 project. Use the your-turn.R script in 02_03 to create a labelled geoscatter plot.

Select a country of your choice and use that to create a labelled geoscatter plot of the 10 largest cities in the country.

The solution shows cities in Germany but the code will work for any region that exists in the world.cities dataset.

Learn More

The {ggrepel} package is really a delight to work with and it works well with many geoms built into {ggplot2}. As mentioned in the video, it doesn’t yet natively support sf objects. There’s a GitHub Issue requesting the feature. You can check that to see if you can skip the data manipulation trick I demoed in this video.

Have any questions? Put them below and we will help you out!

You need to be signed-in to comment on this post. Login.

David Solet

David Solet

March 30, 2022

With current events in mind, I chose the 10 largest cities in Ukraine instead of Germany. It worked well for the lesson. In world.cities, the label for "Kyiv" was "Kiev", which I think is the old anglicized spelling. Is there a source for up-to-date country (and other geographic features) labels? Thanks!

Charlie Hadley

Charlie Hadley

March 31, 2022

Hi David. It really sucks that colonialism seeps into almost all mapping related activities eventually. Unfortunately, the world.cities dataset is part of the {dataset} package and base R - it's therefore extremely unlikely the dataset will ever be deanglicised as there will be very old code that relies on the current version of the data.

I did a quick search and this website https://simplemaps.com/data/world-cities provides a free .csv that correctly names Kyiv and appears to be a pretty good dataset.

Cheers,

Charlie

David Solet

David Solet

March 31, 2022

Thank you very much, Charlie! That is just the thing I'm looking for. David

Bohdanna Kinasevych

Bohdanna Kinasevych

April 6, 2022

Hi Charlie, I'm struggling to add labels to my map. I'm trying to plot 5 locations in Manitoba, Canada and it works up to the point when I convert my sf data file to a tibble and try to add labels. The X Y columns have the correct values for long/lat but my labels all plot at 0,0 (seems as though it's reading the X Y coordinates on a different scale). Any suggestions?

Here's my attempt to reproduce the code: manitoba_sf % st_as_sf() %>% filter(NAME_1 == "Manitoba")

mhrn_sites_tib <- tribble( ~location, ~long, ~lat, "Flin Flon", -101.88820, 54.76882, "Selkirk", -101.24217, 53.83253, "The Pas", -97.88055,55.75860, "Thompson", -97.29231, 49.85396, "Winnipeg", -97.29231, 49.85396, )

mhrn_sites_sf % st_as_sf(coords = c("long", "lat"), crs = 4326)

ggplot() + annotation_map_tile() + geom_sf(data = mhrn_sites_sf) + geom_label_repel(data = mhrn_sites_tib, aes(x = long, y = lat, label = location))

Charlie Hadley

Charlie Hadley

April 7, 2022

Hi Bohdonna,

Thanks for the question. I looked into this and it turns out that annotation_map_tile() transforms the CRS of the ggplot2 chart into something else. So you have two solutions:

  • Set the CRS with coord_sf()
library(tidyverse)
library(sf)
library(ggspatial)
library(ggrepel)

mhrn_sites_tib <- tribble(
  ~location, ~long, ~lat,
  "Flin Flon", -101.88820, 54.76882,
  "Selkirk", -101.24217, 53.83253,
  "The Pas", -97.88055,55.75860,
  "Thompson", -97.29231, 49.85396,
  "Winnipeg", -97.29231, 49.85396,
) %>% 
  select(location, lat, long) %>% 
  identity()

mhrn_sites_sf <- mhrn_sites_tib %>%
  st_as_sf(coords = c("long", "lat"),
         crs = 4326)

ggplot() +
  annotation_map_tile() +
  geom_sf(data = mhrn_sites_sf) +
  geom_label_repel(data = mhrn_sites_tib,
                   aes(x = long,
                       y = lat,
                       label = location)) +
  coord_sf(crs = 4326)
  • Use geom_spatial_label_repel()
ggplot() +
  annotation_map_tile() +
  geom_sf(data = mhrn_sites_sf) +
  geom_spatial_label_repel(data = mhrn_sites_tib,
                   aes(x = long,
                       y = lat,
                       label = location))

Let me know if you have any questions. Charlie

steve wakelin

steve wakelin

April 21, 2022

Hi Charlie I couldn't seem to get this working very well for New Zealand. The cities plotted on an x y plot (with gridlines for the long and lat - using theme_minimal(), but there was no actual country outline for New Zealand.

Enjoying the course!
Kind regards Steve

Charlie Hadley

Charlie Hadley

April 21, 2022

Hi Steve, Glad you're enjoying the course!

It's likely that your issue is related to New Zealand straddling the international date line which makes visualising it harder. This article about CRS for New Zealand is quite useful, and I used it to rewrite the {ggplot2} code in this gist.

Please let me know if this solves or doesn't solve your problem!

Thanks, Charlie

steve wakelin

steve wakelin

April 21, 2022

Hi Charlie

thank you so much for providing some code. Is really is kind of you to help to this extent.

I am having a bit of trouble in this section:

new_zealand_top_10_cities_tib % st_drop_geometry() %>% bind_cols(st_coordinates(new_zealand_top_10_cities_sf)) %>% rename(long = X, lat = Y)

R returns an error that

Error in stop_subscript(): ! Can't rename columns that don't exist. x Column X doesn't exist.

I wonder if by dropping the geometry it removes the x and y columns so it cant rename them?

Also, as an aside, given R had strong development roots in New Zealand, shouldn't NZ be the default centre of all plots ? :-)

Cheers steve

Charlie Hadley

Charlie Hadley

April 22, 2022

Hi Steve,

In your code the pipe is incorrectly written as % and you're also trying to pipe new_zealand_top_10_cities_tib into st_drop_geometry(). In my gist (https://gist.github.com/charliejhadley/04d8c340b3363ca1c666065044ef11bc) I pipe new_zealand_top_10_cities_sf into st_drop_geometry().

Thanks, Charlie