class: center, middle, inverse, title-slide # D’Hondt/Jefferson Allocation ## flipbook | made with Xaringan ###
Gina Reynolds, July 2019 ###
--- # Introduction When awarding seats to parties in proportional representation systems, a dilemma is faced, as the seats available in a representative body are unlikely to able to be perfectly apportioned --- only if fractions of seats were apportioned would that be possible. --- # Plan of the book This book walks through the D'Hondt/Jefferson seat allocation method using dplyr and tidyr, using simulated data. Then we create an animation of the steps of the method using ggplot and gganimate. ```r library(tidyverse) library(animation) set.seed(2020) ``` --- # Step one: Collecting the facts To determine how many seats each party wins we need to know two things. - The number of seats available - The number of votes won by each party --- ## Number of seats available We need to know the number of seats available. Let's say 6. ```r num_seats <- 6 ``` --- ## Number of votes won by each party We also need to know how many votes were won by each party. We'll simulate a number of seats won by 3 parties. ```r num_parties <- 3 party <- c("equality", "justice", "peace", "liberty")[1:num_parties] votes <- sample(1000:10000, num_parties) party_votes <- tibble(party, votes) ``` --- ## Number of votes won by each party Let's check out the table of party and votes won. ```r party_votes ``` ``` # A tibble: 3 x 2 party votes <chr> <int> 1 equality 6822 2 justice 4548 3 peace 6565 ``` --- # Step 2: Calculate the "D'Hondt Outcome" What I call "the D'Hondt Outcome" is the number of votes won divided by 1, and 2, and 3, up to the total number of seats available for each party. Notice how the function `crossing()` is used to set ourselves up to be able to do this in the next slide. --- --- class: split-40 count: false .column[.content[ ```r *party_votes ``` ]] .column[.content[ ``` # A tibble: 3 x 2 party votes <chr> <int> 1 equality 6822 2 justice 4548 3 peace 6565 ``` ]] --- class: split-40 count: false .column[.content[ ```r party_votes %>% * crossing(divisor = 1:num_seats) ``` ]] .column[.content[ ``` # A tibble: 18 x 3 party votes divisor <chr> <int> <int> 1 equality 6822 1 2 equality 6822 2 3 equality 6822 3 4 equality 6822 4 5 equality 6822 5 6 equality 6822 6 7 justice 4548 1 8 justice 4548 2 9 justice 4548 3 10 justice 4548 4 11 justice 4548 5 12 justice 4548 6 13 peace 6565 1 14 peace 6565 2 15 peace 6565 3 16 peace 6565 4 17 peace 6565 5 18 peace 6565 6 ``` ]] --- class: split-40 count: false .column[.content[ ```r party_votes %>% crossing(divisor = 1:num_seats) %>% * mutate(dh_outcome = votes/divisor) ``` ]] .column[.content[ ``` # A tibble: 18 x 4 party votes divisor dh_outcome <chr> <int> <int> <dbl> 1 equality 6822 1 6822 2 equality 6822 2 3411 3 equality 6822 3 2274 4 equality 6822 4 1706. 5 equality 6822 5 1364. 6 equality 6822 6 1137 7 justice 4548 1 4548 8 justice 4548 2 2274 9 justice 4548 3 1516 10 justice 4548 4 1137 11 justice 4548 5 910. 12 justice 4548 6 758 13 peace 6565 1 6565 14 peace 6565 2 3282. 15 peace 6565 3 2188. 16 peace 6565 4 1641. 17 peace 6565 5 1313 18 peace 6565 6 1094. ``` ]] --- class: split-40 count: false .column[.content[ ```r party_votes %>% crossing(divisor = 1:num_seats) %>% mutate(dh_outcome = votes/divisor) -> *dhondt_calc ``` ]] .column[.content[ ]] --- # Step 3: Allocating seats Finally allocate seats using the D’Hondt/Jefferson Allocation method, we rank our "D'Hondt Outcomes", and hand out all available seats to the parties with the top D'Hondt outcomes. --- class: split-40 count: false .column[.content[ ```r *dhondt_calc ``` ]] .column[.content[ ``` # A tibble: 18 x 4 party votes divisor dh_outcome <chr> <int> <int> <dbl> 1 equality 6822 1 6822 2 equality 6822 2 3411 3 equality 6822 3 2274 4 equality 6822 4 1706. 5 equality 6822 5 1364. 6 equality 6822 6 1137 7 justice 4548 1 4548 8 justice 4548 2 2274 9 justice 4548 3 1516 10 justice 4548 4 1137 11 justice 4548 5 910. 12 justice 4548 6 758 13 peace 6565 1 6565 14 peace 6565 2 3282. 15 peace 6565 3 2188. 16 peace 6565 4 1641. 17 peace 6565 5 1313 18 peace 6565 6 1094. ``` ]] --- class: split-40 count: false .column[.content[ ```r dhondt_calc %>% * arrange(-dh_outcome) ``` ]] .column[.content[ ``` # A tibble: 18 x 4 party votes divisor dh_outcome <chr> <int> <int> <dbl> 1 equality 6822 1 6822 2 peace 6565 1 6565 3 justice 4548 1 4548 4 equality 6822 2 3411 5 peace 6565 2 3282. 6 equality 6822 3 2274 7 justice 4548 2 2274 8 peace 6565 3 2188. 9 equality 6822 4 1706. 10 peace 6565 4 1641. 11 justice 4548 3 1516 12 equality 6822 5 1364. 13 peace 6565 5 1313 14 equality 6822 6 1137 15 justice 4548 4 1137 16 peace 6565 6 1094. 17 justice 4548 5 910. 18 justice 4548 6 758 ``` ]] --- class: split-40 count: false .column[.content[ ```r dhondt_calc %>% arrange(-dh_outcome) %>% * slice(1:num_seats) ``` ]] .column[.content[ ``` # A tibble: 6 x 4 party votes divisor dh_outcome <chr> <int> <int> <dbl> 1 equality 6822 1 6822 2 peace 6565 1 6565 3 justice 4548 1 4548 4 equality 6822 2 3411 5 peace 6565 2 3282. 6 equality 6822 3 2274 ``` ]] --- class: split-40 count: false .column[.content[ ```r dhondt_calc %>% arrange(-dh_outcome) %>% slice(1:num_seats) %>% * count(party) ``` ]] .column[.content[ ``` # A tibble: 3 x 2 party n <chr> <int> 1 equality 3 2 justice 1 3 peace 2 ``` ]] --- class: split-40 count: false .column[.content[ ```r dhondt_calc %>% arrange(-dh_outcome) %>% slice(1:num_seats) %>% count(party) %>% * rename(seats_won = n) # Done! ``` ]] .column[.content[ ``` # A tibble: 3 x 2 party seats_won <chr> <int> 1 equality 3 2 justice 1 3 peace 2 ``` ]] --- class: split-40 count: false .column[.content[ ```r dhondt_calc %>% arrange(-dh_outcome) %>% slice(1:num_seats) %>% count(party) %>% rename(seats_won = n) -> # Done! *party_seats ``` ]] .column[.content[ ]] --- # Visualization Now we have calculated the seat allocation for the election. But it might be fun to also visualize this. We'll represent the data associated with the parties with colored columns, the height of which is the "D'Hondt outcome". For each of the steps used in the method, specify positions for each of the calculation steps. The variables t1 through t4 are the positions at different steps. - t1 will just show the total vote counts leaving space for those counts to be divided through by 1, 2,... [total number of votes]. - t2 shows the resultant "D'Hondt outcomes", grouped by party - t3 shows the rank among all the "D'Hondt outcomes" - t4 will show only the "D'Hondt outcomes" that are ranked high enough to earn a seat --- --- class: split-40 count: false .column[.content[ ```r *dhondt_calc ``` ]] .column[.content[ ``` # A tibble: 18 x 4 party votes divisor dh_outcome <chr> <int> <int> <dbl> 1 equality 6822 1 6822 2 equality 6822 2 3411 3 equality 6822 3 2274 4 equality 6822 4 1706. 5 equality 6822 5 1364. 6 equality 6822 6 1137 7 justice 4548 1 4548 8 justice 4548 2 2274 9 justice 4548 3 1516 10 justice 4548 4 1137 11 justice 4548 5 910. 12 justice 4548 6 758 13 peace 6565 1 6565 14 peace 6565 2 3282. 15 peace 6565 3 2188. 16 peace 6565 4 1641. 17 peace 6565 5 1313 18 peace 6565 6 1094. ``` ]] --- class: split-40 count: false .column[.content[ ```r dhondt_calc %>% * mutate(position_t2 = 1:n()) ``` ]] .column[.content[ ``` # A tibble: 18 x 5 party votes divisor dh_outcome position_t2 <chr> <int> <int> <dbl> <int> 1 equality 6822 1 6822 1 2 equality 6822 2 3411 2 3 equality 6822 3 2274 3 4 equality 6822 4 1706. 4 5 equality 6822 5 1364. 5 6 equality 6822 6 1137 6 7 justice 4548 1 4548 7 8 justice 4548 2 2274 8 9 justice 4548 3 1516 9 10 justice 4548 4 1137 10 11 justice 4548 5 910. 11 12 justice 4548 6 758 12 13 peace 6565 1 6565 13 14 peace 6565 2 3282. 14 15 peace 6565 3 2188. 15 16 peace 6565 4 1641. 16 17 peace 6565 5 1313 17 18 peace 6565 6 1094. 18 ``` ]] --- class: split-40 count: false .column[.content[ ```r dhondt_calc %>% mutate(position_t2 = 1:n()) %>% * group_by(party) ``` ]] .column[.content[ ``` # A tibble: 18 x 5 # Groups: party [3] party votes divisor dh_outcome position_t2 <chr> <int> <int> <dbl> <int> 1 equality 6822 1 6822 1 2 equality 6822 2 3411 2 3 equality 6822 3 2274 3 4 equality 6822 4 1706. 4 5 equality 6822 5 1364. 5 6 equality 6822 6 1137 6 7 justice 4548 1 4548 7 8 justice 4548 2 2274 8 9 justice 4548 3 1516 9 10 justice 4548 4 1137 10 11 justice 4548 5 910. 11 12 justice 4548 6 758 12 13 peace 6565 1 6565 13 14 peace 6565 2 3282. 14 15 peace 6565 3 2188. 15 16 peace 6565 4 1641. 16 17 peace 6565 5 1313 17 18 peace 6565 6 1094. 18 ``` ]] --- class: split-40 count: false .column[.content[ ```r dhondt_calc %>% mutate(position_t2 = 1:n()) %>% group_by(party) %>% * mutate(position_t1 = min(position_t2)) ``` ]] .column[.content[ ``` # A tibble: 18 x 6 # Groups: party [3] party votes divisor dh_outcome position_t2 position_t1 <chr> <int> <int> <dbl> <int> <dbl> 1 equality 6822 1 6822 1 1 2 equality 6822 2 3411 2 1 3 equality 6822 3 2274 3 1 4 equality 6822 4 1706. 4 1 5 equality 6822 5 1364. 5 1 6 equality 6822 6 1137 6 1 7 justice 4548 1 4548 7 7 8 justice 4548 2 2274 8 7 9 justice 4548 3 1516 9 7 10 justice 4548 4 1137 10 7 11 justice 4548 5 910. 11 7 12 justice 4548 6 758 12 7 13 peace 6565 1 6565 13 13 14 peace 6565 2 3282. 14 13 15 peace 6565 3 2188. 15 13 16 peace 6565 4 1641. 16 13 17 peace 6565 5 1313 17 13 18 peace 6565 6 1094. 18 13 ``` ]] --- class: split-40 count: false .column[.content[ ```r dhondt_calc %>% mutate(position_t2 = 1:n()) %>% group_by(party) %>% mutate(position_t1 = min(position_t2)) %>% * ungroup() ``` ]] .column[.content[ ``` # A tibble: 18 x 6 party votes divisor dh_outcome position_t2 position_t1 <chr> <int> <int> <dbl> <int> <dbl> 1 equality 6822 1 6822 1 1 2 equality 6822 2 3411 2 1 3 equality 6822 3 2274 3 1 4 equality 6822 4 1706. 4 1 5 equality 6822 5 1364. 5 1 6 equality 6822 6 1137 6 1 7 justice 4548 1 4548 7 7 8 justice 4548 2 2274 8 7 9 justice 4548 3 1516 9 7 10 justice 4548 4 1137 10 7 11 justice 4548 5 910. 11 7 12 justice 4548 6 758 12 7 13 peace 6565 1 6565 13 13 14 peace 6565 2 3282. 14 13 15 peace 6565 3 2188. 15 13 16 peace 6565 4 1641. 16 13 17 peace 6565 5 1313 17 13 18 peace 6565 6 1094. 18 13 ``` ]] --- class: split-40 count: false .column[.content[ ```r dhondt_calc %>% mutate(position_t2 = 1:n()) %>% group_by(party) %>% mutate(position_t1 = min(position_t2)) %>% ungroup() %>% * arrange(-dh_outcome) ``` ]] .column[.content[ ``` # A tibble: 18 x 6 party votes divisor dh_outcome position_t2 position_t1 <chr> <int> <int> <dbl> <int> <dbl> 1 equality 6822 1 6822 1 1 2 peace 6565 1 6565 13 13 3 justice 4548 1 4548 7 7 4 equality 6822 2 3411 2 1 5 peace 6565 2 3282. 14 13 6 equality 6822 3 2274 3 1 7 justice 4548 2 2274 8 7 8 peace 6565 3 2188. 15 13 9 equality 6822 4 1706. 4 1 10 peace 6565 4 1641. 16 13 11 justice 4548 3 1516 9 7 12 equality 6822 5 1364. 5 1 13 peace 6565 5 1313 17 13 14 equality 6822 6 1137 6 1 15 justice 4548 4 1137 10 7 16 peace 6565 6 1094. 18 13 17 justice 4548 5 910. 11 7 18 justice 4548 6 758 12 7 ``` ]] --- class: split-40 count: false .column[.content[ ```r dhondt_calc %>% mutate(position_t2 = 1:n()) %>% group_by(party) %>% mutate(position_t1 = min(position_t2)) %>% ungroup() %>% arrange(-dh_outcome) %>% * mutate(position_t3 = 1:n()) ``` ]] .column[.content[ ``` # A tibble: 18 x 7 party votes divisor dh_outcome position_t2 position_t1 position_t3 <chr> <int> <int> <dbl> <int> <dbl> <int> 1 equality 6822 1 6822 1 1 1 2 peace 6565 1 6565 13 13 2 3 justice 4548 1 4548 7 7 3 4 equality 6822 2 3411 2 1 4 5 peace 6565 2 3282. 14 13 5 6 equality 6822 3 2274 3 1 6 7 justice 4548 2 2274 8 7 7 8 peace 6565 3 2188. 15 13 8 9 equality 6822 4 1706. 4 1 9 10 peace 6565 4 1641. 16 13 10 11 justice 4548 3 1516 9 7 11 12 equality 6822 5 1364. 5 1 12 13 peace 6565 5 1313 17 13 13 14 equality 6822 6 1137 6 1 14 15 justice 4548 4 1137 10 7 15 16 peace 6565 6 1094. 18 13 16 17 justice 4548 5 910. 11 7 17 18 justice 4548 6 758 12 7 18 ``` ]] --- class: split-40 count: false .column[.content[ ```r dhondt_calc %>% mutate(position_t2 = 1:n()) %>% group_by(party) %>% mutate(position_t1 = min(position_t2)) %>% ungroup() %>% arrange(-dh_outcome) %>% mutate(position_t3 = 1:n()) %>% * mutate(position_t4 = ifelse(position_t3 > num_seats, * NA, position_t3)) ``` ]] .column[.content[ ``` # A tibble: 18 x 8 party votes divisor dh_outcome position_t2 position_t1 position_t3 <chr> <int> <int> <dbl> <int> <dbl> <int> 1 equa… 6822 1 6822 1 1 1 2 peace 6565 1 6565 13 13 2 3 just… 4548 1 4548 7 7 3 4 equa… 6822 2 3411 2 1 4 5 peace 6565 2 3282. 14 13 5 6 equa… 6822 3 2274 3 1 6 7 just… 4548 2 2274 8 7 7 8 peace 6565 3 2188. 15 13 8 9 equa… 6822 4 1706. 4 1 9 10 peace 6565 4 1641. 16 13 10 11 just… 4548 3 1516 9 7 11 12 equa… 6822 5 1364. 5 1 12 13 peace 6565 5 1313 17 13 13 14 equa… 6822 6 1137 6 1 14 15 just… 4548 4 1137 10 7 15 16 peace 6565 6 1094. 18 13 16 17 just… 4548 5 910. 11 7 17 18 just… 4548 6 758 12 7 18 # … with 1 more variable: position_t4 <int> ``` ]] --- class: split-40 count: false .column[.content[ ```r dhondt_calc %>% mutate(position_t2 = 1:n()) %>% group_by(party) %>% mutate(position_t1 = min(position_t2)) %>% ungroup() %>% arrange(-dh_outcome) %>% mutate(position_t3 = 1:n()) %>% mutate(position_t4 = ifelse(position_t3 > num_seats, NA, position_t3)) %>% * tidyr::gather(key = "step", * value = "position", * position_t2:position_t4) ``` ]] .column[.content[ ``` # A tibble: 72 x 6 party votes divisor dh_outcome step position <chr> <int> <int> <dbl> <chr> <dbl> 1 equality 6822 1 6822 position_t2 1 2 peace 6565 1 6565 position_t2 13 3 justice 4548 1 4548 position_t2 7 4 equality 6822 2 3411 position_t2 2 5 peace 6565 2 3282. position_t2 14 6 equality 6822 3 2274 position_t2 3 7 justice 4548 2 2274 position_t2 8 8 peace 6565 3 2188. position_t2 15 9 equality 6822 4 1706. position_t2 4 10 peace 6565 4 1641. position_t2 16 # … with 62 more rows ``` ]] --- class: split-40 count: false .column[.content[ ```r dhondt_calc %>% mutate(position_t2 = 1:n()) %>% group_by(party) %>% mutate(position_t1 = min(position_t2)) %>% ungroup() %>% arrange(-dh_outcome) %>% mutate(position_t3 = 1:n()) %>% mutate(position_t4 = ifelse(position_t3 > num_seats, NA, position_t3)) %>% tidyr::gather(key = "step", value = "position", position_t2:position_t4) %>% * mutate(step = as.numeric(as.factor(step))) ``` ]] .column[.content[ ``` # A tibble: 72 x 6 party votes divisor dh_outcome step position <chr> <int> <int> <dbl> <dbl> <dbl> 1 equality 6822 1 6822 2 1 2 peace 6565 1 6565 2 13 3 justice 4548 1 4548 2 7 4 equality 6822 2 3411 2 2 5 peace 6565 2 3282. 2 14 6 equality 6822 3 2274 2 3 7 justice 4548 2 2274 2 8 8 peace 6565 3 2188. 2 15 9 equality 6822 4 1706. 2 4 10 peace 6565 4 1641. 2 16 # … with 62 more rows ``` ]] --- class: split-40 count: false .column[.content[ ```r dhondt_calc %>% mutate(position_t2 = 1:n()) %>% group_by(party) %>% mutate(position_t1 = min(position_t2)) %>% ungroup() %>% arrange(-dh_outcome) %>% mutate(position_t3 = 1:n()) %>% mutate(position_t4 = ifelse(position_t3 > num_seats, NA, position_t3)) %>% tidyr::gather(key = "step", value = "position", position_t2:position_t4) %>% mutate(step = as.numeric(as.factor(step))) -> *animation_prep ``` ]] .column[.content[ ]] --- # Build static plot for one time period, i.e. a single step in the method. --- class: split-40 count: false .column[.content[ ```r *animation_prep ``` ]] .column[.content[ ``` # A tibble: 72 x 6 party votes divisor dh_outcome step position <chr> <int> <int> <dbl> <dbl> <dbl> 1 equality 6822 1 6822 2 1 2 peace 6565 1 6565 2 13 3 justice 4548 1 4548 2 7 4 equality 6822 2 3411 2 2 5 peace 6565 2 3282. 2 14 6 equality 6822 3 2274 2 3 7 justice 4548 2 2274 2 8 8 peace 6565 3 2188. 2 15 9 equality 6822 4 1706. 2 4 10 peace 6565 4 1641. 2 16 # … with 62 more rows ``` ]] --- class: split-40 count: false .column[.content[ ```r animation_prep %>% * # plotting single time period * filter(step == 2) ``` ]] .column[.content[ ``` # A tibble: 18 x 6 party votes divisor dh_outcome step position <chr> <int> <int> <dbl> <dbl> <dbl> 1 equality 6822 1 6822 2 1 2 peace 6565 1 6565 2 13 3 justice 4548 1 4548 2 7 4 equality 6822 2 3411 2 2 5 peace 6565 2 3282. 2 14 6 equality 6822 3 2274 2 3 7 justice 4548 2 2274 2 8 8 peace 6565 3 2188. 2 15 9 equality 6822 4 1706. 2 4 10 peace 6565 4 1641. 2 16 11 justice 4548 3 1516 2 9 12 equality 6822 5 1364. 2 5 13 peace 6565 5 1313 2 17 14 equality 6822 6 1137 2 6 15 justice 4548 4 1137 2 10 16 peace 6565 6 1094. 2 18 17 justice 4548 5 910. 2 11 18 justice 4548 6 758 2 12 ``` ]] --- class: split-40 count: false .column[.content[ ```r animation_prep %>% # plotting single time period filter(step == 2) %>% * ggplot() ``` ]] .column[.content[ <img src="dhondt_jefferson_allocation_files/figure-html/output_static_4-1.png" width="100%" /> ]] --- class: split-40 count: false .column[.content[ ```r animation_prep %>% # plotting single time period filter(step == 2) %>% ggplot() + * aes(xmin = position + .4, * xmax = position - .4, * ymin = 0, * ymax = dh_outcome, * fill = party, * group = paste(party, divisor), * alpha = as.numeric(step == 3)) ``` ]] .column[.content[ <img src="dhondt_jefferson_allocation_files/figure-html/output_static_11-1.png" width="100%" /> ]] --- class: split-40 count: false .column[.content[ ```r animation_prep %>% # plotting single time period filter(step == 2) %>% ggplot() + aes(xmin = position + .4, xmax = position - .4, ymin = 0, ymax = dh_outcome, fill = party, group = paste(party, divisor), alpha = as.numeric(step == 3)) + * scale_fill_viridis_d() ``` ]] .column[.content[ <img src="dhondt_jefferson_allocation_files/figure-html/output_static_12-1.png" width="100%" /> ]] --- class: split-40 count: false .column[.content[ ```r animation_prep %>% # plotting single time period filter(step == 2) %>% ggplot() + aes(xmin = position + .4, xmax = position - .4, ymin = 0, ymax = dh_outcome, fill = party, group = paste(party, divisor), alpha = as.numeric(step == 3)) + scale_fill_viridis_d() + * geom_rect(alpha = .7) ``` ]] .column[.content[ <img src="dhondt_jefferson_allocation_files/figure-html/output_static_13-1.png" width="100%" /> ]] --- class: split-40 count: false .column[.content[ ```r animation_prep %>% # plotting single time period filter(step == 2) %>% ggplot() + aes(xmin = position + .4, xmax = position - .4, ymin = 0, ymax = dh_outcome, fill = party, group = paste(party, divisor), alpha = as.numeric(step == 3)) + scale_fill_viridis_d() + geom_rect(alpha = .7) + * geom_vline(xintercept = 0.25, * col = "slategray", * size = 1.25) ``` ]] .column[.content[ <img src="dhondt_jefferson_allocation_files/figure-html/output_static_16-1.png" width="100%" /> ]] --- class: split-40 count: false .column[.content[ ```r animation_prep %>% # plotting single time period filter(step == 2) %>% ggplot() + aes(xmin = position + .4, xmax = position - .4, ymin = 0, ymax = dh_outcome, fill = party, group = paste(party, divisor), alpha = as.numeric(step == 3)) + scale_fill_viridis_d() + geom_rect(alpha = .7) + geom_vline(xintercept = 0.25, col = "slategray", size = 1.25) + * geom_vline(xintercept = c(6.5, 12.5), * col = "slategray", * size = 1, * linetype = "dotted") ``` ]] .column[.content[ <img src="dhondt_jefferson_allocation_files/figure-html/output_static_20-1.png" width="100%" /> ]] --- class: split-40 count: false .column[.content[ ```r animation_prep %>% # plotting single time period filter(step == 2) %>% ggplot() + aes(xmin = position + .4, xmax = position - .4, ymin = 0, ymax = dh_outcome, fill = party, group = paste(party, divisor), alpha = as.numeric(step == 3)) + scale_fill_viridis_d() + geom_rect(alpha = .7) + geom_vline(xintercept = 0.25, col = "slategray", size = 1.25) + geom_vline(xintercept = c(6.5, 12.5), col = "slategray", size = 1, linetype = "dotted") + * labs(title = "D’Hondt/Jefferson Seat Allocation") ``` ]] .column[.content[ <img src="dhondt_jefferson_allocation_files/figure-html/output_static_21-1.png" width="100%" /> ]] --- class: split-40 count: false .column[.content[ ```r animation_prep %>% # plotting single time period filter(step == 2) %>% ggplot() + aes(xmin = position + .4, xmax = position - .4, ymin = 0, ymax = dh_outcome, fill = party, group = paste(party, divisor), alpha = as.numeric(step == 3)) + scale_fill_viridis_d() + geom_rect(alpha = .7) + geom_vline(xintercept = 0.25, col = "slategray", size = 1.25) + geom_vline(xintercept = c(6.5, 12.5), col = "slategray", size = 1, linetype = "dotted") + labs(title = "D’Hondt/Jefferson Seat Allocation") + * labs(subtitle = "Data: Hypothetical parties and results") ``` ]] .column[.content[ <img src="dhondt_jefferson_allocation_files/figure-html/output_static_22-1.png" width="100%" /> ]] --- class: split-40 count: false .column[.content[ ```r animation_prep %>% # plotting single time period filter(step == 2) %>% ggplot() + aes(xmin = position + .4, xmax = position - .4, ymin = 0, ymax = dh_outcome, fill = party, group = paste(party, divisor), alpha = as.numeric(step == 3)) + scale_fill_viridis_d() + geom_rect(alpha = .7) + geom_vline(xintercept = 0.25, col = "slategray", size = 1.25) + geom_vline(xintercept = c(6.5, 12.5), col = "slategray", size = 1, linetype = "dotted") + labs(title = "D’Hondt/Jefferson Seat Allocation") + labs(subtitle = "Data: Hypothetical parties and results") + * labs(caption = "Visualization: Gina Reynolds @EvaMaeRey in R with ggplot and gganimate") ``` ]] .column[.content[ <img src="dhondt_jefferson_allocation_files/figure-html/output_static_23-1.png" width="100%" /> ]] --- class: split-40 count: false .column[.content[ ```r animation_prep %>% # plotting single time period filter(step == 2) %>% ggplot() + aes(xmin = position + .4, xmax = position - .4, ymin = 0, ymax = dh_outcome, fill = party, group = paste(party, divisor), alpha = as.numeric(step == 3)) + scale_fill_viridis_d() + geom_rect(alpha = .7) + geom_vline(xintercept = 0.25, col = "slategray", size = 1.25) + geom_vline(xintercept = c(6.5, 12.5), col = "slategray", size = 1, linetype = "dotted") + labs(title = "D’Hondt/Jefferson Seat Allocation") + labs(subtitle = "Data: Hypothetical parties and results") + labs(caption = "Visualization: Gina Reynolds @EvaMaeRey in R with ggplot and gganimate") + * labs(x = "Number of Seats (divisor)") ``` ]] .column[.content[ <img src="dhondt_jefferson_allocation_files/figure-html/output_static_24-1.png" width="100%" /> ]] --- class: split-40 count: false .column[.content[ ```r animation_prep %>% # plotting single time period filter(step == 2) %>% ggplot() + aes(xmin = position + .4, xmax = position - .4, ymin = 0, ymax = dh_outcome, fill = party, group = paste(party, divisor), alpha = as.numeric(step == 3)) + scale_fill_viridis_d() + geom_rect(alpha = .7) + geom_vline(xintercept = 0.25, col = "slategray", size = 1.25) + geom_vline(xintercept = c(6.5, 12.5), col = "slategray", size = 1, linetype = "dotted") + labs(title = "D’Hondt/Jefferson Seat Allocation") + labs(subtitle = "Data: Hypothetical parties and results") + labs(caption = "Visualization: Gina Reynolds @EvaMaeRey in R with ggplot and gganimate") + labs(x = "Number of Seats (divisor)") + * labs(y = "Number of Votes\ndivided by 1, 2, ..., N") ``` ]] .column[.content[ <img src="dhondt_jefferson_allocation_files/figure-html/output_static_25-1.png" width="100%" /> ]] --- class: split-40 count: false .column[.content[ ```r animation_prep %>% # plotting single time period filter(step == 2) %>% ggplot() + aes(xmin = position + .4, xmax = position - .4, ymin = 0, ymax = dh_outcome, fill = party, group = paste(party, divisor), alpha = as.numeric(step == 3)) + scale_fill_viridis_d() + geom_rect(alpha = .7) + geom_vline(xintercept = 0.25, col = "slategray", size = 1.25) + geom_vline(xintercept = c(6.5, 12.5), col = "slategray", size = 1, linetype = "dotted") + labs(title = "D’Hondt/Jefferson Seat Allocation") + labs(subtitle = "Data: Hypothetical parties and results") + labs(caption = "Visualization: Gina Reynolds @EvaMaeRey in R with ggplot and gganimate") + labs(x = "Number of Seats (divisor)") + labs(y = "Number of Votes\ndivided by 1, 2, ..., N") + * scale_y_continuous(expand = c(.02, .02)) ``` ]] .column[.content[ <img src="dhondt_jefferson_allocation_files/figure-html/output_static_26-1.png" width="100%" /> ]] --- class: split-40 count: false .column[.content[ ```r animation_prep %>% # plotting single time period filter(step == 2) %>% ggplot() + aes(xmin = position + .4, xmax = position - .4, ymin = 0, ymax = dh_outcome, fill = party, group = paste(party, divisor), alpha = as.numeric(step == 3)) + scale_fill_viridis_d() + geom_rect(alpha = .7) + geom_vline(xintercept = 0.25, col = "slategray", size = 1.25) + geom_vline(xintercept = c(6.5, 12.5), col = "slategray", size = 1, linetype = "dotted") + labs(title = "D’Hondt/Jefferson Seat Allocation") + labs(subtitle = "Data: Hypothetical parties and results") + labs(caption = "Visualization: Gina Reynolds @EvaMaeRey in R with ggplot and gganimate") + labs(x = "Number of Seats (divisor)") + labs(y = "Number of Votes\ndivided by 1, 2, ..., N") + scale_y_continuous(expand = c(.02, .02)) + * scale_x_continuous(breaks = 1:(num_parties * num_seats), * labels = rep(1:num_seats, num_parties), * expand = c(.01, .01)) ``` ]] .column[.content[ <img src="dhondt_jefferson_allocation_files/figure-html/output_static_29-1.png" width="100%" /> ]] --- class: split-40 count: false .column[.content[ ```r animation_prep %>% # plotting single time period filter(step == 2) %>% ggplot() + aes(xmin = position + .4, xmax = position - .4, ymin = 0, ymax = dh_outcome, fill = party, group = paste(party, divisor), alpha = as.numeric(step == 3)) + scale_fill_viridis_d() + geom_rect(alpha = .7) + geom_vline(xintercept = 0.25, col = "slategray", size = 1.25) + geom_vline(xintercept = c(6.5, 12.5), col = "slategray", size = 1, linetype = "dotted") + labs(title = "D’Hondt/Jefferson Seat Allocation") + labs(subtitle = "Data: Hypothetical parties and results") + labs(caption = "Visualization: Gina Reynolds @EvaMaeRey in R with ggplot and gganimate") + labs(x = "Number of Seats (divisor)") + labs(y = "Number of Votes\ndivided by 1, 2, ..., N") + scale_y_continuous(expand = c(.02, .02)) + scale_x_continuous(breaks = 1:(num_parties * num_seats), labels = rep(1:num_seats, num_parties), expand = c(.01, .01)) + * scale_alpha_continuous(range = c(0, 1), * guide = F) ``` ]] .column[.content[ <img src="dhondt_jefferson_allocation_files/figure-html/output_static_31-1.png" width="100%" /> ]] --- class: split-40 count: false .column[.content[ ```r animation_prep %>% # plotting single time period filter(step == 2) %>% ggplot() + aes(xmin = position + .4, xmax = position - .4, ymin = 0, ymax = dh_outcome, fill = party, group = paste(party, divisor), alpha = as.numeric(step == 3)) + scale_fill_viridis_d() + geom_rect(alpha = .7) + geom_vline(xintercept = 0.25, col = "slategray", size = 1.25) + geom_vline(xintercept = c(6.5, 12.5), col = "slategray", size = 1, linetype = "dotted") + labs(title = "D’Hondt/Jefferson Seat Allocation") + labs(subtitle = "Data: Hypothetical parties and results") + labs(caption = "Visualization: Gina Reynolds @EvaMaeRey in R with ggplot and gganimate") + labs(x = "Number of Seats (divisor)") + labs(y = "Number of Votes\ndivided by 1, 2, ..., N") + scale_y_continuous(expand = c(.02, .02)) + scale_x_continuous(breaks = 1:(num_parties * num_seats), labels = rep(1:num_seats, num_parties), expand = c(.01, .01)) + scale_alpha_continuous(range = c(0, 1), guide = F) -> *single_time_period_gg ``` ]] .column[.content[ ]] --- # Some theme fine tuning, if you please --- class: split-40 count: false .column[.content[ ```r *single_time_period_gg ``` ]] .column[.content[ <img src="dhondt_jefferson_allocation_files/figure-html/output_theme_1-1.png" width="100%" /> ]] --- class: split-40 count: false .column[.content[ ```r single_time_period_gg + * theme(axis.ticks = element_blank()) ``` ]] .column[.content[ <img src="dhondt_jefferson_allocation_files/figure-html/output_theme_2-1.png" width="100%" /> ]] --- class: split-40 count: false .column[.content[ ```r single_time_period_gg + theme(axis.ticks = element_blank()) + * theme(legend.background = element_rect(fill = "gainsboro")) ``` ]] .column[.content[ <img src="dhondt_jefferson_allocation_files/figure-html/output_theme_3-1.png" width="100%" /> ]] --- class: split-40 count: false .column[.content[ ```r single_time_period_gg + theme(axis.ticks = element_blank()) + theme(legend.background = element_rect(fill = "gainsboro")) + * theme(plot.background = element_rect(fill = "gainsboro")) ``` ]] .column[.content[ <img src="dhondt_jefferson_allocation_files/figure-html/output_theme_4-1.png" width="100%" /> ]] --- class: split-40 count: false .column[.content[ ```r single_time_period_gg + theme(axis.ticks = element_blank()) + theme(legend.background = element_rect(fill = "gainsboro")) + theme(plot.background = element_rect(fill = "gainsboro")) + * theme(panel.background = element_rect(fill = "gainsboro")) ``` ]] .column[.content[ <img src="dhondt_jefferson_allocation_files/figure-html/output_theme_5-1.png" width="100%" /> ]] --- class: split-40 count: false .column[.content[ ```r single_time_period_gg + theme(axis.ticks = element_blank()) + theme(legend.background = element_rect(fill = "gainsboro")) + theme(plot.background = element_rect(fill = "gainsboro")) + theme(panel.background = element_rect(fill = "gainsboro")) + * theme(panel.grid = element_line(color = "plum4", size = .2)) ``` ]] .column[.content[ <img src="dhondt_jefferson_allocation_files/figure-html/output_theme_6-1.png" width="100%" /> ]] --- class: split-40 count: false .column[.content[ ```r single_time_period_gg + theme(axis.ticks = element_blank()) + theme(legend.background = element_rect(fill = "gainsboro")) + theme(plot.background = element_rect(fill = "gainsboro")) + theme(panel.background = element_rect(fill = "gainsboro")) + theme(panel.grid = element_line(color = "plum4", size = .2)) + * theme(panel.grid.minor = element_blank()) ``` ]] .column[.content[ <img src="dhondt_jefferson_allocation_files/figure-html/output_theme_7-1.png" width="100%" /> ]] --- class: split-40 count: false .column[.content[ ```r single_time_period_gg + theme(axis.ticks = element_blank()) + theme(legend.background = element_rect(fill = "gainsboro")) + theme(plot.background = element_rect(fill = "gainsboro")) + theme(panel.background = element_rect(fill = "gainsboro")) + theme(panel.grid = element_line(color = "plum4", size = .2)) + theme(panel.grid.minor = element_blank()) + * theme(text = element_text(family = "Helvetica", size = 15)) ``` ]] .column[.content[ <img src="dhondt_jefferson_allocation_files/figure-html/output_theme_8-1.png" width="100%" /> ]] --- class: split-40 count: false .column[.content[ ```r single_time_period_gg + theme(axis.ticks = element_blank()) + theme(legend.background = element_rect(fill = "gainsboro")) + theme(plot.background = element_rect(fill = "gainsboro")) + theme(panel.background = element_rect(fill = "gainsboro")) + theme(panel.grid = element_line(color = "plum4", size = .2)) + theme(panel.grid.minor = element_blank()) + theme(text = element_text(family = "Helvetica", size = 15)) + * theme(plot.title = element_text(face = "bold")) ``` ]] .column[.content[ <img src="dhondt_jefferson_allocation_files/figure-html/output_theme_9-1.png" width="100%" /> ]] --- class: split-40 count: false .column[.content[ ```r single_time_period_gg + theme(axis.ticks = element_blank()) + theme(legend.background = element_rect(fill = "gainsboro")) + theme(plot.background = element_rect(fill = "gainsboro")) + theme(panel.background = element_rect(fill = "gainsboro")) + theme(panel.grid = element_line(color = "plum4", size = .2)) + theme(panel.grid.minor = element_blank()) + theme(text = element_text(family = "Helvetica", size = 15)) + theme(plot.title = element_text(face = "bold")) + * theme(legend.position = c(.85, .8)) ``` ]] .column[.content[ <img src="dhondt_jefferson_allocation_files/figure-html/output_theme_10-1.png" width="100%" /> ]] --- class: split-40 count: false .column[.content[ ```r single_time_period_gg + theme(axis.ticks = element_blank()) + theme(legend.background = element_rect(fill = "gainsboro")) + theme(plot.background = element_rect(fill = "gainsboro")) + theme(panel.background = element_rect(fill = "gainsboro")) + theme(panel.grid = element_line(color = "plum4", size = .2)) + theme(panel.grid.minor = element_blank()) + theme(text = element_text(family = "Helvetica", size = 15)) + theme(plot.title = element_text(face = "bold")) + theme(legend.position = c(.85, .8)) + * theme(legend.title = element_blank()) ``` ]] .column[.content[ <img src="dhondt_jefferson_allocation_files/figure-html/output_theme_11-1.png" width="100%" /> ]] --- class: split-40 count: false .column[.content[ ```r single_time_period_gg + theme(axis.ticks = element_blank()) + theme(legend.background = element_rect(fill = "gainsboro")) + theme(plot.background = element_rect(fill = "gainsboro")) + theme(panel.background = element_rect(fill = "gainsboro")) + theme(panel.grid = element_line(color = "plum4", size = .2)) + theme(panel.grid.minor = element_blank()) + theme(text = element_text(family = "Helvetica", size = 15)) + theme(plot.title = element_text(face = "bold")) + theme(legend.position = c(.85, .8)) + theme(legend.title = element_blank()) + * theme(legend.key = element_rect(color = "gainsboro")) ``` ]] .column[.content[ <img src="dhondt_jefferson_allocation_files/figure-html/output_theme_12-1.png" width="100%" /> ]] --- class: split-40 count: false .column[.content[ ```r single_time_period_gg + theme(axis.ticks = element_blank()) + theme(legend.background = element_rect(fill = "gainsboro")) + theme(plot.background = element_rect(fill = "gainsboro")) + theme(panel.background = element_rect(fill = "gainsboro")) + theme(panel.grid = element_line(color = "plum4", size = .2)) + theme(panel.grid.minor = element_blank()) + theme(text = element_text(family = "Helvetica", size = 15)) + theme(plot.title = element_text(face = "bold")) + theme(legend.position = c(.85, .8)) + theme(legend.title = element_blank()) + theme(legend.key = element_rect(color = "gainsboro")) + * theme(axis.title.y = element_text(hjust = 1, * size = 10)) ``` ]] .column[.content[ <img src="dhondt_jefferson_allocation_files/figure-html/output_theme_14-1.png" width="100%" /> ]] --- class: split-40 count: false .column[.content[ ```r single_time_period_gg + theme(axis.ticks = element_blank()) + theme(legend.background = element_rect(fill = "gainsboro")) + theme(plot.background = element_rect(fill = "gainsboro")) + theme(panel.background = element_rect(fill = "gainsboro")) + theme(panel.grid = element_line(color = "plum4", size = .2)) + theme(panel.grid.minor = element_blank()) + theme(text = element_text(family = "Helvetica", size = 15)) + theme(plot.title = element_text(face = "bold")) + theme(legend.position = c(.85, .8)) + theme(legend.title = element_blank()) + theme(legend.key = element_rect(color = "gainsboro")) + theme(axis.title.y = element_text(hjust = 1, size = 10)) + * theme(axis.title.x = element_text(hjust = 0, * size = 10)) ``` ]] .column[.content[ <img src="dhondt_jefferson_allocation_files/figure-html/output_theme_16-1.png" width="100%" /> ]] --- class: split-40 count: false .column[.content[ ```r single_time_period_gg + theme(axis.ticks = element_blank()) + theme(legend.background = element_rect(fill = "gainsboro")) + theme(plot.background = element_rect(fill = "gainsboro")) + theme(panel.background = element_rect(fill = "gainsboro")) + theme(panel.grid = element_line(color = "plum4", size = .2)) + theme(panel.grid.minor = element_blank()) + theme(text = element_text(family = "Helvetica", size = 15)) + theme(plot.title = element_text(face = "bold")) + theme(legend.position = c(.85, .8)) + theme(legend.title = element_blank()) + theme(legend.key = element_rect(color = "gainsboro")) + theme(axis.title.y = element_text(hjust = 1, size = 10)) + theme(axis.title.x = element_text(hjust = 0, size = 10)) -> *static_w_theme ``` ]] .column[.content[ ]] --- # Animation --- class: split-40 count: false .column[.content[ ```r *static_w_theme %+% * # use ALL the data. * # %+% is a special ggplot operator to * # reset ggplot global data * animation_prep ``` ]] .column[.content[ <img src="dhondt_jefferson_allocation_files/figure-html/output_the_animation_5-1.png" width="100%" /> ]] --- class: split-40 count: false .column[.content[ ```r static_w_theme %+% # use ALL the data. # %+% is a special ggplot operator to # reset ggplot global data animation_prep + * # add animation declarations * gganimate::transition_time(time = step) + * gganimate::ease_aes("exponential-in-out") ``` ]] .column[.content[ <img src="dhondt_jefferson_allocation_files/figure-html/output_the_animation_8-1.gif" width="100%" /> ]] --- # Conclusion A seat is awarded for each party column left in the final step of the visualization. --- # Implications In the opening lines of his 1973 paper, "The Relationship between Seats and Votes in Two-Party Systems", Edward Tufte makes the observation: > *"An enduring fact of life in democratic electoral systems is that the party winning the largest share of the votes almost always receives a still larger share of the seats."* While clearly qualified, Tufte "winner-takes-more" generalization is indeed true of D'Hondt seat allocation. Let's compare the share of votes won in our example versus the share of seats won for each party in our hypothetical example. <img src="dhondt_jefferson_allocation_files/figure-html/unnamed-chunk-5-1.png" width="45%" /><img src="dhondt_jefferson_allocation_files/figure-html/unnamed-chunk-5-2.png" width="45%" /> --- # The End! Thanks for joining! The code for this work lives [here](https://github.com/EvaMaeRey/little_flipbooks_library). Open to suggestions. Send me a pull request. Interested in building your own flipbook? It is fun! The code is still underdevelopment, and we'd love to have your feedback. A minimal example is [here]( https://evamaerey.github.io/little_flipbooks_library/tidytuesday_minimal_example/tidytuesday_minimal_example#1). <style type="text/css"> .remark-code{line-height: 1.5; font-size: 60%} </style>