Search code examples
ggplot2mapsr-sf

ggplot and maps: problem with filtering country names


I try to create a map of the Middle East and North Africa region including country names. The map is defined by latitude and longitude coordinates. Several non-MENA countries are included in the resulting map, and I want to label with country names only the countries belonging to the region by defining them using the 'filter' function with a vector of country names. After having inserted the filter function, I get the error message: "Error in data.matrix(data) : 'list' object cannot be coerced to type 'double'". The map writes out fine when I don't include the filter with the vector of country names.

The following code runs fine:

ggplot(data = world) +
  geom_sf(fill= "antiquewhite") +
  geom_text(data = world_points , aes(x=X, y=Y, label=name),
            color = "darkblue", fontface = "bold", check_overlap = TRUE) +
  annotate(geom = "text", x = 20, y = 35, label = "MØNA", 
           fontface = "italic", color = "grey22", size = 6) +
  coord_sf(xlim = c(-18.0, 72.0), ylim = c(11.5, 45.0), expand = FALSE) +
  xlab("lengdegrader") + ylab("breddegrader") +
  ggtitle("Midtøsten og Nord-Afrika") +
  theme(panel.background = element_rect(fill = "aliceblue"))


But this produces the error. Something must be wrong in the geom_text function, but I cannot figure out what:

ggplot(data = world) +
  geom_sf(fill = "antiquewhite") +
  coord_sf(xlim = c(-18.0, 72.0), ylim = c(11.5, 45.0), expand = FALSE) +
  geom_text(data = world_points %>% 
              filter(name %in% c('Egypt', 'Tunisia', 'Algeria', 'Libya', 
                                 'Morocco', 'Sudan', 'Jordan', 'Israel', 
                                 'Palestine', 'Syria', 'Iraq', 'Turkey',
                                 'Iran', 'Afghanistan', 'Saudi Arabia', 'Kuwait', 
                                 'United Arab Emirates', 'Qatar', 'Oman', 'Yemen', 'Bahrain',
                                  'Lebanon')), aes(x=X, y=Y, label=name),
              color = "darkblue", size = 3, check_overlap = FALSE) +
  annotate(geom = "text", x = 20, y = 35, label = "MØNA", 
           fontface = "italic", color = "grey22", size = 6) +
  
  xlab("lengdegrader") + ylab("breddegrader") +
  ggtitle("Midtøsten og Nord-Afrika") +
  theme(panel.background = element_rect(fill = "aliceblue"))

Solution

  • When putting text on maps plotted using ggplot2::geom_sf() you will be better served by ggplot2::geom_sf_text() (the sf part is important!) than plain ggplot2::geom_text().

    This function will take the text position from the {sf} object that serves as data - thus removing the need to specify the x and y coordinates (the information is present in data already). Label argument works as expected

    To sum it up:

    • change geom_text call to geom_sf_text
    • remove x and y coordinates from your aes() call

    You will want to tune the label placement and what not, but it is a start...

    library(dplyr)
    library(ggplot2)
    library(sf)
    
    world <- giscoR::gisco_get_countries() %>% 
      mutate(name = NAME_ENGL)
    world_points <- st_centroid(world)
    
    
    ggplot(data = world) +
      geom_sf(fill = "antiquewhite") +
      coord_sf(xlim = c(-18.0, 72.0), ylim = c(11.5, 45.0), expand = FALSE) +
      geom_sf_text(data = world_points %>% 
                  filter(name %in% c('Egypt', 'Tunisia', 'Algeria', 'Libya', 
                                     'Morocco', 'Sudan', 'Jordan', 'Israel', 
                                     'Palestine', 'Syria', 'Iraq', 'Turkey',
                                     'Iran', 'Afghanistan', 'Saudi Arabia', 'Kuwait', 
                                     'United Arab Emirates', 'Qatar', 'Oman', 'Yemen', 'Bahrain',
                                     'Lebanon')), aes(label=name),
                color = "darkblue", size = 3, check_overlap = FALSE) +
      annotate(geom = "text", x = 20, y = 35, label = "MØNA", 
               fontface = "italic", color = "grey22", size = 6) +
      
      xlab("lengdegrader") + ylab("breddegrader") +
      ggtitle("Midtøsten og Nord-Afrika") +
      theme(panel.background = element_rect(fill = "aliceblue"))
    

    enter image description here