This is a quick post on how to create a map as per the Wikipedia conventions. In this case I have chosen to plot the international organ donor rates, retrieved on 2019-02-10 although the data refers to 2017 (Source: IRODaT).

Update 2019-10-19: The map is featured on Wikipedia.

Webscrapping

First step is to webscrap Wikipedia in order to get the final table. For doing so, I will use the rvest library. You can get the xpaht you want to webscrap as explained here.

library(rvest)
library(dplyr)

Base <-
  read_html("https://en.wikipedia.org/wiki/International_organ_donor_rates") %>%
  html_nodes(xpath = '//*[@id="mw-content-text"]/div/table[3]') %>%
  html_table() %>%
  as.data.frame(
    stringsAsFactors = F,
    fix.empty.names = F
  ) %>%
  select(Country,
    RateDonperMill = Number.of.deceased.donors..per.million.of.population
  )

knitr::kable(head(Base, 10), format = "markdown")
Country RateDonperMill
Argentina 13.33
Armenia 0.00
Australia 20.70
Austria 24.70
Azerbaijan 0.00
Bahrain 4.00
Bangladesh 0.00
Belarus 23.60
Belgium 33.62
Bolivia 0.90

Now we need to choose a good source of maps and a bit of my Country Code database, already discussed on previous posts, so here we go:

library(sf)

# Map import from Eurostat
WorldMap <-
  st_read(
    "https://ec.europa.eu/eurostat/cache/GISCO/distribution/v2/countries/geojson/CNTR_RG_10M_2016_3857.geojson",
    stringsAsFactors = FALSE
  ) %>%
  select(ISO_3166_3 = ISO3_CODE)

# CountryCode import
df <- read.csv(
  "https://raw.githubusercontent.com/dieghernan/Country-Codes-and-International-Organizations/master/outputs/Countrycodes.csv",
  na.strings = "",
  stringsAsFactors = FALSE,
  fileEncoding = "utf8"
)

WorldMap <- left_join(WorldMap, df)

Merging all together

Now let’s join and have a look to see what is going on:

DonorRate <- inner_join(WorldMap,
  Base,
  by = c("NAME.EN" = "Country")
) %>%
  select(
    NAME.EN,
    ISO_3166_3,
    RateDonperMill
  )

nrowcomp <- cbind(nrow(Base), nrow(DonorRate)) %>%
  as.data.frame()
names(nrowcomp) <- c("Initial", "After join")
knitr::kable(nrowcomp, format = "markdown")
Initial After join
94 88

Oops! Joining by name (just the string) doesn’t work for 6 cases. Not too bad but let’s try to fix it.

nameex <- anti_join(Base, DonorRate, by = c("Country" = "NAME.EN"))

knitr::kable(nameex, format = "markdown")
Country RateDonperMill
Bosnia 0.90
Czech Republic 25.51
Hong Kong 6.00
Macedonia 0.00
Slovak Republic 15.80
Taiwan 0.00
nameex$ISO_3166_3 <- c(
  "BIH",
  "CZE",
  "HKG",
  "MKD",
  "SVK",
  "TWN"
)

dfclean <- DonorRate %>%
  st_drop_geometry() %>%
  select(
    Country = NAME.EN,
    ISO_3166_3,
    RateDonperMill
  ) %>%
  rbind(nameex)

# Cleanup
rm(Base, df, nameex, DonorRate)

# Join to map
MapDonorRate <- left_join(WorldMap, dfclean) %>%
  select(
    ISO_3166_3,
    NAME.EN,
    RateDonperMill,
    area_km2
  )

Make the .svg file

As already explained, I would like to follow the Wikipedia conventions, so some things to bear in mind:

  • Obviously the colors. Wikipedia already provides a good guidance for this. I would make use of the RColorBrewerlibrary, which implements ColorBrewer in R.
  • In terms of projection, Wikipedia recommends the Equirectangular projection but, as in their own sample of a gradient map, I would choose to use the Robinson projection.
  • I should produce an .svg file following also the naming convention.

Some libraries then to use: RColorBrewer, rsvg and specially onw of my favourites, cartography:

library(RColorBrewer)
library(cartography)
library(rsvg)

# Create bbox of the world
bbox <- st_linestring(rbind(
  c(-180, 90),
  c(180, 90),
  c(180, -90),
  c(-180, -90),
  c(-180, 90)
)) %>%
  st_segmentize(5) %>%
  st_cast("POLYGON") %>%
  st_sfc(crs = 4326) %>%
  st_transform(crs = "+proj=robin")

# Create SVG
svg(
  "Organ donor rate per million by country gradient map (2017).svg",
  pointsize = 90,
  width = 1600 / 90,
  height = 728 / 90
)

par(mar = c(0.5, 0, 0, 0))
choroLayer(
  MapDonorRate %>% filter(area_km2 > 400) %>% st_transform("+proj=robin"),
  var = "RateDonperMill",
  breaks = c(0, 5, 10, 20, 30, 40, 50),
  col = brewer.pal(6, "PuBu"),
  border = "#646464",
  lwd = 0.1,
  colNA = "#E0E0E0",
  legend.pos = "left",
  legend.title.txt = "",
  legend.values.cex = 0.25
)

# Bounding box
plot(bbox,
  add = T,
  border = "#646464",
  lwd = 0.2
)

dev.off()

Organ donor rate per million by country (2017)

Click here to enlarge the image.

And that’s all. Our .svg file is ready to be uploaded to Wikipedia.