Overview
rict produces clean, publication-ready tables for
redistricting analysis. It is designed to accompany maps from
redist and related packages, summarizing district-level
data on population, demographics, elections, compactness, contiguity,
and administrative splits.
The package builds on two core R table libraries:
Data
rict ships with two example datasets from West
Virginia:
-
wv: aredist_mapobject with county-level demographic, partisan, and geographic data -
wv_plans: aredist_plansobject with sampled redistricting plans and the enacted 2020 congressional plan
Quick start with rict()
The simplest entry point is rict(), which creates a
summary table from a redist_map or
redist_plans object:
rict(wv)
#> Warning: There was 1 warning in `dplyr::summarize()`.
#> ℹ In argument: `dplyr::across(where(is.numeric), sum, na.rm = TRUE)`.
#> ℹ In group 1: `district = 1`.
#> Caused by warning:
#> ! The `...` argument of `across()` is deprecated as of dplyr 1.1.0.
#> Supply arguments directly to `.fns` through an anonymous function instead.
#>
#> # Previously
#> across(a:b, mean, na.rm = TRUE)
#>
#> # Now
#> across(a:b, \(x) mean(x, na.rm = TRUE))
#> ℹ The deprecated feature was likely used in the redist package.
#> Please report the issue at <https://github.com/alarm-redist/redist/issues>.| district | pop | pop_white | pop_black | pop_hisp | pop_aian | pop_asian | pop_nhpi | pop_other | pop_two | vap | vap_white | vap_black | vap_hisp | vap_aian | vap_asian | vap_nhpi | vap_other | vap_two | cd_2010 | cd_2020 | pre_20_rep_tru | pre_20_dem_bid | ndv | adv_20 | nrv | arv_20 | sample_1 | sample_2 | sample_3 | sample_4 | sample_5 | sample_6 | sample_7 | sample_8 | sample_9 | sample_10 | sample_11 | sample_12 | state |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 896067 | 805369 | 36345 | 11331 | 1632 | 6132 | 155 | 2136 | 32967 | 715682 | 649695 | 29039 | 7866 | 1426 | 5030 | 116 | 1294 | 21216 | 73 | 28 | 273523 | 112947 | 112947 | 112947 | 273523 | 273523 | 37 | 31 | 36 | 35 | 38 | 33 | 35 | 36 | 31 | 31 | 37 | 36 | WV |
| 2 | 897649 | 793465 | 28404 | 23496 | 1555 | 8771 | 274 | 2516 | 39168 | 717250 | 643345 | 22963 | 15617 | 1335 | 7203 | 217 | 1687 | 24883 | 35 | 54 | 271859 | 123037 | 123037 | 123037 | 271859 | 271859 | 52 | 53 | 50 | 53 | 51 | 51 | 53 | 53 | 53 | 52 | 51 | 53 | WV |
For a redist_plans object, specify which plan to
display:
rict(wv_plans, "cd_2020")| district | total_pop | chain | pop_overlap | total_vap | plan_dev | comp_edge | comp_polsby | pop_white | pop_black | pop_hisp | pop_aian | pop_asian | pop_nhpi | pop_other | pop_two | vap_white | vap_black | vap_hisp | vap_aian | vap_asian | vap_nhpi | vap_other | vap_two | pre_20_rep_tru | pre_20_dem_bid | adv_20 | arv_20 | county_splits | ndv | nrv | ndshare | e_dvs | pr_dem | e_dem | pbias | egap |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 896067 | NA | 1 | 715682 | 0.000881968 | 0.94 | 0.26271 | 805369 | 36345 | 11331 | 1632 | 6132 | 155 | 2136 | 32967 | 649695 | 29039 | 7866 | 1426 | 5030 | 116 | 1294 | 21216 | 273523 | 112947 | 112947 | 273523 | 0 | 112947 | 273523 | 0.2923 | 0.2923 | 0 | 0 | 0 | 0.104 |
| 2 | 897649 | NA | 1 | 717250 | 0.000881968 | 0.94 | 0.13358 | 793465 | 28404 | 23496 | 1555 | 8771 | 274 | 2516 | 39168 | 643345 | 22963 | 15617 | 1335 | 7203 | 217 | 1687 | 24883 | 271859 | 123037 | 123037 | 271859 | 0 | 123037 | 271859 | 0.3116 | 0.3116 | 0 | 0 | 0 | 0.104 |
Specialized tables
For more targeted analysis, use the rict_* family of
functions. Each accepts a map and plan
argument, and returns either a gt table (default) or a
tibble.
Population parity
rict_population() shows total population per district
and deviation from the ideal (equal) population:
rict_population(map = wv, plan = wv$cd_2020)| District | Population |
Deviation
|
|
|---|---|---|---|
| People | % | ||
| 1 | 896,067 | −791 | −0.1% |
| 2 | 897,649 | 791 | 0.1% |
Demographics
rict_demographics() breaks down population and
voting-age population (VAP) by race and ethnicity. By default,
subcategory columns are normalized to proportions:
rict_demographics(map = wv, plan = wv$cd_2020)| District |
Total Population
|
Voting Age Population
|
||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Pop. | White | Black | Hispanic | Native | Asian | NH/PI | Other | Two+ | VAP | White | Black | Hispanic | Native | Asian | NH/PI | Other | Two+ | |
| 1 | 896,067 | 89.9% | 4.1% | 1.3% | 0.2% | 0.7% | 0.0% | 0.2% | 3.7% | 715,682 | 90.8% | 4.1% | 1.1% | 0.2% | 0.7% | 0.0% | 0.2% | 3.0% |
| 2 | 897,649 | 88.4% | 3.2% | 2.6% | 0.2% | 1.0% | 0.0% | 0.3% | 4.4% | 717,250 | 89.7% | 3.2% | 2.2% | 0.2% | 1.0% | 0.0% | 0.2% | 3.5% |
Set normalize = FALSE to see raw counts:
rict_demographics(map = wv, plan = wv$cd_2020, normalize = FALSE)| District |
Total Population
|
Voting Age Population
|
||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Pop. | White | Black | Hispanic | Native | Asian | NH/PI | Other | Two+ | VAP | White | Black | Hispanic | Native | Asian | NH/PI | Other | Two+ | |
| 1 | 896,067 | 80,536,900.0% | 3,634,500.0% | 1,133,100.0% | 163,200.0% | 613,200.0% | 15,500.0% | 213,600.0% | 3,296,700.0% | 715,682 | 64,969,500.0% | 2,903,900.0% | 786,600.0% | 142,600.0% | 503,000.0% | 11,600.0% | 129,400.0% | 2,121,600.0% |
| 2 | 897,649 | 79,346,500.0% | 2,840,400.0% | 2,349,600.0% | 155,500.0% | 877,100.0% | 27,400.0% | 251,600.0% | 3,916,800.0% | 717,250 | 64,334,500.0% | 2,296,300.0% | 1,561,700.0% | 133,500.0% | 720,300.0% | 21,700.0% | 168,700.0% | 2,488,300.0% |
Elections
rict_elections() summarizes partisan election data. It
automatically detects individual contest columns (e.g.,
pre_20_dem_bid), cycle-average columns
(adv_20, arv_20), and normal vote columns
(ndv, nrv), computing Democratic vote share
for each:
rict_elections(map = wv, plan = wv$cd_2020)| District |
Average Dem. Vote Share
|
Contests Dem. Vote Share
|
Cycle Dem. Vote Share
|
|---|---|---|---|
| Pre-Average | Pres 2020 | 2020 | |
| 1 | 29.2% | 29.2% | 29.2% |
| 2 | 31.2% | 31.2% | 31.2% |
Compactness
rict_compactness() computes geometric compactness
measures via redistmetrics. The default measures are
Polsby-Popper, Schwartzberg, Reock, and Convex Hull:
rict_compactness(map = wv, plan = wv$cd_2020)| District | Polsby-Popper | Schwartzberg | Reock | Convex Hull |
|---|---|---|---|---|
| 1 | 35.0% | 59.2% | 46.8% | 79.6% |
| 2 | 17.4% | 41.7% | 26.7% | 50.1% |
You can supply custom measures as a named list of functions:
rict_compactness(
map = wv, plan = wv$cd_2020,
measures = list(
"comp_polsby" = redistmetrics::comp_polsby,
"comp_lw" = redistmetrics::comp_lw
)
)| District | Polsby-Popper | Length Width |
|---|---|---|
| 1 | 35.0% | 70.0% |
| 2 | 17.4% | 71.8% |
Contiguity
rict_contiguity() checks how many connected pieces each
district has:
rict_contiguity(map = wv, plan = wv$cd_2020)| District | Pieces |
|---|---|
| 1 | 1 |
| 2 | 1 |
Administrative splits
rict_splits() counts how administrative boundaries
(e.g., counties, states) are split across districts:
rict_splits(map = wv, plan = wv$cd_2020, admin = "state")| District | admin_state | total_state | multi_state |
|---|---|---|---|
| 1 | 1 | 1 | 0 |
| 2 | 1 | 1 | 0 |
Component populations
rict_component() breaks down population by
administrative unit within each district:
rict_component(map = wv, plan = wv$cd_2020, admin = "county")| county | pop |
|---|---|
| 1 | |
| 005 | 21,809 |
| 007 | 12,447 |
| 011 | 94,350 |
| 013 | 6,229 |
| 015 | 8,051 |
| 019 | 40,488 |
| 021 | 7,408 |
| 025 | 32,977 |
| 035 | 27,791 |
| 039 | 180,745 |
| 043 | 20,463 |
| 045 | 32,567 |
| 047 | 19,111 |
| 053 | 25,453 |
| 055 | 59,664 |
| 059 | 23,568 |
| 063 | 12,376 |
| 067 | 24,604 |
| 071 | 6,143 |
| 075 | 7,869 |
| 079 | 57,440 |
| 081 | 74,591 |
| 087 | 14,028 |
| 089 | 11,959 |
| 099 | 38,982 |
| 101 | 8,378 |
| 105 | 5,194 |
| 109 | 21,382 |
| 2 | |
| 001 | 15,465 |
| 003 | 122,076 |
| 009 | 22,559 |
| 017 | 7,808 |
| 023 | 10,976 |
| 027 | 23,093 |
| 029 | 29,095 |
| 031 | 14,299 |
| 033 | 65,921 |
| 037 | 57,701 |
| 041 | 17,033 |
| 049 | 56,205 |
| 051 | 30,591 |
| 057 | 26,938 |
| 061 | 105,822 |
| 065 | 17,063 |
| 069 | 42,425 |
| 073 | 7,653 |
| 077 | 34,216 |
| 083 | 27,932 |
| 085 | 8,444 |
| 091 | 16,705 |
| 093 | 6,762 |
| 095 | 8,313 |
| 097 | 23,816 |
| 103 | 14,442 |
| 107 | 84,296 |
Getting tibbles instead of gt tables
Every rict_* function accepts as_gt = FALSE
to return a tibble instead of a gt table, making it easy to
use the results for further computation:
rict_elections(map = wv, plan = wv$cd_2020, as_gt = FALSE)
#> # A tibble: 2 × 4
#> District ndshare pre_20 avg_20
#> <int> <dbl> <dbl> <dbl>
#> 1 1 0.292 0.292 0.292
#> 2 2 0.312 0.312 0.312Extending gt tables
rict provides several helpers for working with
gt tables:
Partisan color scales
data_color_party() applies a red-to-blue color scale for
Democratic vote share columns:
rict(wv_plans, "cd_2020") |>
data_color_party(columns = "e_dvs")| district | total_pop | chain | pop_overlap | total_vap | plan_dev | comp_edge | comp_polsby | pop_white | pop_black | pop_hisp | pop_aian | pop_asian | pop_nhpi | pop_other | pop_two | vap_white | vap_black | vap_hisp | vap_aian | vap_asian | vap_nhpi | vap_other | vap_two | pre_20_rep_tru | pre_20_dem_bid | adv_20 | arv_20 | county_splits | ndv | nrv | ndshare | e_dvs | pr_dem | e_dem | pbias | egap |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 896067 | NA | 1 | 715682 | 0.000881968 | 0.94 | 0.26271 | 805369 | 36345 | 11331 | 1632 | 6132 | 155 | 2136 | 32967 | 649695 | 29039 | 7866 | 1426 | 5030 | 116 | 1294 | 21216 | 273523 | 112947 | 112947 | 273523 | 0 | 112947 | 273523 | 0.2923 | 0.2923 | 0 | 0 | 0 | 0.104 |
| 2 | 897649 | NA | 1 | 717250 | 0.000881968 | 0.94 | 0.13358 | 793465 | 28404 | 23496 | 1555 | 8771 | 274 | 2516 | 39168 | 643345 | 22963 | 15617 | 1335 | 7203 | 217 | 1687 | 24883 | 271859 | 123037 | 123037 | 271859 | 0 | 123037 | 271859 | 0.3116 | 0.3116 | 0 | 0 | 0 | 0.104 |
Geometry plots
gt_plot_sf() embeds small maps of sf
geometries into a gt table:
wv_dist <- wv |> dplyr::group_by(cd_2020) |> dplyr::summarize()
gt::gt(wv_dist) |> gt_plot_sf()| cd_2020 | geom |
|---|---|
| 1 | |
| 2 |
Compactness plots
gt_plot_compactness() adds visual compactness overlays
(e.g., equal-area circles, convex hulls) to a table of compactness
metrics:
rict(wv_plans, "cd_2020") |>
gt_plot_compactness(wv, wv$cd_2020)| district | total_pop | chain | pop_overlap | total_vap | plan_dev | comp_edge | comp_polsby | pop_white | pop_black | pop_hisp | pop_aian | pop_asian | pop_nhpi | pop_other | pop_two | vap_white | vap_black | vap_hisp | vap_aian | vap_asian | vap_nhpi | vap_other | vap_two | pre_20_rep_tru | pre_20_dem_bid | adv_20 | arv_20 | county_splits | ndv | nrv | ndshare | e_dvs | pr_dem | e_dem | pbias | egap | gg_polsby |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 896067 | NA | 1 | 715682 | 0.000881968 | 0.94 | 0.26271 | 805369 | 36345 | 11331 | 1632 | 6132 | 155 | 2136 | 32967 | 649695 | 29039 | 7866 | 1426 | 5030 | 116 | 1294 | 21216 | 273523 | 112947 | 112947 | 273523 | 0 | 112947 | 273523 | 0.2923 | 0.2923 | 0 | 0 | 0 | 0.104 | |
| 2 | 897649 | NA | 1 | 717250 | 0.000881968 | 0.94 | 0.13358 | 793465 | 28404 | 23496 | 1555 | 8771 | 274 | 2516 | 39168 | 643345 | 22963 | 15617 | 1335 | 7203 | 217 | 1687 | 24883 | 271859 | 123037 | 123037 | 271859 | 0 | 123037 | 271859 | 0.3116 | 0.3116 | 0 | 0 | 0 | 0.104 |
Other gt utilities
-
gt_add_column(): add a new column to agttable -
gt_get_data(): extract the underlying tibble from agttable -
gt_hide_lists(): hide list-columns (e.g., adjacency lists) from display
tab <- rict(wv)
gt_get_data(tab)
#> # A tibble: 2 × 40
#> district pop pop_white pop_black pop_hisp pop_aian pop_asian pop_nhpi
#> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 1 896067 805369 36345 11331 1632 6132 155
#> 2 2 897649 793465 28404 23496 1555 8771 274
#> # ℹ 32 more variables: pop_other <dbl>, pop_two <dbl>, vap <dbl>,
#> # vap_white <dbl>, vap_black <dbl>, vap_hisp <dbl>, vap_aian <dbl>,
#> # vap_asian <dbl>, vap_nhpi <dbl>, vap_other <dbl>, vap_two <dbl>,
#> # cd_2010 <int>, cd_2020 <int>, pre_20_rep_tru <dbl>, pre_20_dem_bid <dbl>,
#> # ndv <dbl>, adv_20 <dbl>, nrv <dbl>, arv_20 <dbl>, sample_1 <int>,
#> # sample_2 <int>, sample_3 <int>, sample_4 <int>, sample_5 <int>,
#> # sample_6 <int>, sample_7 <int>, sample_8 <int>, sample_9 <int>, …