Twitter in collage: a year in the life of a freshman Congresswoman

[This article was first published on Jason Timm, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.


A super simple post that summarizes R-based methods for visual summary & collage-building using image attachments on Twitter. In the process, a bit of a photo homage to Congresswoman Xochitl Torres Small in her first year representing New Mexico’s 2nd district.

if (!require("pacman")) install.packages("pacman")
pacman::p_load(tidyverse, rtweet, tigris) 
options(tigris_use_cache = TRUE, tigris_class = "sf")

New Mexico’s 2nd District

The 2nd congressional district of New Mexico is a super fun district. It is not my district, but I have a few stomping grounds that way. Faywood is home to natural hot springs and a STAR-GAZING CHAIR!!!. Weed has an absolutely lovely frisbee golf course. Ruidoso has all things: including two disc golf courses and a horse track.

Folks in the district supported Trump in 2016 by a fair margin (+10.2%) and subsequently sent a freshman Democrat to the House in 2018. Only the second time the district has sent a Democrat to the House in the last 30 years. Also, it is one of only five districts that supported Trump by more than ten points, supported McCain in 2008 & Romney in 2012, and sent a Democrat to Congress in 2018. I have written some previously about Torres Small’s win in 2018 and the demographics of the district.

So, a complicated & ideologically diverse district. And Congresswoman Torres Small does an amazing job representing this diversity. She is one of the few House Dems that engages with Fox News, eg, writing op-eds and doing interviews. And she is a super positive Twitter follow if you are interested in feeling good about the folks that represent us in Congress.

The district is also geographically vast – and super-rural. Per the table below, NM-02 is the fifth largest district in the country – only the big rural states with at-large representation are bigger. So, lots of ground to cover.

cds <- tigris::congressional_districts(cb = TRUE)

cds %>%
  data.frame() %>%
  arrange(desc(ALAND)) %>%
  slice(1:5) %>%
  mutate(ALAND = round(ALAND/ 2.59e+6,0), # SQUARE MILES
         ALAND = format(ALAND,
         geo = c('Alaska', 'Montana',
                 'Wyoming', 'South Dakota',
                 'New Mexico - 02')) %>%
  select(geo, GEOID, ALAND)%>%
Alaska 0200 570,883
Montana 3000 145,545
Wyoming 5600 97,091
South Dakota 4600 75,809
New Mexico – 02 3502 71,745

One hundred days into her term in the 116th Congress, Congresswoman Torres Small tweeted:

In #100Days, I’ve ✈️???? over 43,000 miles & met w/ constituents in

✅Bernalillo ✅Catron ✅Chaves ✅Cibola ✅De Baca ✅Dona Ana ✅Eddy ✅Grant ✅Guadalupe ✅Hidalgo ✅Lea ✅Lincoln ✅Luna ✅McKinley ✅Otero ✅Roosevelt ✅Sierra ✅Socorro ✅Valencia

And I’m just getting started

So, she is on the move. The map below highlights the district in geographical context. Lots of big districts in the Southwest. NM-02 is roughly bounded by Mexico, West Texas, ABQ/Santa Fe metros, and the Navajo Nation. A bit of cultural crossroads, as it were.

world <- rnaturalearth::ne_countries(scale = "medium", returnclass = "sf") %>%
  filter(gu_a3 %in% c('USA', 'MEX'))
states <- tigris::states(cb = TRUE)

cds %>%
  mutate(color = ifelse(GEOID == '3502', 'blue', 'gray')) %>%
  ggplot() + 
  geom_sf(data = world,  color = 'darkgray', alpha = .75,  
          fill = '#dae2ba', size = 1.1) + 
  geom_sf(aes(fill = color), color = 'darkgray') + 
  scale_fill_manual(values = c('lightblue', 'gray')) +
  ggsflabel::lims_bbox(cds %>%
                         filter(STATEFP %in% c('04', '48', '35', '32'))) +
  geom_sf(data = states,  color = 'darkgray', alpha = 0,  size = 1.1) + 
  theme(legend.position = 'none') +
  ggtitle('NM-02 in context')

Collaging the year’s happenings

So, the goal here is to provide a visual summary (ie, collage) of Congresswoman Torres Small’s year representing NM-02 using images from Twitter. Via the rtweet package, we collect all of @RepTorresSmall tweets since she took office at the beginning of 2019.

xochitl_tweets <- rtweet::get_timeline( 
  n = 1500,
  check=FALSE) %>%
  mutate(created_at = as.Date(gsub(' .*$', '', created_at))) %>%
  filter(is_quote == 'FALSE' & 
           is_retweet == 'FALSE' & 
           created_at > '2019-01-02' &
           display_text_width > 0)

Next, we identify tweets containing photo attachments. And then download these photos locally. The code presented here has been modified directly from this post. For a more detailed walk through of methods, I would recommend having a look.

pics <- xochitl_tweets %>%
  filter(! %>%
  select(media_url, created_at)

lapply(pics$media_url, function (y) {
  magick::image_read(y) %>%
    magick::image_scale("1000") %>%
    magick::image_border('white', '10x10') %>%
    magick::image_write(gsub('^.*/', '', y)) #%>%
    #magick::image_annotate(pics$created_at[y], font = 'Times', size = 50)

Next, we shuffle the photos some, and then stack photos as a collection of single column collages. Again, these intermediary files are stored locally.

files <- dir(local_pics, full.names = TRUE)
files <- sample(files, length(files))
files1 <- files[1:49]
no_rows <- 7
no_cols <- 7

make_column <- function(i, files, no_rows){
  magick::image_read(files[(i*no_rows+1):((i+1)*no_rows)]) %>%
    magick::image_append(stack = TRUE) %>%
    magick::image_write(paste0("cols", i, ".jpg"))}

     files = files1,
     no_rows = no_rows)

Lastly, we piece together the column collages as a single collage. For good measure, I created three collages comprised of 7 x 7 = 49 photos. A busy year for the Congresswoman.

magick::image_read(dir(local_cols, full.names = TRUE)) %>% 
  magick::image_scale("500x1000") %>%
  magick::image_append(stack = FALSE) 

To leave a comment for the author, please follow the link and comment on their blog: Jason Timm. offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)