--- title: "Joining your own data" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Joining your own data} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", message = FALSE, warning = FALSE, fig.width = 7, fig.height = 4, fig.align = "center", dpi = 96 ) library(countryatlas) library(ggplot2) library(dplyr) has_sf <- requireNamespace("sf", quietly = TRUE) && requireNamespace("rnaturalearth", quietly = TRUE) && requireNamespace("rnaturalearthdata", quietly = TRUE) ``` The headline use case: *I have a frame keyed on messy country names — get it on a map.* The package exposes the same matching machinery it uses internally. ## Standardise any frame `standardize_country()` attaches ISO codes and classifications, reconciling spellings automatically: ```{r} my_data <- data.frame( nation = c("U.S.", "S. Korea", "Czechia", "Kosovo", "Cote d'Ivoire", "UK"), score = c(10, 8, 6, 4, 7, 9) ) standardize_country(my_data, nation, warn = FALSE) ``` ## One call to a map `join_world()` auto-detects the country column, standardises it and attaches geometry: ```{r} my_data |> join_world(nation, warn = FALSE) |> world_map(score, title = "My data on the ISO spine") ``` ## Reconcile two messy tables `country_join()` joins two frames that each key on country names, by reconciling both sides to `iso3c` first: ```{r} a <- data.frame(country = c("Czechia", "South Korea", "Russia"), gdp = 1:3) b <- data.frame(nation = c("Czech Republic", "Korea, Rep.", "Russian Federation"), pop = c(10, 51, 144)) country_join(a, b, country, nation) ``` ## Reconcile many tables at once `country_join_all()` generalises this to a whole list of frames: every table is reconciled to `iso3c` first, then reduce-joined — three sources spelled three ways collapse into one honest table: ```{r} t1 <- data.frame(country = c("Czechia", "South Korea"), gdp = c(1, 2)) t2 <- data.frame(country = c("Czech Republic", "Korea, Rep."), pop = c(10, 51)) t3 <- data.frame(country = c("Czechia", "Korea"), area = c(79, 100)) country_join_all(list(t1, t2, t3), by = "country") ``` ## Check before you trust Always inspect what failed to match: ```{r} check_country_match(my_data$nation) ``` ## Historical data: dissolved countries Historical panels bring a nastier failure mode: dissolved entities. Most are silently unmatched — but some are silently *mis*matched. countrycode resolves `"USSR"` to Russia's `RUS`, so Soviet-era totals quietly become Russian totals. The `historical` column in the report above flags both cases, and `dissolve_country()` resolves them to successor states via the curated `historical_codes` crosswalk (one row per successor, dated): ```{r} check_country_match(c("USSR", "Yugoslavia", "West Germany")) dissolve_country(c("Czechoslovakia", "France")) ``` `"West Germany"` is the instructive case: it resolves to `DEU` and is *not* flagged — correctly so, because the Federal Republic never dissolved. It absorbed the GDR in 1990 and simply continued, so `DEU` really is the right answer. The crosswalk is curated rather than a blanket rule that anything old-sounding gets flagged, so only the entity that actually ceased to exist is listed: `historical_codes` maps East Germany (`DDR`) to `DEU`. ## Repair what can be repaired `repair_country_names()` is the "act on it" companion to that report: it substitutes the closest known country name, but only when the match is confident, and attaches a record of what it changed: ```{r} fixed <- repair_country_names(c("Brzil", "Nehterlands", "United States"), verbose = FALSE) fixed ``` If something legitimately cannot be matched (an entity the backends simply do not know), extend the override table: ```{r} country_overrides(c(Somaliland = "SOM"))[c("Kosovo", "Somaliland")] ``` ## Custom origins If your key is already an ISO-2 or World Bank code, tell `standardize_country()` via `origin`: ```{r} df <- data.frame(code = c("US", "KR", "BR")) standardize_country(df, code, origin = "iso2c", warn = FALSE) ``` ## Point data onto the spine Not all data comes keyed on names — sometimes all you have is coordinates (events, weather stations, survey sites). `locate_country()` runs a point-in-polygon lookup and tags each point with the country that contains it, so point data joins the ISO spine like everything else. It needs the optional `sf` + `rnaturalearth` packages: ```{r eval = has_sf} locate_country(lon = c(2.35, -74.0, 139.7), lat = c(48.85, 40.7, 35.7)) ``` Coarse coastlines can place a genuinely-onshore point (a port city, say) just outside its country's simplified polygon; `locate_country()` snaps such points to the nearest country within `tolerance_km` (25 km by default) while leaving open-ocean points `NA`.