Title: 'ggplot2' Faceting Utilities for Geographical Data
Version: 0.2.4
Description: Provides geographical faceting functionality for 'ggplot2'. Geographical faceting arranges a sequence of plots of data for different geographical entities into a grid that preserves some of the geographical orientation.
Depends: R (≥ 4.1.0)
License: MIT + file LICENSE
Encoding: UTF-8
LazyData: true
Imports: ggplot2 (≥ 3.2.1), gtable, graphics, rnaturalearth, sp, ggrepel, gridExtra, geogrid, methods, rlang, httr2
Suggests: sf, testthat, covr, lintr, knitr, rmarkdown
URL: https://github.com/hafen/geofacet, https://hafen.github.io/geofacet/
BugReports: https://github.com/hafen/geofacet/issues
RoxygenNote: 7.3.2
VignetteBuilder: knitr
NeedsCompilation: no
Packaged: 2025-06-28 21:36:03 UTC; rhafen
Author: Ryan Hafen [aut, cre], Barret Schloerke [ctb]
Maintainer: Ryan Hafen <rhafen@gmail.com>
Repository: CRAN
Date/Publication: 2025-06-28 22:30:02 UTC

geofacet: 'ggplot2' Faceting Utilities for Geographical Data

Description

logo

Provides geographical faceting functionality for 'ggplot2'. Geographical faceting arranges a sequence of plots of data for different geographical entities into a grid that preserves some of the geographical orientation.

Author(s)

Maintainer: Ryan Hafen rhafen@gmail.com

Other contributors:

See Also

Useful links:


Attach a SpatialPolygonsDataFrame object to a grid

Description

Attach a SpatialPolygonsDataFrame object to a grid

Usage

attach_spdf(x, spdf)

Arguments

x

object to attach SpatialPolygonsDataFrame object to

spdf

a SpatialPolygonsDataFrame object to attach


aus_pop

Description

March 2017 population data for Australian states and territories by age group. Online source no longer available.

Usage

aus_pop

auto_states

Description

List of valid values for countries for fetching rnaturalearth data when used with grid_auto to create a grid of states.

List of valid values for continents for fetching rnaturalearth data when used with grid_auto to create a grid of countries.


election

Description

2016 US presidential election results, obtained from https://docs.google.com/spreadsheets/d/133Eb4qQmOxNvtesw2hdVns073R68EZx4SfCnP4IGQf8/htmlview?sle=true.

Usage

election

eu_gdp

Description

GDP per capita in PPS - Index (EU28 = 100). "Gross domestic product (GDP) is a measure for the economic activity. It is defined as the value of all goods and services produced less the value of any goods or services used in their creation. The volume index of GDP per capita in Purchasing Power Standards (PPS) is expressed in relation to the European Union (EU28) average set to equal 100. If the index of a country is higher than 100, this country's level of GDP per head is higher than the EU average and vice versa. Basic figures are expressed in PPS, i.e. a common currency that eliminates the differences in price levels between countries allowing meaningful volume comparisons of GDP between countries. Please note that the index, calculated from PPS figures and expressed with respect to EU28 = 100, is intended for cross-country comparisons rather than for temporal comparisons." Source is no longer available (previously at http://ec.europa.eu/eurostat/web/national-accounts/data/main-tables). Dataset ID: tec00114.

Usage

eu_gdp

eu_imm

Description

Annual number of resettled persons for each EU country. "Resettled refugees means persons who have been granted an authorization to reside in a Member State within the framework of a national or Community resettlement scheme.". Source: https://ec.europa.eu/eurostat/cache/metadata/en/migr_asydec_esms.htm. Dataset ID: tps00195.

Usage

eu_imm

Arrange a sequence of geographical panels into a grid that preserves some geographical orientation

Description

Arrange a sequence of geographical panels into a grid that preserves some geographical orientation

Usage

facet_geo(facets, ..., grid = "us_state_grid1", label = NULL, move_axes = TRUE)

Arguments

facets

passed to facet_wrap

grid

either a character vector of the grid layout to use (see '?grids' for the list and use 'get_grid()' to inspect or 'grid_preview()' to plot a specific grid), or a data.frame object containing a grid (e.g. an output from 'grid_design()' or 'grid_auto()')

label

an optional string denoting the name of a column in grid to use for facet labels. If NULL, the variable that best matches that in the data specified with facets will be used for the facet labels.

move_axes

should axis labels and ticks be moved to the closest panel along the margins?

...

additional parameters passed to facet_wrap

Examples

## Not run: 
library(ggplot2)

# barchart of state rankings in various categories
ggplot(state_ranks, aes(variable, rank, fill = variable)) +
  geom_col() +
  coord_flip() +
  facet_geo(~ state) +
  theme_bw()

# use an alternative US state grid and place
ggplot(state_ranks, aes(variable, rank, fill = variable)) +
  geom_col() +
  coord_flip() +
  facet_geo(~ state, grid = "us_state_grid2") +
  theme(panel.spacing = unit(0.1, "lines"))

# custom grid (move Wisconsin above Michigan)
my_grid <- us_state_grid1
my_grid$col[my_grid$code == "WI"] <- 7

ggplot(state_ranks, aes(variable, rank, fill = variable)) +
  geom_col() +
  coord_flip() +
  facet_geo(~ state, grid = my_grid)

# plot unemployment rate time series for each state
ggplot(state_unemp, aes(year, rate)) +
  geom_line() +
  facet_geo(~ state) +
  scale_x_continuous(labels = function(x) paste0("'", substr(x, 3, 4))) +
  ylab("Unemployment Rate (%)") +
  theme_bw()

# plot the 2016 unemployment rate
ggplot(subset(state_unemp, year == 2016), aes(factor(year), rate)) +
  geom_col(fill = "steelblue") +
  facet_geo(~ state) +
  theme(
    axis.title.x = element_blank(),
    axis.text.x = element_blank(),
    axis.ticks.x = element_blank()) +
  ylab("Unemployment Rate (%)") +
  xlab("Year")

# plot European Union GDP
ggplot(eu_gdp, aes(year, gdp_pc)) +
  geom_line(color = "steelblue") +
  geom_hline(yintercept = 100, linetype = 2) +
  facet_geo(~ name, grid = "eu_grid1") +
  scale_x_continuous(labels = function(x) paste0("'", substr(x, 3, 4))) +
  ylab("GDP Per Capita") +
  theme_bw()

# use a free x-axis to look at just change
ggplot(eu_gdp, aes(year, gdp_pc)) +
  geom_line(color = "steelblue") +
  facet_geo(~ name, grid = "eu_grid1", scales = "free_y") +
  scale_x_continuous(labels = function(x) paste0("'", substr(x, 3, 4))) +
  ylab("GDP Per Capita in Relation to EU Index (100)") +
  theme_bw()
# would be nice if ggplot2 had a "sliced" option...
# (for example, there's not much going on with Denmark but it looks like there is)

# plot European Union annual # of resettled persons
ggplot(eu_imm, aes(year, persons)) +
  geom_line() +
  facet_geo(~ name, grid = "eu_grid1") +
  scale_x_continuous(labels = function(x) paste0("'", substr(x, 3, 4))) +
  scale_y_sqrt(minor_breaks = NULL) +
  ylab("# Resettled Persons") +
  theme_bw()

# plot just for 2016
ggplot(subset(eu_imm, year == 2016), aes(factor(year), persons)) +
  geom_col(fill = "steelblue") +
  geom_text(aes(factor(year), 3000, label = persons), color = "gray") +
  facet_geo(~ name, grid = "eu_grid1") +
  theme(
    axis.title.x = element_blank(),
    axis.text.x = element_blank(),
    axis.ticks.x = element_blank()) +
  ylab("# Resettled Persons in 2016") +
  xlab("Year") +
  theme_bw()

# plot Australian population
ggplot(aus_pop, aes(age_group, pop / 1e6, fill = age_group)) +
  geom_col() +
  facet_geo(~ code, grid = "aus_grid1") +
  coord_flip() +
  labs(
    title = "Australian Population Breakdown",
    caption = "Data Source: ABS Labour Force Survey, 12 month average",
    y = "Population [Millions]") +
  theme_bw()

# South Africa population density by province
ggplot(sa_pop_dens, aes(factor(year), density, fill = factor(year))) +
  geom_col() +
  facet_geo(~ province, grid = "sa_prov_grid1") +
  labs(title = "South Africa population density by province",
    caption = "Data Source: Statistics SA Census",
    y = "Population density per square km") +
  theme_bw()

# use the Afrikaans name stored in the grid, "name_af", as facet labels
ggplot(sa_pop_dens, aes(factor(year), density, fill = factor(year))) +
  geom_col() +
  facet_geo(~ code, grid = "sa_prov_grid1", label = "name_af") +
  labs(title = "South Africa population density by province",
    caption = "Data Source: Statistics SA Census",
    y = "Population density per square km") +
  theme_bw()

# affordable housing starts by year for boroughs in London
ggplot(london_afford, aes(x = year, y = starts, fill = year)) +
  geom_col(position = position_dodge()) +
  facet_geo(~ code, grid = "london_boroughs_grid", label = "name") +
  labs(title = "Affordable Housing Starts in London",
    subtitle = "Each Borough, 2015-16 to 2016-17",
    caption = "Source: London Datastore", x = "", y = "")

# dental health in Scotland
ggplot(nhs_scot_dental, aes(x = year, y = percent)) +
  geom_line() +
  facet_geo(~ name, grid = "nhs_scot_grid") +
  scale_x_continuous(breaks = c(2004, 2007, 2010, 2013)) +
  scale_y_continuous(breaks = c(40, 60, 80)) +
  labs(title = "Child Dental Health in Scotland",
    subtitle = "Percentage of P1 children in Scotland with no obvious decay experience.",
    caption = "Source: statistics.gov.scot", x = "", y = "")

# India population breakdown
ggplot(subset(india_pop, type == "state"),
  aes(pop_type, value / 1e6, fill = pop_type)) +
  geom_col() +
  facet_geo(~ name, grid = "india_grid1", label = "code") +
  labs(title = "Indian Population Breakdown",
       caption = "Data Source: Wikipedia",
       x = "",
       y = "Population [Millions]") +
  theme_bw() +
  theme(axis.text.x = element_text(angle = 40, hjust = 1))

ggplot(subset(india_pop, type == "state"),
  aes(pop_type, value / 1e6, fill = pop_type)) +
  geom_col() +
  facet_geo(~ name, grid = "india_grid2", label = "name") +
  labs(title = "Indian Population Breakdown",
       caption = "Data Source: Wikipedia",
       x = "",
       y = "Population [Millions]") +
  theme_bw() +
  theme(axis.text.x = element_text(angle = 40, hjust = 1),
    strip.text.x = element_text(size = 6))

# A few ways to look at the 2016 election results
ggplot(election, aes("", pct, fill = candidate)) +
  geom_col(alpha = 0.8, width = 1) +
  scale_fill_manual(values = c("#4e79a7", "#e15759", "#59a14f")) +
  facet_geo(~ state, grid = "us_state_grid2") +
  scale_y_continuous(expand = c(0, 0)) +
  labs(title = "2016 Election Results",
    caption = "Data Source: 2016 National Popular Vote Tracker",
    x = NULL,
    y = "Percentage of Voters") +
  theme(axis.title.x = element_blank(),
    axis.text.x = element_blank(),
    axis.ticks.x = element_blank(),
    strip.text.x = element_text(size = 6))

ggplot(election, aes(candidate, pct, fill = candidate)) +
  geom_col() +
  scale_fill_manual(values = c("#4e79a7", "#e15759", "#59a14f")) +
  facet_geo(~ state, grid = "us_state_grid2") +
  theme_bw() +
  coord_flip() +
  labs(title = "2016 Election Results",
    caption = "Data Source: 2016 National Popular Vote Tracker",
    x = NULL,
    y = "Percentage of Voters") +
  theme(strip.text.x = element_text(size = 6))

ggplot(election, aes(candidate, votes / 1000000, fill = candidate)) +
  geom_col() +
  scale_fill_manual(values = c("#4e79a7", "#e15759", "#59a14f")) +
  facet_geo(~ state, grid = "us_state_grid2") +
  coord_flip() +
  labs(title = "2016 Election Results",
    caption = "Data Source: 2016 National Popular Vote Tracker",
    x = NULL,
    y = "Votes (millions)") +
  theme(strip.text.x = element_text(size = 6))

## End(Not run)

Perform post-processing on a facet_geo ggplot object

Description

Perform post-processing on a facet_geo ggplot object

Usage

get_geofacet_grob(x)

Arguments

x

object of class 'facet_geo'


Get a list of valid grid names

Description

Get a list of valid grid names

Usage

get_grid_names()

Get rnaturalearth data

Description

Get rnaturalearth data

Usage

get_ne_data(code)

Arguments

code

A country/continent name to get rnaturalearth data from (see auto_countries or auto_states).

Examples

## Not run: 
dat <- get_ne_data("brazil")

## End(Not run)

Generate a grid automatically from a country/continent name or a SpatialPolygonsDataFrame or 'sf' polygons

Description

Generate a grid automatically from a country/continent name or a SpatialPolygonsDataFrame or 'sf' polygons

Usage

grid_auto(x, names = NULL, codes = NULL, seed = NULL)

Arguments

x

A country/continent name, a SpatialPolygonsDataFrame or 'sf' polygons to build a grid for.

names

An optional vector of variable names in x@data to use as "name_" columns in the resulting grid.

codes

An optional vector of variable names in x@data to use as "code_" columns in the resulting grid.

seed

An optional random seed sent to calculate_grid.

Details

If a country or continent name is specified for x, it can be any of the strings found in auto_countries or auto_states. In this case, the rnaturalearth package will be searched for the corresponding shapefiles. You can use get_ne_data to see what these shapefiles look like.

The columns of the @data component of resulting shapefile (either user-specified or fetched from rnaturalearth) are those that will be available to names and codes.

Examples

## Not run: 
# auto grid using a name to identify the country
grd <- grid_auto("brazil", seed = 1234)
grid_preview(grd, label = "name")
# open the result up in the grid designer for further refinement
grid_design(grd, label = "name")

# using a custom file (can be GeoJSON or shapefile)
ff <- system.file("extdata", "bay_counties.geojson", package = "geogrid")
bay_shp <- sf::st_read(ff)
grd <- grid_auto(bay_shp, seed = 1) # names are inferred
grid_preview(grd, label = "name_county")
grid_design(grd, label = "code_fipsstco")

# explicitly specify the names and codes variables to use
grd <- grid_auto(bay_shp, seed = 1, names = "county", codes = "fipsstco")
grid_preview(grd, label = "name_county")
grid_preview(grd, label = "code_fipsstco")

## End(Not run)

Interactively design a grid

Description

Interactively design a grid

Usage

grid_design(data = NULL, img = NULL, label = "code", auto_img = TRUE)

Arguments

data

A data frame containing a grid to start from or NULL if starting from scratch.

img

An optional URL pointing to a reference image containing a geographic map of the entities in the grid.

label

An optional column name to use as the label for plotting the original geography, if attached to data.

auto_img

If the original geography is attached to data, should a plot of that be created and uploaded to the viewer?

Examples

# edit aus_grid1
grid_design(data = aus_grid1, img = "http://www.john.chapman.name/Austral4.gif")
# start with a clean slate
grid_design()
# arrange the alphabet
grid_design(data.frame(code = letters))

Plot a preview of a grid

Description

Plot a preview of a grid

Usage

grid_preview(x, label = NULL, label_raw = NULL, do_plot = TRUE)

Arguments

x

a data frame containing a grid

label

the column name in x that should be used for text labels in the grid plot

label_raw

the column name in the optional SpatialPolygonsDataFrame attached to x that should be used for text labels in the raw geography plot

do_plot

should the grid preview be plotted?

Examples

grid_preview(us_state_grid2)
grid_preview(eu_grid1, label = "name")

Submit a grid to be included in the package

Description

Submit a grid to be included in the package

Usage

grid_submit(x, name = NULL, desc = NULL)

Arguments

x

a data frame containing a grid

name

proposed name of the grid (if not supplied, will be asked for interactively)

desc

a description of the grid (if not supplied, will be asked for interactively)

Details

This opens up a github issue for this package in the web browser with pre-populated content for adding a grid to the package.

Examples

## Not run: 
my_grid <- us_state_grid1
my_grid$col[my_grid$label == "WI"] <- 7
grid_submit(my_grid, name = "us_grid_tweak_wi",
  desc = "Modified us_state_grid1 to move WI over")

## End(Not run)

Geo Grids

Description

There are now 216 grids available in this package and more online. To view a full list of available grids, see here. To create and submit your own grid, see here. To see several examples of grids being used to visualize data, see facet_geo.

Usage

us_state_grid1

us_state_grid2

eu_grid1

aus_grid1

sa_prov_grid1

gb_london_boroughs_grid

nhs_scot_grid

india_grid1

india_grid2

argentina_grid1

br_states_grid1

sea_grid1

mys_grid1

fr_regions_grid1

de_states_grid1

us_or_counties_grid1

us_wa_counties_grid1

us_in_counties_grid1

us_in_central_counties_grid1

se_counties_grid1

sf_bay_area_counties_grid1

ua_region_grid1

mx_state_grid1

mx_state_grid2

scotland_local_authority_grid1

us_state_without_DC_grid1

italy_grid1

italy_grid2

be_province_grid1

us_state_grid3

jp_prefs_grid1

ng_state_grid1

bd_upazila_grid1

spain_prov_grid1

ch_cantons_grid1

ch_cantons_grid2

china_prov_grid1

world_86countries_grid

se_counties_grid2

uk_regions1

us_state_contiguous_grid1

sk_province_grid1

ch_aargau_districts_grid1

jo_gov_grid1

es_autonomous_communities_grid1

spain_prov_grid2

world_countries_grid1

br_states_grid2

china_city_grid1

kr_seoul_district_grid1

nz_regions_grid1

sl_regions_grid1

us_census_div_grid1

ar_tucuman_province_grid1

us_nh_counties_grid1

china_prov_grid2

pl_voivodeships_grid1

us_ia_counties_grid1

us_id_counties_grid1

ar_cordoba_dep_grid1

us_fl_counties_grid1

ar_buenosaires_communes_grid1

nz_regions_grid2

oecd_grid1

ec_prov_grid1

nl_prov_grid1

ca_prov_grid1

us_nc_counties_grid1

mx_ciudad_prov_grid1

bg_prov_grid1

us_hhs_regions_grid1

tw_counties_grid1

tw_counties_grid2

af_prov_grid1

us_mi_counties_grid1

pe_prov_grid1

sa_prov_grid2

mx_state_grid3

cn_bj_districts_grid1

us_va_counties_grid1

us_mo_counties_grid1

cl_santiago_prov_grid1

us_tx_capcog_counties_grid1

sg_planning_area_grid1

in_state_ut_grid1

cn_fujian_prov_grid1

ca_quebec_electoral_districts_grid1

nl_prov_grid2

cn_bj_districts_grid2

ar_santiago_del_estero_prov_grid1

ar_formosa_prov_grid1

ar_chaco_prov_grid1

ar_catamarca_prov_grid1

ar_jujuy_prov_grid1

ar_neuquen_prov_grid1

ar_san_luis_prov_grid1

ar_san_juan_prov_grid1

ar_santa_fe_prov_grid1

ar_la_rioja_prov_grid1

ar_mendoza_prov_grid1

ar_salta_prov_grid1

ar_rio_negro_prov_grid1

uy_departamentos_grid1

ar_buenos_aires_prov_electoral_dist_grid1

europe_countries_grid1

argentina_grid2

us_state_without_DC_grid2

jp_prefs_grid2

na_regions_grid1

mm_state_grid1

us_state_with_DC_PR_grid1

fr_departements_grid1

ar_salta_prov_grid2

ie_counties_grid1

sg_regions_grid1

us_ny_counties_grid1

ru_federal_subjects_grid1

us_ca_counties_grid1

lk_districts_grid1

us_state_without_DC_grid3

co_cali_subdivisions_grid1

us_in_northern_counties_grid1

italy_grid3

us_state_with_DC_PR_grid2

us_state_grid7

sg_planning_area_grid2

ch_cantons_fl_grid1

europe_countries_grid2

us_states_territories_grid1

us_tn_counties_grid1

us_il_chicago_community_areas_grid1

us_state_with_DC_PR_grid3

in_state_ut_grid2

at_states_grid1

us_pa_counties_grid1

us_oh_counties_grid1

fr_departements_grid2

us_wi_counties_grid1

africa_countries_grid1

no_counties_grid1

tr_provinces_grid1

us_eastern_states_grid1

br_states_grid3

us_states_territories_grid2

us_state_grid8

us_state_grid9

fr_departements_grid3

in_state_ut_grid3

th_provinces_grid1

th_bangkok_districts_grid1

ca_us_prov_state_grid1

sy_governorates_grid1

ro_counties_grid1

us_va_health_districts_grid1

us_state_without_DC_canada_prov_grid1

ir_provinces_grid1

co_departments_grid1

ir_tehran_districts_grid1

ro_counties_grid2

gb_sct_council_areas_grid1

mw_districts_grid1

dk_cph_grid1

us_nv_counties_grid1

ie_counties_grid2

bo_departments_grid1

ie_counties_grid3

co_departments_grid2

americas_countries_grid1

us_census_div_grid2

ar_buenosaires_conurbano_grid1

us_md_counties_grid1

us_ia_counties_grid2

us_western_states_grid1

us_ga_counties_grid1

ro_counties_grid3

es_autonomous_communities_grid2

qa_municipalities_grid1

kz_region_grid1

middle_east_grid1

cz_prague_districts_grid1

es_catalonia_comarques_grid1

no_counties_grid2

fi_helsinki_neighborhoods_grid1

us_state_without_DC_AK_HI_grid1

ru_federal_subjects_grid2

us_ut_counties_grid1

in_state_ut_grid4

ec_prov_grid2

es_prov_grid1

americas_countries_grid2

us_nm_counties_grid1

us_me_counties_grid1

cu_prov_grid1

ge_regions_grid1

co_departments_grid3

gb_london_boroughs_grid2

gb_sct_aberdeenshire_IZ_grid1

gb_sct_aberdeenshire_wards_grid1

at_vienna_districts_grid1

gh_regions_grid1

uy_departamentos_grid2

ch_vaud_districts_grid1

us_ca_counties_FIPS_grid1

kr_seoul_district_grid2

kr_districts_grid1

oecd_grid2

bo_departments_grid2

ca_us_prov_state_grid2

us_il_counties_grid1

tn_governorates_grid1

gb_sct_glasgow_wards_grid1

kr_provinces_grid1

kr_counties_districts_cities_grid1

us_ok_counties_grid1

us_dc_neighborhoods_grid1

us_mn_counties_grid1

india_pop

Description

2011 population data for India, broken down by urban and rural. Source: https://en.wikipedia.org/wiki/List_of_states_and_union_territories_of_India_by_population.

Usage

india_pop

london_afford

Description

Total affordable housing completions by financial year in each London borough since 2015/16. Source: https://www.gov.uk/government/statistical-data-sets/live-tables-on-affordable-housing-supply

Usage

london_afford

nhs_scot_dental

Description

Child dental health data in Scotland. Source: http://statistics.gov.scot/data/child-dental-health

Usage

nhs_scot_dental

Plot geofaceted ggplot2 object

Description

Plot geofaceted ggplot2 object

Usage

## S3 method for class 'facet_geo'
plot(x, ...)

Arguments

x

plot object

...

ignored


Print geofaceted ggplot2 object

Description

Print geofaceted ggplot2 object

Usage

## S3 method for class 'facet_geo'
print(x, newpage = is.null(vp), vp = NULL, ...)

Arguments

x

plot object

newpage

draw new (empty) page first?

vp

viewport to draw plot in

...

other arguments not used by this method


sa_pop_dens

Description

Population density for each province in South Africa for 1996, 2001, and 2011. Source: https://en.wikipedia.org/wiki/List_of_South_African_provinces_by_population_density

Usage

sa_pop_dens

state_ranks

Description

State rankings in the following categories with the variable upon which ranking is based in parentheses: education (adults over 25 with a bachelor's degree in 2015), employment (March 2017 unemployment rate - Bureau of Labor Statistics), health (obesity rate from 2015 - Centers for Disease Control), insured (uninsured rate in 2015 - US Census), sleep (share of adults that report at least 7 hours of sleep each night from 2016 - Disease Control), wealth (poverty rate 2014/15 - US Census). In each category, the lower the ranking, the more favorable. This data is based on data presented in a May 17, 2017 Axios article, "The Emoji States of America".

Usage

state_ranks

state_unemp

Description

Seasonally-adjusted December unemployment rate for each state (including DC) from 2000 to 2017. Obtained from bls.gov.

Usage

state_unemp