Skip to contents

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:

  • gt for formatted HTML output
  • tibble for data-frame output (set as_gt = FALSE)

Data

rict ships with two example datasets from West Virginia:

  • wv: a redist_map object with county-level demographic, partisan, and geographic data
  • wv_plans: a redist_plans object with sampled redistricting plans and the enacted 2020 congressional plan
data(wv)
data(wv_plans)

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.312

Extending 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

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>, …