Last active
December 2, 2025 13:12
-
-
Save elliottmorris/3399e606d9be1fd28574a09be63fdac3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| library(tidyverse) | |
| library(janitor) | |
| library(zoo) | |
| library(scales) | |
| clean_and_avg = function(series){ | |
| dat = read_csv(sprintf('%s.csv',series)) | |
| dat = janitor::clean_names(dat) | |
| dat$date = as.Date(as.POSIXct(dat$unix_timestamp/1000, origin = "1970-01-01", tz = "UTC")) | |
| dat = dat %>% | |
| group_by(party,date) %>% | |
| summarise(n = n()) %>% | |
| group_by(party) %>% | |
| arrange(party, date) %>% | |
| mutate(ntot = cumsum(n)) %>% | |
| group_by(party) %>% | |
| mutate(daily_avg = rollapply(data = n, width = 30, partial = T, fill = NA, FUN = mean, na.rm = T, align = 'right')) %>% | |
| ungroup() %>% | |
| mutate(index = rescale(daily_avg, to = c(0, 100))) %>% | |
| rename({{series}} := daily_avg) %>% | |
| select(all_of(c('party','date',series))) | |
| return(dat) | |
| } | |
| dat = | |
| expand_grid(party = c("Democrat","Republican"), | |
| date = seq.Date(ymd('2010-01-01'),ymd('2025-11-25'))) %>% | |
| left_join( | |
| clean_and_avg('inflation'), | |
| by=c('party','date') | |
| ) %>% | |
| left_join( | |
| clean_and_avg('affordability'), | |
| by=c('party','date') | |
| ) %>% | |
| left_join( | |
| clean_and_avg('prices'), | |
| by=c('party','date') | |
| ) | |
| dat = dat %>% | |
| mutate_at(c('inflation','affordability','prices'), | |
| na.approx, na.rm = F) | |
| dat %>% | |
| filter(date >= ymd('2024-01-01')) %>% | |
| gather(word, avg, 3:5) %>% | |
| filter(word == 'affordability') %>% | |
| ungroup() %>% | |
| mutate(index = rescale(avg, to = c(0, 100))) %>% | |
| ggplot(., aes(x = date, y = index, col = party)) + | |
| # annotation one | |
| annotate(geom='text',x = ymd('2025-06-20'),y=80, | |
| label = 'Zohran Mamdani wins 2025\nDemocratic mayoral primary\nin New York City', | |
| hjust = 1) + | |
| geom_vline(xintercept = ymd('2025-06-24'),col='black') + | |
| # annotation 2 | |
| annotate(geom='text',x = ymd('2025-11-01'),y=90, | |
| label = '2025\nstatewide\nand NYC\ngeneral\nelections', | |
| hjust = 1) + | |
| geom_vline(xintercept = ymd('2025-11-04'),col='black') + | |
| # annotation 3 | |
| annotate(geom='text',x = ymd('2024-11-01'),y=90, | |
| label = 'Trump wins\n2024 election', | |
| hjust = 1) + | |
| geom_vline(xintercept = ymd('2024-11-05'),col='black') + | |
| # annotation 4 | |
| annotate(geom='text',x = ymd('2024-07-15'),y=60, | |
| label = 'Joe Biden drops out\nof 2024 presidential election', | |
| hjust = 1) + | |
| geom_vline(xintercept = ymd('2024-07-21'),col='black') + | |
| # rest of chart | |
| geom_line() + | |
| scale_color_manual(values = c('Democrat' = 'blue','Republican'='red')) + | |
| coord_cartesian(ylim=c(0,100)) + | |
| scale_x_date(date_labels = '%b %Y') + | |
| labs(x = 'Date', | |
| y = 'Mentions index\n(max monthly avg = 100)', | |
| subtitle = 'Index of monthly average mentions of the word "affordability" in congressional emails,\nby political party. 100 = max monthly value.', | |
| title='Republicans are playing catch-up on "affordability"', | |
| col = 'Party', | |
| caption = 'Data: DCInbox.com\nSource: Strength In Numbers/gelliottmorris.com') + | |
| theme_minimal() + | |
| theme(legend.position = 'top',legend.justification = 'left', | |
| plot.caption = element_text(hjust=0), | |
| panel.grid.minor.x = element_blank()) | |
| dat %>% | |
| filter(date >= ymd('2025-06-01')) %>% | |
| gather(word, avg, 3:5) %>% | |
| filter(word == 'affordability') %>% | |
| ungroup() %>% | |
| mutate(index = rescale(avg, to = c(0, 100))) %>% | |
| ggplot(., aes(x = date, y = index, col = party)) + | |
| # annotation one | |
| annotate(geom='text',x = ymd('2025-06-25'),y=60, | |
| label = 'Zohran Mamdani wins 2025\nDemocratic mayoral primary\nin New York City', | |
| hjust = 0) + | |
| geom_vline(xintercept = ymd('2025-06-24'),col='black') + | |
| # annotation 2 | |
| annotate(geom='text',x = ymd('2025-11-01'),y=90, | |
| label = '2025\nstatewide\nand NYC\ngeneral\nelections', | |
| hjust = 1) + | |
| geom_vline(xintercept = ymd('2025-11-04'),col='black') + | |
| # rest of chart | |
| geom_line() + | |
| scale_color_manual(values = c('Democrat' = 'blue','Republican'='red')) + | |
| coord_cartesian(ylim=c(0,100)) + | |
| scale_x_date(date_breaks = 'month', date_labels = '%b') + | |
| labs(x = '2025', | |
| y = 'Mentions index\n(max monthly avg = 100)', | |
| subtitle = 'Index of monthly average mentions of the word "affordability" in congressional emails,\nby political party. 100 = max monthly value.', | |
| title='Republicans are playing catch-up on "affordability"', | |
| col = 'Party', | |
| caption = 'Data: DCInbox.com\nSource: Strength In Numbers/gelliottmorris.com') + | |
| theme_minimal() + | |
| theme(legend.position = 'top',legend.justification = 'left', | |
| plot.caption = element_text(hjust=0), | |
| panel.grid.minor.x = element_blank()) | |
| dat %>% | |
| filter(date >= ymd('2024-01-01')) %>% | |
| gather(word, avg, 3:5) %>% | |
| #filter(word != 'prices') %>% | |
| ungroup() %>% | |
| mutate(index = rescale(avg, to = c(0, 100))) %>% | |
| ggplot(., aes(x = date, y = index, col = word)) + | |
| geom_line() + | |
| facet_wrap(~party,ncol=1) + | |
| theme_minimal() + | |
| scale_color_manual(values = c('affordability' = 'green','inflation'='gray40','prices'='pink')) + | |
| coord_cartesian(ylim=c(0,100)) + | |
| scale_x_date(date_breaks = '6 month', date_labels = '%b %Y') + | |
| labs(x = 'Date', | |
| y = 'Mentions index\n(max monthly avg = 100)', | |
| subtitle = 'Index of monthly average mentions of words related to affordability and prices\nin congressional emails, by word political party. 100 = max monthly value.', | |
| title='"Affordability" is the new "inflation"', | |
| col = 'Word', | |
| caption = 'Data: DCInbox.com\nSource: Strength In Numbers/gelliottmorris.com') + | |
| theme_minimal() + | |
| theme(legend.position = 'top',legend.justification = 'left', | |
| plot.caption = element_text(hjust=0), | |
| panel.grid.minor.x = element_blank()) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment