Search code examples
rggplot2gganimate

Rotating through multiple Y Variables in gganimate


I'm currently trying to animate a plot using gganimate but am struggling to figure out how I would rotate through multiple y variables. The following data was collected from twitter scraping which allowed me to calculate a "sentiment score" based on the tweets following the recent Democratic debate. The goal here is to create an animated plot that eases through all 10 sentiment scores and adjusts the ggplot for each candidate. Is this possible with gganimate?

  structure(
    list(
      candidate = c("warren", "booker", "yang", "harris",  "biden", "sanders", "buttigieg"),
      anger = c(162, 216, 193, 74, 451, 290, 114),
      anticipation = c(570, 492, 401, 205, 360, 419, 499),
      disgust = c(94, 75, 52, 61, 202, 81, 69),
      fear = c(245, 241, 119, 117, 271, 251, 102),
      joy = c(574, 525, 279, 181, 214, 319, 183),
      sadness = c(237, 161, 138, 106, 406, 157, 251),
      surprise = c(104, 191, 176, 106, 255, 343, 123),
      trust = c(741, 749, 460, 325,  593, 574, 410),
      negative = c(540, 317, 253, 205, 715, 360, 469),
      positive = c(989, 1202, 857, 510, 751, 790, 701)
    ),
    class = c("spec_tbl_df",  "tbl_df", "tbl", "data.frame"),
    row.names = c(NA, -7L),
    spec = structure(
      list(
        cols = list(
          candidate = structure(list(), class = c("collector_character",  "collector")),
          anger = structure(list(), class = c("collector_double", "collector")),
          anticipation = structure(list(), class = c("collector_double",  "collector")),
          disgust = structure(list(), class = c("collector_double",  "collector")),
          fear = structure(list(), class = c("collector_double", "collector")),
          joy = structure(list(), class = c("collector_double", "collector")),
          sadness = structure(list(), class = c("collector_double", "collector")),
          surprise = structure(list(), class = c("collector_double", "collector")),
          trust = structure(list(), class = c("collector_double", "collector")),
          negative = structure(list(), class = c("collector_double", "collector")),
          positive = structure(list(), class = c("collector_double", "collector"))),
        default = structure(list(), class = c("collector_guess", "collector")), skip = 1
      ),
      class = "col_spec")

  )

Here is the script I currently have written:

library ("ggplot2")
library("dplyr")
library("tidyverse")
library("plotly")
library("viridis")
library("gganimate")


#Read in CSV Files
sentiment_score <- read_csv('C:\\Users\\tdago\\Documents\\R\\Sentiment_Scores.csv')
sentiment_score_hashtag <- read_csv('C:\\Users\\tdago\\Documents\\R\\Sentiment_Scores_hashtag.csv')


#Tidy Data
sentiment_score <- sentiment_score %>%
  rename(candidate = X1)

sentiment_score_hashtag <-sentiment_score_hashtag %>%
  rename(candidate = X1)

#Create Charts for Comparison

ggplot(data=sentiment_score,aes(x = candidate, y=anger))+
  geom_bar(aes(fill=candidate),stat = "identity")+
  theme(legend.position="none")+
  xlab("Presidential Candidates")+ylab("Scores")+ggtitle("Anger") +
  labs(x = "", y = "{sentiment"}) +
  ease_aes('linear') 

Note: the sentiment_score object is the only one that is being used in this specific chart. sentiment_score_hashtag is a similar data frame that contains sentiment scores based on a different search.


Solution

  • I don't think you can rotate through Y variables with gganimate. Is easier to transform your data from wide to long format (see this question for a comprehensive list of methods to achieve this). I will go with the tidy way, using tidyr::pivot_longer:

    > sentiment_score %>%
    +     pivot_longer(-candidate, names_to = 'sentiment')
    # A tibble: 70 x 3
       candidate sentiment    value
       <chr>     <chr>        <dbl>
     1 warren    anger          162
     2 warren    anticipation   570
     3 warren    disgust         94
     4 warren    fear           245
     5 warren    joy            574
     6 warren    sadness        237
     7 warren    surprise       104
     8 warren    trust          741
     9 warren    negative       540
    10 warren    positive       989
    # … with 60 more rows
    > 
    

    This way, you can use easily sentiment as a state variable in gganimate, and follow the nice gganimate getting started manual.

    Here is an example of the possibilities:

    library ("ggplot2")
    library("dplyr")
    #> 
    #> Attaching package: 'dplyr'
    #> The following objects are masked from 'package:stats':
    #> 
    #>     filter, lag
    #> The following objects are masked from 'package:base':
    #> 
    #>     intersect, setdiff, setequal, union
    library("tidyverse")
    # library("plotly")
    # library("viridis")
    library("gganimate")
    
    
    #Tidy Data
    sentiment_score <- structure(
      list(
        candidate = c("warren", "booker", "yang", "harris",  "biden", "sanders", "buttigieg"),
        anger = c(162, 216, 193, 74, 451, 290, 114),
        anticipation = c(570, 492, 401, 205, 360, 419, 499),
        disgust = c(94, 75, 52, 61, 202, 81, 69),
        fear = c(245, 241, 119, 117, 271, 251, 102),
        joy = c(574, 525, 279, 181, 214, 319, 183),
        sadness = c(237, 161, 138, 106, 406, 157, 251),
        surprise = c(104, 191, 176, 106, 255, 343, 123),
        trust = c(741, 749, 460, 325,  593, 574, 410),
        negative = c(540, 317, 253, 205, 715, 360, 469),
        positive = c(989, 1202, 857, 510, 751, 790, 701)
      ),
      class = c("spec_tbl_df",  "tbl_df", "tbl", "data.frame"),
      row.names = c(NA, -7L),
      spec = structure(
        list(
          cols = list(
            candidate = structure(list(), class = c("collector_character",  "collector")),
            anger = structure(list(), class = c("collector_double", "collector")),
            anticipation = structure(list(), class = c("collector_double",  "collector")),
            disgust = structure(list(), class = c("collector_double",  "collector")),
            fear = structure(list(), class = c("collector_double", "collector")),
            joy = structure(list(), class = c("collector_double", "collector")),
            sadness = structure(list(), class = c("collector_double", "collector")),
            surprise = structure(list(), class = c("collector_double", "collector")),
            trust = structure(list(), class = c("collector_double", "collector")),
            negative = structure(list(), class = c("collector_double", "collector")),
            positive = structure(list(), class = c("collector_double", "collector"))),
          default = structure(list(), class = c("collector_guess", "collector")), skip = 1
        ),
        class = "col_spec")
    
    )
    
    #Create Charts for Comparison
    candidates_plot <- sentiment_score %>%
      pivot_longer(-candidate, names_to = 'sentiment') %>%
      ggplot(aes(x = candidate, y=value))+
      geom_bar(aes(fill=candidate, group = sentiment),stat = "identity")+
      scale_y_continuous(expand = c(0,0), limits = c(0,1250)) +
      theme(legend.position="none")#+
    # xlab("Presidential Candidates")+ylab("Scores")+ggtitle("{sentiment}") +
    # labs(x = "Presidential Candidates", y = "{sentiment}")
    
    anim <- candidates_plot +
      transition_states(
        sentiment, 2, 2
      ) +
      enter_fade() + enter_drift(y_mod = -500) +
      exit_shrink() + exit_drift(y_mod = -500) +
    
      labs(
        title = '{closest_state}',
        x = "Presidential Candidates", y = "{closest_state}"
      )
    
    animate(
      anim, width = 500, height = 300, res = 90
    )
    

    Created on 2019-11-25 by the reprex package (v0.3.0)