Ok, with the help of some links I found two potential solutions:
Labeling center of map polygons in R ggplot
https://gis.stackexchange.com/questions/63577/joining-polygons-in-r/273515
As @camille mentioned, it basically boils down to reshaping/dissolving the original country shape file into continents.
An alternative is to manually create a small data frame where I put in the coordinate positions of each continent and add is as a text layer to a plot.
Here are the two solutions for combining/dissolving the country shapefile to a continent one:
1. Solution: dissolving in the original shaepfile / polygons object
library(rgdal)
library(broom)
library(ggplot2)
library(svglite)
library(tidyverse)
library(maptools)
library(raster)
library(rgeos)
### First part is about downloading shapefiles
# load shape files
# download.file("http://naciscdn.org/naturalearth/packages/natural_earth_vector.zip",
# "world maps.zip")
#
# unzip("folder\\world maps.zip",
# exdir = "folder\\Raw maps from zip")
### Next part is bringing the world data into the right shape and enrich with the my results
###
# read in the shape file
world = readOGR(dsn = "folder\\Raw maps from zip\\110m_cultural",
layer = "ne_110m_admin_0_countries")
# Reshape the world data so that polygons are continents not countries
world_id = world@data$CONTINENT
world_union = unionSpatialPolygons(world, world_id)
# Bring it into tidy format
world_fortified = tidy(world_union, region = "CONTINENT")
# Here I create some dummy survey results
results = data.frame(id = c("Africa", "Asia", "Europe", "North America", "Oceania", "South America"),
kpi = c(20, 30, 50, 50, 60, 70),
continent_long = c(15, 80, 20, -100, 150, -60),
continent_lat = c(15, 35, 50, 40, -25, -15),
stringsAsFactors = F)
# Combine world map with results and drop Antarctica and seaven Seas
world_for_plot = world_fortified %>%
left_join(., results, by = "id") %>%
filter(!is.na(kpi))
### plot the results.
# Let's create the plot first wit data and let's care about the labels later
plain <- theme(
axis.text = element_blank(),
axis.line = element_blank(),
axis.ticks = element_blank(),
panel.border = element_blank(),
panel.grid = element_blank(),
axis.title = element_blank(),
panel.background = element_rect(fill = "transparent"),
plot.background = element_rect(fill = "transparent"),
plot.title = element_text(hjust = 0.5)
)
# This is the actual results plot with different colours based on the results
raw_plot = ggplot(data = world_for_plot,
aes(x = long,
y = lat,
group = group)) +
geom_polygon(aes(fill = kpi)) +
coord_equal(1.3) +
scale_fill_distiller(palette = "RdYlGn", direction = 1) +
labs(fill = "kpi") +
plain
## Now automatically adding label positions form the shapefile
# We start with getting the centroid positions of each continent and delete the continents we don't have
position = coordinates(world_union)
position = data.frame(position, row.names(position))
names(position) = c("long", "lat", "id")
position = position %>%
filter(id %in% world_for_plot$id)
# We can now refer to this new data in our previously created plot object
final_plot = raw_plot +
geom_text(data = position,
aes(label = id,
x = long,
y = lat,
group = id))
# But we can also put in the continent coordinates manually. I already created some coordinates in the results object
# So we can easily use this data instead of the above calculated positions.
final_plot = raw_plot +
geom_text(data = results,
aes(label = id,
x = continent_long,
y = continent_lat,
group = id))
2. Solution: Using sf objects in a more data frame like way
library(sf)
library(tidyverse)
library(ggplot2)
# I dropped the part of downloading the shapefile here. See solution 1 for that.
world = read_sf(dsn = "folder\\Raw maps from zip\\110m_cultural",
layer = "ne_110m_admin_0_countries")
# Next we just do some tidy magic and group the data by CONTINENT and get the respective coordinates in a long list
continents = world %>%
group_by(CONTINENT) %>%
summarise(.)
# Here I create some dummy survey results
results = data.frame(CONTINENT = c("Africa", "Asia", "Europe", "North America", "Oceania", "South America"),
kpi = c(20, 30, 50, 50, 60, 70),
continent_long = c(15, 80, 20, -100, 150, -60),
continent_lat = c(15, 35, 50, 40, -25, -15),
stringsAsFactors = F)
# Now let's join the continent data with the results
world_for_plot = continents %>%
left_join(., results, by = c("CONTINENT")) %>%
filter(!is.na(kpi))
### Now we can plot the results.
# Let's create the plot first with data and let's care about the labels later
plain <- theme(
axis.text = element_blank(),
axis.line = element_blank(),
axis.ticks = element_blank(),
panel.border = element_blank(),
panel.grid = element_blank(),
axis.title = element_blank(),
panel.background = element_rect(fill = "transparent"),
plot.background = element_rect(fill = "transparent"),
plot.title = element_text(hjust = 0.5)
)
# This is the actual results plot with different colours based on the results
raw_plot = ggplot(data = world_for_plot) +
geom_sf(aes(fill = kpi),
colour=NA) +
coord_sf() +
scale_fill_distiller(palette = "RdYlGn", direction = 1) +
plain
# Now we can add the labels
final_plot = raw_plot +
geom_sf_text(aes(label=CONTINENT))
# We could also use our own label positions
final_plot = raw_plot +
geom_text(aes(label = CONTINENT,
x = continent_long,
y = continent_lat,
group = CONTINENT))
Happy to hear your thoughts about it.
Please note that the plot below is the one where I actually manually positioned the labels.
