| Type: | Package |
| Title: | Join World Bank Data, Country Codes and Maps on the ISO Spine |
| Version: | 2.0.0 |
| Description: | A complete toolkit for getting country data onto honest maps. Country names rarely line up across data sources ("US", "U.S.", "United States", "United States of America" are one country, but a naive join treats them as four), so 'countryatlas' makes ISO codes the universal join key. It generalises a one-call, map-ready table that stitches together 'ggplot2' map geometry, 'WDI' World Bank indicators and the 'countrycode' Rosetta stone; exposes the join machinery for the user's own data; ships curated reference data (metadata, group memberships, an indicator catalogue, flags and currencies); adds analysis helpers (per-capita, regional roll-ups, ranking, inequality and convergence statistics); and turns one hand-drawn choropleth into a full vocabulary of projected, area-honest maps (binned and quantile choropleths, proportional-symbol, spike, bivariate, cartogram, tile-grid, flow, small-multiple, animated, globe and interactive), and can hand its curated, ISO-reconciled tables to 'ggsql' for database-side spatial rendering. Heavy spatial dependencies stay optional, and a bundled offline snapshot lets every example, test and vignette run without the network. |
| License: | GPL (≥ 3) |
| URL: | https://pursuitofdatascience.github.io/countryatlas/, https://github.com/PursuitOfDataScience/countryatlas |
| BugReports: | https://github.com/PursuitOfDataScience/countryatlas/issues |
| Encoding: | UTF-8 |
| LazyData: | true |
| Depends: | R (≥ 4.1.0) |
| Imports: | cli, countrycode, dplyr, ggplot2, memoise, rlang, tibble, tidyr, WDI |
| Suggests: | biscale, cartogram, classInt, covr, DBI, duckdb, gganimate, ggiraph, ggrepel, ggsql, gifski, knitr, leaflet, magick, mapproj, maps, nanoarrow, plotly, rmapshaper, rmarkdown, rnaturalearth, rnaturalearthdata, scales, sf, stringdist, testthat (≥ 3.0.0) |
| VignetteBuilder: | knitr |
| Config/testthat/edition: | 3 |
| Config/roxygen2/version: | 8.0.0 |
| RoxygenNote: | 7.3.2 |
| NeedsCompilation: | no |
| Packaged: | 2026-08-24 16:22:01 UTC; youzhi |
| Author: | Youzhi Yu [aut, cre] |
| Maintainer: | Youzhi Yu <yuyouzhi666@icloud.com> |
| Repository: | CRAN |
| Date/Publication: | 2026-08-25 05:10:02 UTC |
countryatlas: join World Bank data, country codes and maps on the ISO spine
Description
countryatlas exists to kill one recurring source of pain: country names
never line up across data sources. The package makes ISO codes the universal
join key and hands you a ready-to-map tibble that stitches together map
geometry (ggplot2::map_data() or Natural Earth sf), World Bank indicators
(WDI::WDI()) and the countrycode::countrycode() crosswalk.
Details
The happy path stays one call: world_data(). Everything else is opt-in.
Core data assembly
world_data(), country_data(), world_geometry(), locate_country(),
country_borders(), neighbors(), distance_between().
The join engine
standardize_country(), join_world(), attach_geometry(), country_join(),
country_join_all(), dissolve_country().
Diagnostics
check_country_match(), repair_country_names(), country_overrides(),
audit_coverage().
Reference data
convert_country(), country_codes(), country_groups(), in_group(),
wdi_search(), and the datasets country_meta, common_indicators,
country_groups_tbl, world_snapshot, world_tiles, historical_codes.
Analysis helpers
per_capita(), aggregate_regions(), rank_countries(), complete_years(),
growth_rate(), index_to(), share_of_world(), lag_by_country(),
diff_by_country(), correlate_indicators(), beta_convergence(),
sigma_convergence(), gini(), theil(), morans_i().
Visualization
world_map(), globe_map(), spin_globe(), facet_map(), bubble_map(),
spike_map(), bivariate_map(), cartogram_map(), dorling_map(),
tile_map(), flow_map(), animate_world(), interactive_map(),
geom_country_labels(), theme_world_map(), simplify_geometry().
Database rendering (ggsql)
as_ggsql_source(), world_query().
Performance & caching
Options
Three options change the package's behaviour. All are unset by default.
countryatlas.cache_dirWhere the persistent World Bank cache lives. Defaults to
tools::R_user_dir("countryatlas", "cache"); set it to""for session-only caching. Seeclear_wdi_cache().countryatlas.workersHow many processes fetch indicators in parallel (only when the cache is on disk – a memory-only memo cannot survive a fork). Defaults to one fewer than the available cores, and to 2 under
R CMD check, per CRAN policy. Must be a single finite number; values below one are clamped to one.countryatlas.gdp_compatSet to
TRUEto restore thegdp_per_capita_2015column thatworld_data()emitted in 1.0.0. It is a one-cycle deprecation shim and off by default.
Author(s)
Maintainer: Youzhi Yu yuyouzhi666@icloud.com
See Also
Useful links:
Report bugs at https://github.com/PursuitOfDataScience/countryatlas/issues
Roll countries up to region / income / continent
Description
Aggregate a country-level value to a coarser grouping, optionally with population-weighted means.
Usage
aggregate_regions(data, value, by = "region", fun = "sum", weight = NULL)
Arguments
data |
A country-level data frame. |
value |
The value column to aggregate (unquoted). |
by |
Grouping column(s) (character), default |
fun |
Aggregation: |
weight |
Optional weight column (unquoted) for |
Value
A tibble of by plus the aggregated value.
Groups with no data
Missing values are dropped before aggregating, so a group is summarised from
whatever it does have. A group with no non-missing value returns NA
rather than a figure: sum() would otherwise report 0, mean() NaN and
min()/max() -Inf/Inf, each of which reads as a real total for a
region we simply have no data for. Use audit_coverage() to see where those
gaps are.
Examples
df <- data.frame(iso3c = c("USA", "CAN", "BRA"),
region = c("North America", "North America", "Latin America"),
gdp = c(21, 1.7, 1.4))
aggregate_regions(df, gdp, fun = "sum")
Animate a choropleth over time
Description
Given a panel from world_data(2000:2020, ...), animate the choropleth over
year via the optional gganimate package, or fall back to a faceted
small-multiple when it is not installed.
Usage
animate_world(data, fill, time = year, projection = "equal_earth", ...)
Arguments
data |
A panel map-ready frame (polygon or sf) with a |
fill |
The fill column (unquoted). |
time |
The time column (unquoted; default |
projection |
Projection for the sf backend. See |
... |
Passed to |
Value
A gganim object (if gganimate is available) or a faceted
ggplot.
Examples
## Not run:
world_data(2000:2005, c(gdp = "NY.GDP.PCAP.KD")) |>
animate_world(gdp)
## End(Not run)
Export a countryatlas table as a ggsql source
Description
Hand countryatlas's curated, ISO-reconciled, WDI-joined spatial table to
ggsql so it can be charted with DRAW spatial – the
bridge that lets ggsql draw maps of your override-corrected data instead of
its static bundled world. sf geometry is WKB-encoded so ggsql can decode it.
Usage
as_ggsql_source(
data,
name = "countryatlas_world",
format = c("duckdb", "parquet", "arrow"),
con = NULL,
path = NULL,
geometry_col = "geometry"
)
Arguments
data |
A map-ready frame (ideally |
name |
The table name to register/write (default |
format |
|
con |
An existing DuckDB |
path |
Output path for |
geometry_col |
Name for the WKB geometry column (default |
Value
Depending on format: a DuckDB connection (with the table written),
a Parquet file path, or a nanoarrow array stream.
Examples
## Not run:
# Curate in R, render in the database:
src <- world_data(2020, geometry = "sf") |> as_ggsql_source(format = "duckdb")
ggsql::ggsql_execute(src, world_query(gdp_per_capita))
## End(Not run)
Attach geometry to a country-level table
Description
The bridge between a one-row-per-country table (e.g. from country_data())
and plotting: bolts polygon or sf geometry onto your data, keyed on
iso3c.
Usage
attach_geometry(
data,
by = "iso3c",
geometry = c("polygon", "sf"),
scale = "small",
region = NULL,
projection = "equal_earth",
recenter = NULL,
overrides = country_overrides()
)
Arguments
data |
A data frame with an |
by |
The join key (default |
geometry |
|
scale |
Natural Earth resolution for the |
region |
Optional region subset (see |
projection, recenter |
Projection, and optional central meridian, for
the |
overrides |
Name -> iso3c overrides applied when matching the geometry
backend's country names (default |
Value
For "polygon", a tibble with long/lat/group plus your
columns. For "sf", an sf object.
One row in, one row out
Geometry is attached once per row, not once per country. That is what a panel wants – one row per country-year, each carrying the shape – but it means a frame that repeats a country by accident draws that country more than once, and only the last one painted is visible. The package cannot tell the two apart (a panel's time column may be called anything), so reduce to one row per country yourself when that is what you meant.
Which countries have geometry
The join keeps only countries the chosen backend actually carries, so rows of
data with no matching geometry are dropped silently – worth checking first
when a country you expected is missing from the map. Coverage differs by
backend and, for "sf", by scale, which changes which countries are
present and not merely how detailed they look. Of the 215 countries in
world_snapshot, "polygon" carries 210, "sf" with scale = "small" (the
default, 110m) carries 169, and "sf" with scale = "medium" carries 214:
the 110m coastlines omit most small states, so scale = "medium" is the fix
when microstates matter – Hong Kong, Macao, Tuvalu and the British Virgin
Islands are each in no other backend. Gibraltar alone is in none of them.
Examples
df <- data.frame(iso3c = c("USA", "CAN"), value = c(1, 2))
if (requireNamespace("maps", quietly = TRUE)) {
attach_geometry(df, geometry = "polygon")
}
Coverage / missingness audit
Description
What is missing, before you trust the map: which countries are unmatched,
the NA rate per indicator, and which World Bank regions / income groups are
under-covered – so a half-empty map is caught before it is published.
Usage
audit_coverage(data, indicator = NULL, by = c("region", "income", "continent"))
Arguments
data |
A country-level (or map-ready) data frame. |
indicator |
Optional character vector of value columns to report |
by |
Grouping for the coverage breakdown: |
Value
A list of class countryatlas_coverage, with elements unmatched,
na_rates and by_group. It has a print() method, so at the console you
see a formatted report rather than the raw list; reach into the elements by
name to use the numbers programmatically.
Examples
audit_coverage(countryatlas::world_snapshot$countries)
Beta convergence (growth regression)
Description
Do poor countries grow faster than rich ones? The classic unconditional
beta-convergence test: each country's average log growth rate is regressed
on its log initial level. A significantly negative beta is convergence;
the implied convergence speed and half_life (years to close half the
gap) are derived from it.
Usage
beta_convergence(data, value)
Arguments
data |
A panel with |
value |
The value column (unquoted); must be positive (log scale). |
Value
A one-row tibble: beta, se, t_value, p_value, r_squared,
n (countries), speed (annual convergence rate, NA when beta >= 0)
and half_life (years). The fitted lm object is attached as the
"model" attribute.
See Also
sigma_convergence() for the dispersion-over-time counterpart.
Examples
set.seed(1)
start <- runif(20, 6, 11) # log initial level
growth <- 0.05 - 0.004 * start + rnorm(20, 0, 0.002) # poorer grow faster
panel <- data.frame(
iso3c = rep(sprintf("C%02d", 1:20), each = 2),
year = rep(c(2000L, 2020L), 20),
gdp = as.vector(rbind(exp(start), exp(start + growth * 20)))
)
beta_convergence(panel, gdp)
Two-variable bivariate choropleth
Description
A 2-D bivariate choropleth with a built-in 2-D legend (via the optional
biscale package), e.g. GDP per capita x life expectancy in one map.
Usage
bivariate_map(
data,
fill_x,
fill_y,
palette = "GrPink",
dim = 3,
projection = "equal_earth"
)
Arguments
data |
An |
fill_x, fill_y |
The two value columns (unquoted). |
palette |
A |
dim |
Bivariate dimension (2 or 3, default 3). |
projection |
Projection; see |
Value
A ggplot object (the map; combine with biscale::bi_legend() for a
standalone legend).
Examples
if (requireNamespace("sf", quietly = TRUE) &&
requireNamespace("rnaturalearth", quietly = TRUE) &&
requireNamespace("biscale", quietly = TRUE)) {
attach_geometry(countryatlas::world_snapshot$countries, geometry = "sf") |>
bivariate_map(gdp_per_capita, life_expectancy)
}
Proportional-symbol (bubble) map
Description
Plots sized circles at country centroids – the right idiom for totals (population, total emissions, total GDP), which a choropleth misrepresents because big values hide in small countries and vice versa.
Usage
bubble_map(
data,
size,
color = NULL,
projection = "equal_earth",
backend = c("polygon", "sf"),
max_size = 18,
alpha = 0.7
)
Arguments
data |
A country-level frame with |
size |
The column controlling bubble size (unquoted). |
color |
Optional column controlling bubble colour (unquoted). |
projection |
Projection for the base map (sf path). See |
backend |
|
max_size |
Largest bubble size. |
alpha |
Bubble transparency. |
Value
A ggplot object.
Examples
snap <- countryatlas::world_snapshot$countries
if (requireNamespace("maps", quietly = TRUE)) {
bubble_map(snap, population)
}
Area-honest cartogram
Description
Resizes countries by weight (population, GDP, ...) via the optional
cartogram package, defeating the "big empty countries dominate the eye"
bias of world choropleths.
Usage
cartogram_map(
data,
weight,
type = c("contiguous", "dorling", "noncontiguous"),
fill = NULL,
projection = "equal_earth",
...
)
Arguments
data |
An |
weight |
The column to resize by (unquoted). |
type |
|
fill |
Optional fill column (unquoted); defaults to |
projection |
Projection; an equal-area CRS is recommended. See
|
... |
Passed to the underlying |
Value
A ggplot object.
Examples
if (requireNamespace("sf", quietly = TRUE) &&
requireNamespace("rnaturalearth", quietly = TRUE) &&
requireNamespace("cartogram", quietly = TRUE)) {
attach_geometry(countryatlas::world_snapshot$countries, geometry = "sf") |>
cartogram_map(population, type = "dorling")
}
Pre-flight country-match report
Description
A report on what will and will not match before you trust the map: the
input, its iso3c, whether it matched, whether it is a historical
(dissolved) entity, and a suggestion (the closest known country name by
string distance) for misses. Surfaced automatically by join_world().
Usage
check_country_match(
x,
origin = "country.name",
custom_match = country_overrides(),
suggest = TRUE
)
Arguments
x |
A vector of country names or codes. |
origin |
How to read |
custom_match |
Overrides applied before matching (default
|
suggest |
Whether to compute closest-name suggestions for misses
(requires the optional |
Details
The historical flag matters even for rows that matched: countrycode
silently resolves "USSR" to Russia's RUS, so Soviet-era data becomes
Russian data without a warning. Rows flagged historical should usually be
routed through dissolve_country() instead.
Value
A tibble with columns input, iso3c, matched, historical,
suggestion.
See Also
dissolve_country() for resolving the entities this flags as
historical to their successor states, and repair_country_names() for
applying the suggestion column automatically.
Examples
check_country_match(c("USA", "Cote d'Ivoire", "Yugoslavia", "Wakanda"))
# "USSR" matches (to RUS!) but is flagged historical:
check_country_match("USSR")
Clear the on-disk / in-memory WDI cache
Description
Forget memoised World Bank fetches, both in-session and (optionally) on disk.
Usage
clear_wdi_cache(disk = FALSE)
Arguments
disk |
Whether to also delete the persistent on-disk cache. |
Value
Invisibly TRUE.
Where the cache lives
The persistent cache goes in the standard per-user cache location,
tools::R_user_dir("countryatlas", "cache"). Point it elsewhere with
options(countryatlas.cache_dir = ), or skip the disk entirely by passing
cache = FALSE to world_data() / country_data(). Nothing is written
until a World Bank fetch actually succeeds, so a purely offline session
(examples, tests, the bundled world_snapshot) never creates it.
Examples
clear_wdi_cache() # forget the in-session memo
## Not run:
clear_wdi_cache(disk = TRUE) # also delete the persistent cache
## End(Not run)
Curated indicator catalogue
Description
A friendly-name to WDI-code lookup so indicator = common_indicators$population
beats memorising "SP.POP.TOTL".
Usage
common_indicators
Format
A tibble with columns name (friendly name), code (WDI indicator
code) and description.
Source
World Bank indicator catalogue.
Fill or interpolate panel gaps
Description
Completes a panel so every country has every year, optionally filling missing
values by carry-forward ("locf") or linear interpolation ("linear") so
animations do not flicker on missing years.
Usage
complete_years(
data,
years = NULL,
value = NULL,
method = c("none", "locf", "linear")
)
Arguments
data |
A panel with |
years |
The full set of years to complete to. Defaults to the observed min:max. |
value |
Optional value column(s) (character) to fill. If |
method |
|
Value
A completed (and optionally filled) panel tibble.
Examples
df <- data.frame(iso3c = "USA", year = c(2000L, 2002L), gdp = c(1, 3))
complete_years(df, 2000:2002, method = "linear")
Friendly country-code conversion
Description
A discoverable wrapper around countrycode::countrycode() exposing the full
set of schemes with first-class shortcuts for the high-value ones: flag
emoji, currency, top-level domain, continent/region and research codes
(Correlates of War, Polity, Gleditsch-Ward, V-Dem, IMF, FAO, FIPS, GAUL).
Usage
convert_country(
x,
to = "iso3c",
from = "country.name",
custom_match = country_overrides(),
warn = TRUE
)
Arguments
x |
A vector of country names or codes. |
to |
Destination scheme. A shortcut ( |
from |
Origin scheme (default |
custom_match |
Optional overrides (default |
warn |
Whether to warn about inputs that match no country (default
|
Value
A vector of converted codes.
Examples
convert_country(c("Japan", "Brazil"), to = "flag")
convert_country("Germany", to = "currency")
convert_country(c("USA", "France"), to = "continent")
convert_country(c("Germany", "United States"), to = "name_fr")
Pairwise correlation of indicators on the spine
Description
Which indicators move together across countries? Computes pairwise
correlations between indicator columns (pairwise-complete, so patchy
coverage doesn't shrink every pair to the common subset), with the per-pair
n reported so a headline r computed on 12 countries can't masquerade as
a world fact.
Usage
correlate_indicators(data, ..., method = c("pearson", "spearman"), min_n = 3)
Arguments
data |
A country-level (or map-ready) data frame; map-ready frames are
reduced to one row per country first, so the reported |
... |
< |
method |
|
min_n |
Minimum number of complete pairs for a correlation to be
reported (default |
Value
A tibble with one row per indicator pair: var_x, var_y, r,
n (complete pairs), sorted by |r| descending.
Examples
correlate_indicators(countryatlas::world_snapshot$countries)
Country adjacency (shared land borders)
Description
Which countries share a land border with which, as a tidy edge list –
built from polygon topology (sf::st_touches()), so it reflects the same
curated geometry as the rest of the package. Powers neighbors().
Usage
country_borders(scale = "small", region = NULL)
Arguments
scale |
Natural Earth resolution to compute adjacency from. Coarser
scales simplify small slivers and may miss a handful of short borders.
|
region |
Optional region subset (see |
Value
A tibble, one row per bordering pair: iso3c_a, country_a,
iso3c_b, country_b. Each unordered pair appears once, with
iso3c_a <= iso3c_b alphabetically.
Turning it into a graph
igraph::graph_from_data_frame() takes the first two columns as the edge
endpoints, so pass only the two code columns – handing it the whole tibble
would build edges from each country's code to its own name:
igraph::graph_from_data_frame(
country_borders()[, c("iso3c_a", "iso3c_b")], directed = FALSE)
Attaching igraph also masks neighbors(), which it exports too, so call
that one as countryatlas::neighbors() from then on.
Examples
if (requireNamespace("sf", quietly = TRUE) &&
requireNamespace("rnaturalearth", quietly = TRUE)) {
head(country_borders(region = "Europe"))
# The whole world is only a little dearer: a fraction of a second.
nrow(country_borders())
}
The countrycode codelist as a tidy tibble
Description
The whole countrycode::codelist reshaped into a tidy, pipeable lookup you
can filter() / join() directly – one row per country.
Usage
country_codes(codes = NULL)
Arguments
codes |
Optional character vector of column names to keep (in addition
to |
Value
A tibble, one row per country.
Examples
country_codes()
country_codes(c("iso2c", "continent", "currency"))
Lightweight one-row-per-country table
Description
The analysis counterpart to world_data(): no polygons, one tidy row per
country (iso3c, iso2c, country, classifications and the requested
indicators). This is what you actually join() / mutate() / summarise()
/ rank() on; attach geometry only at draw time with attach_geometry().
Usage
country_data(
year,
indicator = NULL,
latest = FALSE,
panel = FALSE,
classify = c("income", "continent", "region"),
cache = TRUE,
language = "en",
parallel = TRUE
)
Arguments
year |
A single year or a range (with |
indicator |
A named character vector of WDI codes (or |
latest |
Use the most recent non- |
panel |
Return a panel keyed on |
classify |
Which classifications to add. |
cache |
Whether to use the WDI cache. |
language |
WDI language code. |
parallel |
Whether to fetch indicators in parallel. Ignored when the
cache is memory-only; see |
Value
A tibble, one row per country (or per country-year for a panel).
iso3c is the stable key; country is a label and its spelling depends on
where the row came from. A successful fetch carries the World Bank's names
("Korea, Rep.", "Congo, Dem. Rep."), while the country spine used when the
fetch returns nothing carries the countrycode names ("South Korea",
"Congo - Kinshasa") – as do convert_country(), standardize_country()
and the rest of the package. Match on iso3c, and relabel with
convert_country(iso3c, to = "country") if you need one consistent set.
Examples
country_data(2020, c(co2 = "EN.GHG.CO2.MT.CE.AR5"))
Country-group membership
Description
Answers the constant question "is this country in the EU / OECD / G7 / G20 / BRICS / ...?" from a curated, dated membership table (point-in-time membership is genuinely fiddly, so it is shipped and maintained, not guessed). See country_groups_tbl.
Usage
country_groups(group = NULL)
Arguments
group |
One or more group names: any of |
Value
A tibble of group, iso3c, country.
Examples
country_groups("EU")
country_groups(c("G7", "BRICS"))
Country-group membership (point-in-time)
Description
A curated, dated membership table for the common country groups.
Usage
country_groups_tbl
Format
A tibble with columns group, iso3c, country.
Source
Curated from official membership lists (point-in-time; see the
package NEWS for the reference date).
Reconcile and join two messy country tables
Description
The generic two-table version of the package's whole reason for being: join
any two data frames that each key on country names or codes, by reconciling
both sides to iso3c first. Tables keyed on "Czech Republic" vs
"Czechia", or "South Korea" vs "Korea, Rep.", just work.
Usage
country_join(
x,
y,
by_x,
by_y,
origin_x = "country.name",
origin_y = "country.name",
type = c("left", "inner", "full"),
suffix = c(".x", ".y")
)
Arguments
x, y |
Data frames to join. |
by_x, by_y |
The country columns in |
origin_x, origin_y |
How to read each key (countrycode origin schemes). |
type |
Join type: |
suffix |
Suffix for clashing non-key columns (default
|
Value
A tibble joined on a reconciled iso3c key.
Examples
a <- data.frame(country = c("Czechia", "South Korea"), gdp = c(1, 2))
b <- data.frame(nation = c("Czech Republic", "Korea, Rep."), pop = c(10, 51))
country_join(a, b, country, nation)
Join many messy country tables on the ISO spine
Description
The many-table generalisation of country_join(): reduce-join a list of data
frames that each key on country names or codes, reconciling every one to
iso3c first.
Usage
country_join_all(
tables,
by,
origin = "country.name",
type = c("full", "left", "inner")
)
Arguments
tables |
A list of data frames. |
by |
A single country-column name present in every table, or a character vector giving the column for each table. |
origin |
countrycode origin scheme(s) for the key column(s) (default
|
type |
Join type: |
Value
A single tibble joined on iso3c (clashing non-key columns get
dplyr's default .x/.y suffixes).
Examples
a <- data.frame(country = c("Czechia", "South Korea"), gdp = c(1, 2))
b <- data.frame(country = c("Czech Republic", "Korea, Rep."), pop = c(10, 51))
d <- data.frame(country = c("Czechia", "Korea"), area = c(79, 100))
country_join_all(list(a, b, d), by = "country")
Static per-country metadata
Description
One row per country with the facts people constantly need and currently scrape together by hand.
Usage
country_meta
Format
A tibble with one row per country and columns including iso3c,
iso2c, country, continent, region, un_region, capital,
capital_lat, capital_lon, centroid_lat, centroid_lon, area_km2,
currency, tld, landlocked, flag.
Assembled from countrycode::codelist, so Kosovo (XKX) has no row –
countrycode has none either. The geometry backends and
convert_country() do handle it; distance_between(), which reads its
centroids from here, does not. Ten further territories have a row but no
centroid or area.
country therefore carries the English names from countrycode
("South Korea", "Congo - Kinshasa"), which differ from the World Bank's for
38 of the 215 countries in world_snapshot ("Korea, Rep.",
"Congo, Dem. Rep."). Each
table is faithful to its own source, so join on iso3c and keep whichever
label you want to display – reconciling the two is what country_join()
is for.
Source
Assembled from countrycode, WDI metadata and Natural Earth geometry.
Resolve dissolved entities to their successor states
Description
Historical data is full of countries that no longer exist – the USSR,
Yugoslavia, Czechoslovakia – and they poison naive joins twice over: most
are silently unmatched, and some are silently mismatched
(countrycode resolves "USSR" to Russia alone, so Soviet-era totals
quietly become Russian totals). dissolve_country() resolves a mixed
vector of historical and modern names against the curated
historical_codes crosswalk: dissolved entities expand to one row per
successor state (one-to-many, dated), while modern names pass through as
single rows – so a whole messy column can be piped in unchanged.
Usage
dissolve_country(x, warn = TRUE)
Arguments
x |
A character vector of country names (historical and/or modern). |
warn |
Whether to warn about names that match neither a historical
entity nor a modern country (default |
Value
A tibble with one row per (input, successor) pair: input (as
given), historical (canonical dissolved-entity name, NA for modern
countries), dissolved (year the entity ceased to exist, NA for
modern), iso3c and country (the successor state). Unmatched inputs
yield one row with iso3c = NA.
See Also
historical_codes for the crosswalk itself and the successor
policy (e.g. Kosovo's inclusion in the Yugoslavia list);
check_country_match(), whose historical column flags these entities;
repair_country_names(), which deliberately leaves them alone.
Examples
dissolve_country(c("USSR", "Czechoslovakia", "France"))
# One-to-many: Yugoslavia expands to its successor territories
dissolve_country("Yugoslavia")
Great-circle distance between two countries
Description
Haversine distance (km) between two countries' centroids – the lightweight
companion to country_borders() for "how far apart" rather than "do they
touch". Works from the bundled country_meta centroids, so unlike most of
the spatial toolkit it needs neither sf nor the network.
Usage
distance_between(a, b, origin = "country.name")
Arguments
a, b |
Vectors of country names or codes. Either the same length, or one of them length 1 to compare one country against many. |
origin |
How to read |
Value
A numeric vector of great-circle distances in kilometres (NA for
any country that doesn't resolve to a known centroid).
Countries without a bundled centroid
country_meta carries no centroid for a handful of small or dependent
territories (Bouvet Island, the British Virgin Islands, Gibraltar, Hong Kong,
Macao, Svalbard and Jan Mayen, Tokelau, Tuvalu, the U.S. Minor Outlying
Islands and the Aland Islands), and no row at all for Kosovo, because
countrycode::codelist has none. Those inputs return NA here even though
the geometry backends do map them – so neighbors() and country_borders()
know about Kosovo while this function does not.
Examples
distance_between("France", "Germany")
distance_between("USA", c("Canada", "Mexico"))
Dorling cartogram (first-class verb)
Description
Non-overlapping proportional circles sized by weight, positioned to stay
as close as possible to each country's true location – arguably the most
legible cartogram variant, since a microstate's circle is exactly as
visible as a giant country's. A first-class verb for
cartogram_map()(type = "dorling") that surfaces the Dorling-specific
tuning knobs.
Usage
dorling_map(
data,
weight,
fill = NULL,
k = 5,
itermax = 1000,
projection = "equal_earth"
)
Arguments
data |
An |
weight |
The column controlling circle size (unquoted). |
fill |
Optional fill column (unquoted); defaults to |
k |
Share of the bounding box filled by the largest circle (default
|
itermax |
Maximum iterations of the circle-repulsion algorithm
(default |
projection |
Projection; an equal-area CRS is recommended. See
|
Value
A ggplot object.
Examples
if (requireNamespace("sf", quietly = TRUE) &&
requireNamespace("rnaturalearth", quietly = TRUE) &&
requireNamespace("cartogram", quietly = TRUE)) {
attach_geometry(countryatlas::world_snapshot$countries, geometry = "sf") |>
dorling_map(population)
}
Small-multiple choropleths
Description
Facet a choropleth into small multiples (one panel per group or per year) –
the static counterpart to animate_world(), for print and side-by-side
comparison. Builds a world_map() and facets it on facet.
Usage
facet_map(data, fill, facet, ncol = NULL, ...)
Arguments
data |
A map-ready frame (polygon or sf) containing the |
fill |
The fill column (unquoted). |
facet |
The faceting column (unquoted; e.g. |
ncol |
Number of facet columns (passed to |
... |
Passed to |
Value
A faceted ggplot object.
Examples
snap <- countryatlas::world_snapshot$countries
if (requireNamespace("maps", quietly = TRUE)) {
mapdf <- attach_geometry(snap, geometry = "polygon")
facet_map(mapdf, gdp_per_capita, continent, style = "quantile")
}
Great-circle origin-destination flow map
Description
Draws great-circle arcs between country pairs from an origin-destination table (trade, migration, flights, remittances), resolving both endpoints to centroids automatically.
Usage
flow_map(data, from, to, weight = NULL, origin = "country.name", n = 50)
Arguments
data |
An OD table. |
from, to |
The origin and destination country columns (unquoted; names
or |
weight |
Optional column controlling arc width/alpha (unquoted). |
origin |
How to read |
n |
Points per arc (smoothness). |
Value
A ggplot object.
Examples
od <- data.frame(from = c("China", "Germany"),
to = c("United States", "France"),
value = c(500, 200))
if (requireNamespace("maps", quietly = TRUE)) {
flow_map(od, from, to, value)
}
Centroid-anchored country labels
Description
A ggplot2 layer that places labels (names, ISO codes or flag emoji) at
country centroids, with optional ggrepel collision avoidance. Designed for
the polygon backend produced by world_data() / join_world(): it reads the
long, lat and group columns, so it errors on an sf frame and points at
ggplot2::geom_sf_text() instead. Placement is exact only while group is
present – that is what identifies each country's separate pieces, and the
label goes on the largest one.
Usage
geom_country_labels(mapping = NULL, repel = TRUE, flag = FALSE, size = 3, ...)
Arguments
mapping |
Aesthetic mapping; defaults to |
repel |
Use |
flag |
If |
size |
Label text size. |
... |
Passed to the underlying text geom. |
Value
A ggplot2 layer.
Examples
library(ggplot2)
snap <- countryatlas::world_snapshot$countries
if (requireNamespace("maps", quietly = TRUE)) {
mapdf <- attach_geometry(snap, geometry = "polygon")
world_map(mapdf, gdp_per_capita) + geom_country_labels()
}
Gini coefficient (population-weightable)
Description
The Gini index of inequality across countries, optionally weighted (weight by population and the statistic describes inequality between people assigned their country's mean, not between country units).
Usage
gini(x, weights = NULL, na.rm = TRUE)
Arguments
x |
A numeric vector (e.g. GDP per capita by country). |
weights |
Optional non-negative weights (e.g. population), either the
same length as |
na.rm |
Whether to drop |
Value
A single number in [0, 1]: 0 is perfect equality.
See Also
theil(), which adds a between/within-group decomposition.
Examples
snap <- countryatlas::world_snapshot$countries
gini(snap$gdp_per_capita) # between countries
gini(snap$gdp_per_capita, weights = snap$population) # between people
Orthographic globe choropleth
Description
The world as a globe (orthographic projection) centred on lon/lat – the
honest answer to "the whole world on a rectangle exaggerates the poles". Takes
the same fill / style options as world_map(). The default "sf" backend
gives the cleanest limb; the "polygon" backend draws the globe with
ggplot2::coord_map() and needs only maps + mapproj (no sf).
Usage
globe_map(
data,
fill,
lon = 0,
lat = 20,
backend = c("sf", "polygon"),
style = c("continuous", "binned", "quantile", "jenks", "categorical"),
palette = NULL,
n_bins = 5,
borders = TRUE,
title = NULL,
legend = NULL,
na_label = "No data"
)
Arguments
data |
A map-ready frame: an |
fill |
The fill column (unquoted). |
lon, lat |
The longitude / latitude the globe is centred on (the face pointing at the viewer). |
backend |
|
style, palette, n_bins, borders, title, legend, na_label |
As in |
Value
A ggplot object.
Examples
# No sf required -- the polygon backend needs only maps + mapproj:
if (requireNamespace("maps", quietly = TRUE) &&
requireNamespace("mapproj", quietly = TRUE)) {
globe_map(countryatlas::world_snapshot$countries, continent,
backend = "polygon", style = "categorical")
}
## Not run:
# The sf backend gives the cleanest limb (needs a World Bank fetch):
world_data(2020, geometry = "sf") |>
globe_map(gdp_per_capita, lon = 10, lat = 30)
## End(Not run)
Year-on-year (or compound) growth rate
Description
Adds a growth-rate column to a panel: either the period-over-period change
("yoy") or the compound annual growth rate from the first observed year
("cagr"), computed per country.
Usage
growth_rate(data, value, type = c("yoy", "cagr"), suffix = "_growth")
Arguments
data |
A panel with |
value |
The value column (unquoted). |
type |
|
suffix |
Suffix for the new column (default |
Value
data with a growth-rate column added (a proportion, so 0.03 = 3%).
Examples
df <- data.frame(iso3c = "USA", year = 2000:2002, gdp = c(100, 110, 121))
growth_rate(df, gdp)
Historical / dissolved entities and their successor states
Description
A curated crosswalk from dissolved entities (Soviet Union, Yugoslavia,
Czechoslovakia, ...) to the modern states that succeeded them – one row per
(entity, successor) pair, dated, so historical panels can be brought onto
the modern ISO spine honestly instead of being silently dropped (or worse:
countrycode resolves "USSR" to Russia alone). Consumed by
dissolve_country() and flagged by check_country_match().
Usage
historical_codes
Format
A tibble with one row per (entity, successor):
- historical
Canonical name of the dissolved entity.
- iso3c_hist
The alpha-3 code the entity held at dissolution, where one existed (
SUN,YUG,CSK,DDR,ANT,SCG,YMD, ...); it may since have been inherited by a successor (e.g.YEM).- dissolved
Year the entity ceased to exist.
- iso3c, country
The successor state.
Details
Kosovo (XKX) is included among the Yugoslavia and Serbia-and-Montenegro
successors on a territory basis (its territory was part of both); filter
it out if your analysis follows strict UN-membership succession.
Source
Curated from ISO 3166-3 and the historical record.
Is a country in a group?
Description
A vectorised membership predicate built on country_groups().
Usage
in_group(x, group, origin = "country.name")
Arguments
x |
A vector of country names or codes. |
group |
A single group name (see |
origin |
How to read |
Value
A logical vector the same length as x. A value origin cannot
resolve to an ISO code answers FALSE – the same as a country that is
genuinely outside the group – so run check_country_match() first if you
need to tell "not a member" from "not recognised".
Examples
in_group(c("France", "United States", "Japan"), "EU")
Rebase a series to an index (base year = 100)
Description
Rescales a value column so the chosen base year equals to (100 by default),
per country – the standard way to compare trajectories that start at very
different levels.
Usage
index_to(data, value, base_year, to = 100, suffix = "_index")
Arguments
data |
A panel with |
value |
The value column (unquoted). |
base_year |
The year set equal to |
to |
The index value the base year maps to (default |
suffix |
Suffix for the new column (default |
Value
data with an index column added.
Examples
df <- data.frame(iso3c = "USA", year = 2000:2002, gdp = c(50, 55, 60))
index_to(df, gdp, base_year = 2000)
Web-ready interactive choropleth
Description
An interactive choropleth with hover and zoom, for dashboards and
R Markdown / Quarto. Engines are all optional Suggests.
Usage
interactive_map(
data,
fill,
tooltip = NULL,
engine = c("plotly", "ggiraph", "leaflet", "ggsql"),
...
)
Arguments
data |
A map-ready frame (polygon or sf). The |
fill |
The fill column (unquoted). |
tooltip |
Optional tooltip column (unquoted). |
engine |
|
... |
Passed to |
Value
An interactive widget.
Examples
## Not run:
world_data(2020) |> interactive_map(gdp_per_capita)
world_data(2020, geometry = "sf") |>
interactive_map(gdp_per_capita, engine = "ggsql", transform = "log10")
## End(Not run)
One call: your data, on a map
Description
Auto-detects the country column, standardises it to ISO codes (via
standardize_country()), attaches geometry and returns a plot-ready frame –
the function that fulfils the package's promise for your own data. Pipe the
result straight into world_map().
Usage
join_world(
data,
country_col = NULL,
origin = "country.name",
geometry = c("polygon", "sf", "none"),
scale = "small",
region = NULL,
projection = "equal_earth",
recenter = NULL,
warn = TRUE
)
Arguments
data |
A data frame keyed on country names or codes. |
country_col |
The country column (unquoted). If omitted, it is auto-detected. |
origin |
How to read |
geometry |
|
scale |
Natural Earth resolution for the |
region |
Optional region subset (see |
projection, recenter |
Projection, and optional central meridian, for
the |
warn |
Whether to report unmatched countries (default |
Value
A plot-ready frame: polygon tibble, sf object, or (for
geometry = "none") the standardised table.
Examples
rates <- data.frame(country = c("United States", "Brazil", "Kenya"),
vaccination_pct = c(0.7, 0.8, 0.6))
if (requireNamespace("maps", quietly = TRUE)) {
joined <- join_world(rates, country)
}
Panel lag / difference by country
Description
The two panel primitives everyone hand-rolls (and gets subtly wrong when the
frame isn't sorted): the value n years back, and the change since then –
grouped by iso3c, ordered by year, so country A's 1960 never leaks into
country B's first row.
Usage
lag_by_country(data, value, n = 1, suffix = NULL)
diff_by_country(data, value, n = 1, suffix = NULL)
Arguments
data |
A panel with |
value |
The value column (unquoted). |
n |
Number of periods to lag / difference over (default |
suffix |
Suffix for the new column. Defaults to |
Value
data with the lagged / differenced column added.
Examples
df <- data.frame(iso3c = "USA", year = 2000:2003, gdp = c(100, 110, 121, 133))
lag_by_country(df, gdp)
diff_by_country(df, gdp)
Tag coordinates with the country that contains them
Description
Point-in-polygon lookup: given longitude / latitude vectors (or an sf POINT
object), return the iso3c of the country each point falls in – the bridge
for getting point data (events, stations, observations) onto the country
spine so it can be joined, aggregated and mapped like everything else.
Usage
locate_country(
lon = NULL,
lat = NULL,
points = NULL,
scale = "small",
add = "country",
tolerance_km = 25
)
Arguments
lon, lat |
Equal-length numeric vectors of longitude / latitude, giving
one point per element (ignored if |
points |
Optional |
scale |
Natural Earth resolution for the lookup geometry. |
add |
Extra attributes to return alongside |
tolerance_km |
Snap an unmatched point to the nearest country when it
lies within this many kilometres of one (default |
Value
A tibble with one row per point: iso3c plus any add columns
(NA for points that fall in no country, e.g. open ocean).
Examples
if (requireNamespace("sf", quietly = TRUE) &&
requireNamespace("rnaturalearth", quietly = TRUE)) {
locate_country(lon = c(2.35, -74.0), lat = c(48.85, 40.7)) # Paris, NYC
}
Global Moran's I (spatial autocorrelation)
Description
Do neighbouring countries have similar values? Global Moran's I on the
country spine, using the country_borders() land-border adjacency as the
spatial weights (row-standardised), with a permutation pseudo-p-value. No
spdep required: at ~200 countries the dense arithmetic is trivial, and
reusing the package's own adjacency keeps the weights consistent with the
maps. Countries with no land border in the data (islands) carry no weight
and are excluded.
Usage
morans_i(data, value, scale = "small", n_perm = 999)
Arguments
data |
A country-level data frame with |
value |
The value column (unquoted). |
scale |
Natural Earth resolution for the adjacency (see
|
n_perm |
Number of permutations for the pseudo-p-value (default |
Value
A one-row tibble: i (observed Moran's I), expected
(-1/(n-1) under no autocorrelation), n (countries used),
n_links (border pairs among them) and p_value (one-sided,
P(I_{perm} \ge I_{obs}); positive autocorrelation is the standard
alternative). Set a seed beforehand for a reproducible p_value.
Examples
if (requireNamespace("sf", quietly = TRUE) &&
requireNamespace("rnaturalearth", quietly = TRUE)) {
snap <- countryatlas::world_snapshot$countries
set.seed(42)
morans_i(snap, gdp_per_capita, n_perm = 99) # GDP clusters in space
}
A country's neighbours
Description
Which countries border a given country (or countries) – a vectorised
lookup built on country_borders().
Usage
neighbors(x, origin = "country.name", scale = "small")
Arguments
x |
A vector of country names or codes. |
origin |
How to read |
scale |
Natural Earth resolution to compute adjacency from. |
Value
A tibble with one row per (iso3c, neighbor) pair: the queried
country's iso3c, and each bordering country's iso3c and country
name (neighbor, neighbor_country). Countries with no land border
(islands, e.g. Japan, Madagascar) return zero rows.
Pass a vector, don't loop
Every call rebuilds the whole world's adjacency from polygon topology, so
asking about one country costs the same as asking about all of them. x is
vectorised, and adding countries to a single call only adds the filtering:
countryatlas::neighbors(c("FRA", "DEU", "ESP"), origin = "iso3c")
Looping instead pays that rebuild once per country – for every bordering
country in the world, roughly two orders of magnitude more work than one
vectorised call. The same applies to country_borders(), which does the work.
Name clash with igraph
igraph also exports a neighbors(), and it takes a graph and a vertex
rather than country names. Whichever package is attached later wins, so if
you use both – which country_borders() suggests, for building a graph of
the adjacency – qualify this one as countryatlas::neighbors().
Examples
if (requireNamespace("sf", quietly = TRUE) &&
requireNamespace("rnaturalearth", quietly = TRUE)) {
neighbors("France")
neighbors(c("FRA", "JPN"), origin = "iso3c") # Japan has no land border
}
Normalise an indicator by population
Description
Removes the "is this map just a population map?" footgun by dividing a value
column by population. If no population column is supplied, SP.POP.TOTL is
pulled automatically for the relevant countries and years.
Usage
per_capita(data, value, pop = NULL, suffix = "_per_capita", cache = TRUE)
Arguments
data |
A country-level (or panel) data frame with |
value |
The value column to normalise (unquoted). |
pop |
Optional population column (unquoted). If absent, population is fetched from WDI. |
suffix |
Suffix for the new column (default |
cache |
Whether to use the WDI cache when fetching population. |
Value
data with a new per-capita column.
Examples
df <- data.frame(iso3c = c("USA", "CHN"), year = 2020L,
co2 = c(5e6, 1e7), pop = c(331e6, 1402e6))
per_capita(df, co2, pop)
Add rank, percentile and z-score
Description
Adds rank, percentile and z_score for a value column, optionally within
a group (region, year, ...), for "top 10" tables and labelling.
Usage
rank_countries(data, value, within = NULL, desc = TRUE)
Arguments
data |
A data frame. |
value |
The value column to rank (unquoted). |
within |
Optional grouping column(s) (unquoted or character) to rank within. |
desc |
Rank descending (largest = rank 1); default |
Value
data with rank, percentile and z_score columns added.
Examples
df <- data.frame(iso3c = c("USA", "CHN", "IND"), gdp = c(21, 17, 3))
rank_countries(df, gdp)
Auto-repair country names to their closest known match
Description
The "act on it" companion to check_country_match(): replaces unmatched
country names with their closest known country name (by string distance), but
only when the match is confident enough, and reports what it changed. Pipe the
result into standardize_country() / join_world().
Usage
repair_country_names(
x,
threshold = 0.2,
origin = "country.name",
verbose = TRUE
)
Arguments
x |
A vector of country names. |
threshold |
Maximum string distance to accept a repair (0 = identical,
1 = unrelated). Lower is stricter; default |
origin |
countrycode origin scheme (default |
verbose |
Whether to message the substitutions made (default |
Value
A character vector the same length as x, with confident misses
replaced by the closest known country name (others left unchanged). The
applied substitutions are attached as the attribute "repairs".
See Also
check_country_match() for the report this acts on, and
dissolve_country() for dissolved entities, which are deliberately not
repaired.
Examples
repair_country_names(c("United States", "Brzil", "Germny"))
Each country's share of the world total
Description
Adds a column giving each country's value as a share of the (year's) world
total – e.g. share of global emissions or GDP. Operates within year when a
panel is supplied. A dplyr grouping on data is ignored – the denominator
is always the world (or the year's) total, never the group's.
Usage
share_of_world(data, value, suffix = "_share")
Arguments
data |
A country-level (or panel) data frame. |
value |
The value column (unquoted). |
suffix |
Suffix for the new column (default |
Value
data with a share column added (a proportion in [0, 1]).
Examples
df <- data.frame(iso3c = c("USA", "CHN"), co2 = c(5, 10))
share_of_world(df, co2)
Sigma convergence (dispersion over time)
Description
Is the cross-country distribution actually narrowing? Reports the dispersion
of a (positive) indicator across countries for every year of a panel –
falling dispersion is sigma convergence. The natural companion to
beta_convergence(): beta convergence is necessary but not sufficient for
sigma convergence.
Usage
sigma_convergence(data, value, measure = c("sd_log", "cv"))
Arguments
data |
A panel with |
value |
The value column (unquoted). |
measure |
|
Value
A tibble with one row per year: year, n (countries with
positive values) and sigma.
See Also
beta_convergence() for the growth-regression counterpart.
Examples
df <- data.frame(
iso3c = rep(c("A", "B", "C"), 2),
year = rep(c(2000L, 2010L), each = 3),
gdp = c(1, 10, 100, 2, 11, 60) # dispersion falls
)
sigma_convergence(df, gdp)
Simplify (thin) geometry for faster plotting
Description
Reduce the vertex count of an sf object via the optional rmapshaper
package (falling back to sf::st_simplify()), for fast web/plotting.
Usage
simplify_geometry(x, keep = 0.05, ...)
Arguments
x |
An |
keep |
Proportion of vertices to keep: greater than 0 and at most 1
( |
... |
Passed to the underlying simplifier. |
Value
A simplified sf object.
Examples
if (requireNamespace("sf", quietly = TRUE) &&
requireNamespace("rnaturalearth", quietly = TRUE)) {
world_geometry(geometry = "sf") |> simplify_geometry(keep = 0.1)
}
Spike map (heights at country centroids)
Description
The classic "population spikes" display: a triangular spike at each country
centroid whose height encodes the value. Like bubble_map() it is the
honest idiom for totals, with a different visual trade-off: spikes
overplot less in dense regions (Europe, the Caribbean) because they only
grow upward. Uses the polygon backend, so it needs only maps.
Usage
spike_map(
data,
height,
max_height = 20,
width = 1.6,
color = "#B2182B",
alpha = 0.65
)
Arguments
data |
A country-level frame with |
height |
The column controlling spike height (unquoted). |
max_height |
Height of the tallest spike, in degrees of latitude
(default |
width |
Base width of each spike, in degrees of longitude (default
|
color |
Spike colour (default a warm red). |
alpha |
Spike fill transparency. |
Value
A ggplot object.
Examples
if (requireNamespace("maps", quietly = TRUE)) {
spike_map(countryatlas::world_snapshot$countries, population)
}
Spin the globe
Description
An animated GIF of the world rotating on its axis: a sequence of orthographic
globe_map() frames at evenly spaced central longitudes, assembled into a
looping animation with the optional gifski (preferred) or magick package.
Embeds directly in R Markdown / Quarto / a README.
Usage
spin_globe(
data,
fill,
lat = 20,
n_frames = 60,
fps = 15,
backend = c("polygon", "sf"),
width = 480,
height = 480,
file = NULL,
...
)
Arguments
data |
A map-ready frame (see |
fill |
The fill column (unquoted). |
lat |
The latitude the globe is tilted toward (the viewer's eye line). |
n_frames |
Number of frames in one full 360 degrees rotation. |
fps |
Frames per second of the output animation. |
backend |
|
width, height |
Pixel dimensions of the animation. |
file |
Optional output path ( |
... |
Passed to |
Value
The path to the written GIF, invisibly.
Examples
## Not run:
# No sf required:
spin_globe(world_snapshot$countries, continent, backend = "polygon",
style = "categorical")
## End(Not run)
Add ISO codes and classifications to any data frame
Description
The package's mission, exposed for your data: take a data frame keyed on
messy country names (or codes) and attach standardised ISO codes plus useful
classifications, reconciling spellings via countrycode::countrycode() and
the curated country_overrides() table. The result joins cleanly to anything
else keyed on iso3c.
Usage
standardize_country(
data,
country_col,
origin = "country.name",
add = c("iso3c", "iso2c", "continent", "region"),
custom_match = country_overrides(),
warn = TRUE
)
Arguments
data |
A data frame / tibble. |
country_col |
The column holding country names or codes (unquoted, tidy-eval). |
origin |
How to read |
add |
Character vector of attributes to add. Defaults to
|
custom_match |
A named character vector of name -> iso3c overrides;
defaults to |
warn |
Whether to warn about unmatched countries (default |
Value
data with the requested columns added (and existing same-named
columns overwritten).
Examples
df <- data.frame(nation = c("U.S.", "S. Korea", "Czechia"), value = 1:3)
standardize_country(df, nation)
Theil index, with between/within decomposition
Description
The Theil T inequality index – less famous than Gini, but it decomposes exactly into a between-group and a within-group component, answering "how much of world inequality is between continents vs within them?" in one call. Weight by population to describe inequality between people rather than between country units.
Usage
theil(x, weights = NULL, groups = NULL, na.rm = TRUE)
Arguments
x |
A positive numeric vector (log scale; zero/negative values are dropped with a warning). |
weights |
Optional non-negative weights (e.g. population), either the
same length as |
groups |
Optional grouping vector (e.g. continent), the same length as
|
na.rm |
Whether to drop |
Value
Without groups: a single non-negative number (0 = perfect
equality). With groups: a tibble with components "total",
"between" and "within" (total = between + within) and each
component's share of the total (NA when the total is 0, i.e.
perfect equality, and the shares are undefined).
When there is nothing to compute – no values left after na.rm, a zero
total weight, or an infinity in x or weights – the result is a single
NA whatever groups says, so reach for the components only after checking
is.data.frame().
See Also
gini() for the more familiar single-number summary, which does not
decompose.
Examples
snap <- countryatlas::world_snapshot$countries
theil(snap$gdp_per_capita, weights = snap$population)
theil(snap$gdp_per_capita, weights = snap$population, groups = snap$continent)
A clean theme for world maps
Description
Strips axes, panel grid and background so the map is the focus. Applied by
every plotting function in the package except bivariate_map(), which uses
biscale::bi_theme() so the map matches its own legend, and exported here for
reuse on plots you build yourself.
Usage
theme_world_map(base_size = 12, base_family = "")
Arguments
base_size |
Base font size. |
base_family |
Base font family. |
Value
A ggplot2 theme object.
Examples
library(ggplot2)
ggplot() + theme_world_map()
Equal-area world tile grid
Description
A statebins-style equal-area tile grid of the world (one square per country)
so tiny states are actually visible. Uses the bundled world_tiles layout.
For small multiples of a tile grid, facet the result as you would any other
ggplot (or see facet_map() for the choropleth equivalent).
Usage
tile_map(data, fill, label = TRUE)
Arguments
data |
A country-level frame with |
fill |
The fill column (unquoted). |
label |
Whether to draw ISO codes on the tiles (default |
Details
Every tile in the layout is drawn, taking the scale's na.value fill where
data has no row for it. The converse also holds and is quieter: data rows
keyed on one of the 10 countries with no tile are dropped without a warning
(see world_tiles for which).
Value
A ggplot object.
Examples
tile_map(countryatlas::world_snapshot$countries, gdp_per_capita)
Search World Bank indicators
Description
A tidy, pipeable wrapper on WDI::WDIsearch() for discovering indicator
codes.
Usage
wdi_search(pattern, field = c("name", "indicator"), cache = NULL)
Arguments
pattern |
A regular expression to search indicator names/codes for. |
field |
Which field to search: |
cache |
Optional cached |
Value
A tibble of matching indicator codes and names.
Examples
# Searches WDI's bundled indicator list, so this needs no connection.
wdi_search("CO2 emissions")
Curated country-name overrides (replaces the silent drop-list)
Description
A documented custom_match table for entities that map backends
(ggplot2::map_data() and Natural Earth) get wrong or leave without an ISO
code. Earlier versions of the package deleted these regions; now they are
matched instead, so they stop silently disappearing from maps.
country_overrides() is the preferred name as of the package's rename to
countryatlas; wdj_overrides() is kept as a backward-compatible alias.
Usage
wdj_overrides(extra = NULL)
country_overrides(extra = NULL)
Arguments
extra |
An optional named character vector of additional overrides
(names are country/region names, values are |
Details
The table maps a country/region name (as spelled by the geometry backends) to
an ISO 3166-1 alpha-3 code. Pass the result as the custom_match argument to
standardize_country(), world_data() and friends. Every downstream code
(iso2c, continent, region, flag, ...) is derived from this iso3c, so a
single override is enough.
Value
A named character vector suitable for countrycode(custom_match=).
Accented names and locales
Every name in this table is plain ASCII, and that is deliberate: ASCII
spellings match in any locale. Accented spellings ("Curacao" with a
cedilla, "Saint Barthelemy" with an acute) are matched natively by
countrycode::countrycode() in a UTF-8 locale, which is why they are not
listed here – but in a non-UTF-8 locale (LC_CTYPE=C) they cannot be
compared reliably and resolve to NA.
If your input may contain accented country names, run in a UTF-8 locale.
De-accenting with iconv(x, to = "ASCII//TRANSLIT") gives ASCII spellings
that resolve everywhere, but it is not an escape from the locale problem:
//TRANSLIT is itself locale-dependent, so under LC_CTYPE=C it returns
NA (or, given an explicit from = "UTF-8", replaces each accent with ?)
and nothing resolves. De-accent while still in a UTF-8 locale, or supply the
ASCII spellings directly.
Examples
wdj_overrides()
wdj_overrides(c(Somaliland = "SOM"))
country_overrides()
Map-ready, enriched country tibble
Description
The package's headline function, generalised but backward-compatible. Returns
a tibble that already stitches together map geometry, World Bank indicators
and the countrycode crosswalk, keyed on the ISO spine – ready to pipe into
world_map() or ggplot2.
Usage
world_data(
year,
indicator = c(gdp_per_capita = "NY.GDP.PCAP.KD"),
geometry = c("polygon", "sf", "none"),
scale = c("small", "medium", "large"),
region = NULL,
classify = c("income", "continent", "region"),
projection = "equal_earth",
recenter = NULL,
latest = FALSE,
cache = TRUE,
language = "en",
parallel = TRUE,
overrides = country_overrides()
)
Arguments
year |
A single year or a range (e.g. |
indicator |
A named character vector of WDI codes. Names drive column
names, e.g. |
geometry |
|
scale |
Natural Earth resolution for the |
region |
Optional subset: a continent, group name, |
classify |
Which classifications to add (any of |
projection, recenter |
Projection, and optional central meridian, for
the |
latest |
If |
cache |
Whether to use the memoised / on-disk WDI cache. |
language |
WDI language code (default |
parallel |
Whether to fetch multiple indicators in parallel. Ignored
when the cache is memory-only (an unwritable |
overrides |
Name -> iso3c overrides for geometry matching (default
|
Details
world_data(2020) keeps its original behaviour (polygon backend, GDP per
capita). Everything else is opt-in: any indicator(s), a span of years (a
panel), an sf backend with real projections, and region subsetting.
Value
A tibble (polygon backend), sf object (sf backend) or country-level
tibble (geometry = "none").
iso3c is the stable key; country is a label and its spelling depends on
where the row came from. A successful fetch carries the World Bank's names
("Korea, Rep.", "Congo, Dem. Rep."), while the country spine used when the
fetch returns nothing carries the countrycode names ("South Korea",
"Congo - Kinshasa") – as do convert_country(), standardize_country()
and the rest of the package. Match on iso3c, and relabel with
convert_country(iso3c, to = "country") if you need one consistent set.
Examples
# geometry = "polygon", the default, comes from the suggested `maps`
# package, so guard the call: an example may not assume a Suggests is
# installed (R CMD check runs \donttest{} blocks, and CRAN has a
# check flavour with no suggested packages at all).
if (requireNamespace("maps", quietly = TRUE)) {
world_data(2020)
}
# geometry = "none" needs nothing beyond the hard dependencies.
world_data(2020, indicator = c(life_exp = "SP.DYN.LE00.IN"),
geometry = "none")
Geometry without the data
Description
Sometimes you just want the canvas: country polygons, label-ready centroids, coastlines, internal borders, a graticule or an ocean rectangle – already projected, region-subset and antimeridian-safe. This is the building block the plotting functions sit on, exposed for power users.
Usage
world_geometry(
what = c("countries", "centroids", "coastline", "borders", "graticule", "ocean"),
geometry = c("polygon", "sf"),
scale = "small",
region = NULL,
projection = "equal_earth",
recenter = NULL
)
Arguments
what |
What to return: |
geometry |
|
scale |
Natural Earth resolution for the |
region |
Optional subset: a continent, a group name, a vector of |
projection |
Projection for the |
recenter |
Optional central meridian for a recentred map (e.g. |
Value
A tibble (polygon backend) or sf object (sf backend), with columns
depending on what:
"countries"polygon:
long,lat,group,order,region,subregion,iso3c,iso2c. sf:iso3c,iso2c,name_long."centroids"the same identifier columns plus
centroid_lonandcentroid_lat."coastline","borders","ocean","graticule"sf only.
The centroid columns are in the coordinate system of the object
returned, so on the sf backend they are projected metres, not degrees –
centroid_lon for France is 174097, not 2.1. For centroids in degrees
use country_meta$centroid_lon / $centroid_lat, which is also what the
polygon backend returns.
A few Natural Earth features have no ISO code and so come back with iso3c
NA – Somaliland at every scale, plus the Indian Ocean Territories and
Ashmore and Cartier Islands from "medium" on. They are kept so the land is
still drawn; drop or country_overrides() them if you group by iso3c.
"orthographic" is the one genuinely hemispheric projection: the countries
on the far side have no image and come back as empty geometries (correctly,
but sf::st_coordinates() cannot read a column that mixes empty and
non-empty – drop them first). The other three azimuthal projections
("azimuthal_equal_area", "north_polar", "south_polar") are Lambert
equal-area and draw the whole globe, the far side stretched around the
rim rather than dropped, so pass region if you want a polar view of the
northern countries alone.
"ocean" is a whole-globe background rectangle. It is unavailable in all
four azimuthal projections – "orthographic" has no image for it, and the
Lambert three cut the globe at the antipode, which collapses the rectangle's
outline – and it cannot be recentred; both cases error rather than
returning an invisible layer.
Examples
if (requireNamespace("maps", quietly = TRUE)) {
head(world_geometry("countries", geometry = "polygon"))
}
One-line choropleth, several honest styles
Description
Encapsulates the choropleth boilerplate and goes beyond a single style.
Auto-detects the polygon vs sf backend, applies theme_world_map(), and –
for sf – a real projection via ggplot2::coord_sf(). Binned / quantile /
jenks styles are offered because a continuous fill on a skewed indicator
hides almost all the variation; binning is the honest default for
choropleths.
Usage
world_map(
data,
fill,
style = c("continuous", "binned", "quantile", "jenks", "categorical"),
projection = "equal_earth",
palette = NULL,
n_bins = 5,
borders = TRUE,
title = NULL,
legend = NULL,
na_label = "No data",
recenter = NULL
)
Arguments
data |
A map-ready frame from |
fill |
The fill column (unquoted). |
style |
|
projection |
For the |
palette |
Optional palette name passed to the relevant |
n_bins |
Number of bins for binned/quantile/jenks styles. |
borders |
Draw country borders (default |
title, legend |
Optional plot title and legend title. |
na_label |
Legend key label for missing data, used by the styles with
a discrete legend ( |
recenter |
Optional central meridian for the |
Value
A ggplot object.
Examples
snap <- countryatlas::world_snapshot$countries
if (requireNamespace("maps", quietly = TRUE)) {
mapdf <- attach_geometry(snap, geometry = "polygon")
world_map(mapdf, gdp_per_capita, style = "quantile")
}
Emit a ggsql spatial query for a country map
Description
Build a ggsql query string that draws a choropleth from
a registered countryatlas source – the same idea as world_map(), but the
map is rendered in the database (DuckDB) and returned as a web-ready
Vega-Lite widget, so the geometry never has to come back into R. Pure string
builder with no dependencies; pair it with as_ggsql_source() +
ggsql::ggsql_execute(), or drop the string into a {ggsql} chunk.
Usage
world_query(
fill,
source = "countryatlas_world",
projection = "equal_earth",
palette = "viridis",
transform = NULL,
title = NULL,
draw = "spatial"
)
Arguments
fill |
The fill column (unquoted or a string). |
source |
The table/source name registered with ggsql (default
|
projection |
A projection ggsql's |
palette |
A scale ggsql's |
transform |
Optional scale transform for |
title |
Optional plot title ( |
draw |
The spatial layer (default |
Value
A ggsql_query string (prints as the formatted query).
Executing the query
Building the string needs nothing installed. Running it needs
ggsql >= 0.4.1, the version that added the DRAW spatial clause; older
ggsql releases parse the query and reject that clause. As of August 2026
that clause has shipped in the ggsql engine but not yet in the ggsql R
package (still 0.3.3), so interactive_map()(engine = "ggsql") will refuse
until the bindings catch up. PROJECT TO additionally needs a spatial
backend – for DuckDB, its spatial extension.
Examples
world_query(gdp_per_capita, projection = "equal_earth",
palette = "magma", transform = "log10",
title = "GDP per capita")
Offline snapshot of world data
Description
A small, lazy-loaded, one-row-per-country snapshot of a curated indicator set for one recent year. It lets every example, test and vignette run offline and deterministically, without the World Bank API.
Usage
world_snapshot
Format
A list with three elements:
- countries
A tibble, one row per country, with
iso3c,iso2c,country, classifications and curated indicators (gdp_per_capita,population,life_expectancy,co2_per_capita).- sf
NULLin the released package – geometry is not bundled twice. Attach it on demand withattach_geometry():attach_geometry(world_snapshot$countries, geometry = "sf")pulls the same Natural Earth 110m polygons fromrnaturalearth.- year
The reference year.
country carries the World Bank's own names, which differ from the
countrycode names used by country_meta for 38 countries.
Source
World Bank via WDI; geometry from Natural Earth via rnaturalearth. Snapshot year: 2024.
Equal-area world tile-grid layout
Description
A statebins-style equal-area tile layout: one square per country, positioned
on a row/col grid derived from country centroids. Used by tile_map().
Usage
world_tiles
Format
A tibble with columns iso3c, country, row, col; one row per
country, with row/col unique across the grid.
Details
The grid holds one row for each of the 239 countries in country_meta that
has a bundled centroid; the 10 without one (ALA, BVT, GIB, HKG,
MAC, SJM, TKL, TUV, UMI, VGB – see country_meta) have no tile
and so cannot be drawn by tile_map().
Source
Derived from Natural Earth country centroids.