I have a data frame with two column, such as the below df
as an example, and I want to use maps::map()
in order to create a global choropleth map. I want color to be assigned to those countries exist in the df
, and for rest just empty colourless polygons. But the result is quite different with what I expected. I have tried with below script:
Also, why wolrd map has such low quality? is there a way to make this better?
df <- tribble(
~Country, ~Value,
"Jordan", 35,
"USA", 84,
"Turkey", 65,
"Pakistan", 43
)
percent_map <- function(var, color, legend.title, min = 0, max = 100) {
# generate vector of fill colors for map
shades <- colorRampPalette(c("white", color))(100)
# constrain gradient to percents that occur between min and max
var <- pmax(var, min)
var <- pmin(var, max)
percents <- as.integer(cut(var, 100,
include.lowest = TRUE, ordered = TRUE))
fills <- shades[percents]
# plot choropleth map
maps::map("world", fill = TRUE, col = fills,
resolution = 0,
myborder = 0, mar = c(0,0,0,0))
# overlay state borders
maps::map("world", col = "white", fill = FALSE, add = TRUE,
lty = 1, lwd = 1,
myborder = 0, mar = c(0,0,0,0))
}
percent_map(var = df$Value,
color = "darkgreen",
legend.title = "Global Map for Value",
min = 0, max = 100
)
What's happening here is that you take a Value
column from your tibble and get a vector of 4 values, c(35, 84, 65, 43)
, loosing any reference to actual countries. After generating fills, there's still a vector of length 4 ( c("#FFFFFF", "#006400", "#619F61", "#D5E5D5")
), which will be recycled over every country polygon. I.e. every country gets a value from your vector of 4, so 1/4 of those will end up as white and 3/4 will be some shade of green.
If it doesn't have to be a base plot and ggplot would do, you could still use data from maps::map()
(though it is from 2013, so not exactly up-to-date):
library(dplyr)
library(ggplot2)
df <- tribble(
~Country, ~Value,
"Jordan", 35,
"USA", 84,
"Turkey", 65,
"Pakistan", 43
)
# gets data from maps::map()
map_data("world") %>%
# join map dataframe with values tabl
left_join(df, by = join_by(region == Country)) %>%
ggplot(aes(long, lat)) +
geom_polygon(aes(group = group, fill = Value), color ="grey80") +
scale_fill_gradient(low = "white",
high = "darkgreen",
limits = c(1,100),
na.value = "grey99") +
coord_sf() +
theme_bw()
If it has to be a base plot but it's OK to use sf
and some other data source (like Natural Earth / rnaturalearth
package), perhaps something like this:
library(sf)
df$Country[df$Country == "USA"] <- "United States of America"
ne_world <- rnaturalearth::ne_countries(returnclass = "sf") %>%
left_join(df, by = join_by(admin == Country))
plot(ne_world["Value"],
border = 'grey80',
pal = colorRampPalette(c("white", "darkgreen"))(100),
breaks = c(0:100))
You may also want to check tmap
or sf
plotting vignette
Created on 2023-05-12 with reprex v2.0.2