Search code examples
rggplot2polygongeom-text

cannot add labels for country with ggplot, geom_polygon and geom_text


I want to plot a chloropleth map of Africa with country labels. I'm using the world map from maptools, and ggplot2. geom_polygon makes the chloropleth successfully, but as soon as I add geom_text it adds loads of lines and looks crazy!

enter image description here

I have tried to set the projection but it hasn't change.

The code I've used is below:

tiff(file="~risk.tiff", width=600, height=600, res = 100)
ggplot(mapdata_x, aes (x = long, y = lat, group = group)) +
geom_polygon(aes(fill = factor(risk)), size = 0.25, color = "black") +
scale_fill_manual(values = c("#a6d96a", "#ffffbf", "#fdae61", "#d7191c"),
                 name = "Risk quartile") +
theme(axis.text.x = element_blank(),
    axis.text.y = element_blank(),
    axis.ticks = element_blank(),
    axis.title.y = element_blank(),
    axis.title.x = element_blank(),
    rect = element_blank())+
labs(title = "Risk")+
geom_text(data = mapdata_x, aes(x = long, y = lat, label = region), size = 3)
dev.off()

I've tried to set the projection using this code:

mapdata<- map_data("world")
coordinates(mapdata)<-~long+lat
proj4string(mapdata)<-CRS("+proj=longlat + datum=WGS84")
mapdata<-data.frame(mapdata)

But that hasn't changed anything.

Can't find anyone else who has had this issue. I'm new to mapping in R so any help much appreciated!


Solution

  • Really rough question here. Here's something to hopefully get you going in the right direction.

    The main issue you have is mapdata_x presumably has many data points for each region. You need just one, so that there is only one label for each region. You can create a new data frame or filter the one you have inside ggplot, I have created a new dataframe, label_data, to accomplish this in the code below.

    library(maptools)
    library(ggplot2)
    library(dplyr)
    library(ggrepel)
    africa_regions <- data.frame(region = c('Nigeria', 'Ethiopia', 'Egypt', 
                        'DR Congo', 'Tanzania', 'South Africa', 
                        'Kenya', 'Uganda', 'Algeria', 'Sudan', 
                        'Morocco', 'Angola', 'Mozambique', 'Ghana', 
                        'Madagascar', 'Cameroon', 'Niger', 'Burkina Faso', 
                        'Mali', 'Malawi', 'Zambia', 'Senegal', 'Chad', 'Somalia', 
                        'Zimbabwe', 'Guinea', 'Rwanda', 'Benin', 'Burundi', 
                        'Tunisia', 'South Sudan', 'Togo', 'Sierra Leone', 'Libya', 
                        'Democratic Republic of the Congo', 'Republic of Congo',
                        'Liberia', 'Central African Republic', 'Mauritania', 
                        'Eritrea', 'Namibia', 'Gambia', 'Botswana', 'Gabon', 'Lesotho', 
                        'Guinea-Bissau', 'Equatorial Guinea', 'Maruitius', 'Eswatini', 
                        'Djibouti', 'Comoros', 'Cabo Verde', 'Sao Tome and Principe', 
                        'Seychelles', 'Reunion', 'Western Sahara', 'Mayotte', 
                        'Saint Helena', 'Swaziland', 'Ivory Coast'), 
                        risk = c(4, 2, 1, 
                                 4, 2, 1, 
                                 2, 4, 1, 3, 
                                 1, 2, 2, 4, 
                                 1, 4, 3, 3, 
                                 3, 2, 2, 3, 3, 2, 
                                 2, 3, 4, 4, 4, 
                                 1, 3, 4, 3, 1, 
                                 4, 4, 
                                 3, 3, 1, 
                                 2, 2, 3, 2, 4, 1, 
                                 3, 4, 3, 2, 
                                 2, 1, 4, 4, 
                                 2, 1, 1, 1,
                                 1, 1, 3))
    
    table(africa_regions$risk)
    
    mapdata_x <- map_data('world') %>% filter(region %in% africa_regions$region)
    
    mapdata_x <- mapdata_x %>% left_join(africa_regions, by='region')
    
    label_data <- mapdata_x %>% group_by(region) %>% filter(row_number() == 1)
    
    ggplot(mapdata_x, aes (x = long, y = lat, group = group)) +
      geom_polygon(aes(fill = factor(risk)), linewidth = 0.25, color = "black") +
      scale_fill_manual(values = c("#a6d96a", "#ffffbf", "#fdae61", "#d7191c"),
                        name = "Risk quartile") +
      theme(axis.text.x = element_blank(),
            axis.text.y = element_blank(),
            axis.ticks = element_blank(),
            axis.title.y = element_blank(),
            axis.title.x = element_blank(),
            rect = element_blank())+
      labs(title = "Risk") +
      geom_label_repel(data = label_data, 
                       aes(x = long, y = lat, label = region), size = 3,
                       max.overlaps = 12)
    

    I used the africa_regions data frame to attempt to recreate your map, but can barely see how you have chosen the Risk quartile variable. Not really important to the question though.

    The ggrepel library automatically spaces out the labels so there is minimal overlap, which can be nice.

    There are a few issues here to still be addressed, mainly that filtering to the first data point for each region may not be the best way to approach the problem. But this should get you going in the right direction.