Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

gganimate: include additional variable other than states level variable or frame in title expression

I'd like to insert another column value of my data into a gganimate animation title.

Example, here the states level variable is x and I'd like to add to title variable y:

df <- tibble(x = 1:10, y = c('a', 'a', 'b', 'd', 'c', letters[1:5]))
df

A tibble: 10 x 2
       x y    
   <int> <chr>
 1     1 a    
 2     2 a    
 3     3 b    
 4     4 d    
 5     5 c    
 6     6 a    
 7     7 b    
 8     8 c    
 9     9 d    
10    10 e 

This works as expected:

ggplot(df, aes(x, x)) +
  geom_point() +
  labs(title = '{closest_state}') +
  transition_states(x,
                    transition_length = 0.1,
                    state_length = 0.1)

enter image description here

This fails:

ggplot(df, aes(x, x)) +
  geom_point() +
  labs(title = '{closest_state}, another_var: {y}') +
  transition_states(x,
                    transition_length = 0.1,
                    state_length = 0.1)

Error in eval(parse(text = text, keep.source = FALSE), envir) :
object 'y' not found

Also tried this, but y will not change:

ggplot(df, aes(x, x)) +
  geom_point() +
  labs(title = str_c('{closest_state}, another_var: ', df$y)) +
  transition_states(x,
                    transition_length = 0.1,
                    state_length = 0.1)

enter image description here

Another option is to map y as the states level variable and use the frame variable instead of x, but in my application y is either a not-necessarily-unique character variable like above, or it is a numeric variable but again not-necessarily-unique and not-necessarily-ordered. In which case gganimate (or ggplot?) will order it as it sees fit, making the final result weird not ordered by x:

ggplot(df, aes(x, x)) +
  geom_point() +
  labs(title = '{frame}, another_var: {closest_state}') +
  transition_states(y,
                    transition_length = 0.1,
                    state_length = 0.1)

enter image description here

So how to simply add the changing value of the un-ordered, not numeric, y variable?

Finally: This question was asked here but without a reproducible example so it was not answered, hoping this one is better.

like image 662
Giora Simchoni Avatar asked Dec 20 '18 08:12

Giora Simchoni


3 Answers

One dirty solution would be to paste together the variables and make a new one to use in the transition_states:

df <- mutate(df, title_var = factor(paste(x, y, sep="-"), levels = paste(x, y, sep="-")))
# # A tibble: 6 x 3
# x y     title_var
# <int> <chr> <fct>    
# 1     1 a     1-a      
# 2     2 a     2-a      
# 3     3 b     3-b      
# 4     4 d     4-d      
# 5     5 c     5-c      
# 6     6 a     6-a  

Then we could use gsub() in ordet to strip closest_state from the unwanted part, like this:

gsub(pattern = "\\d+-", replacement = "", "1-a") 
"a"

So:

ggplot(df, aes(x, x)) +
  geom_point() +
  labs(title = '{gsub(pattern = "\\d+-", replacement = "", closest_state)}') +
  transition_states(title_var, transition_length = 0.1, state_length = 0.1)

enter image description here

like image 104
RLave Avatar answered Oct 18 '22 02:10

RLave


Another possibility, slightly more compact, from the author of gganimate himself, following the issue I opened:

https://github.com/thomasp85/gganimate/issues/252#issuecomment-450846868

According to Thomas:

There are multiple reasons why random columns from the input data cannot be accessed so it is unlikely to get any better than this...

like image 28
Giora Simchoni Avatar answered Oct 18 '22 02:10

Giora Simchoni


Here's a solution using dplyr, based on the gganimate developer Thomas's solution, provided by Giora.

library(tidyverse)
library(gganimate)

df <- tibble::tibble(x = 1:10, y = c('a', 'a', 'b', 'd', 'c', letters[1:5]))

a <- ggplot(df, aes(x, x)) +
  geom_point() +
  labs(title = "{closest_state}, another_var: {df %>% filter(x == closest_state) %>% pull(y)}") +
  transition_states(x,
                    transition_length = 0.1,
                    state_length = 0.1)
animate(a)

The gganimate titles use glue syntax for the animated title elements, and you can include entire dplyr data manipulation pipelines within them.

You can refer to the closest_state variable provided by gganimate::transition_states() within your dplyr calls. Here, since the animation's frames are indexed by successive levels of x, I use filter() to subset df for a given frame based on the value of x and then refer to corresponding rows of column y, which contain additional information I'd like to display in the title. Using pull, you can grab the individual value of y corresponding to x and display it within the animation's title.

This is a clean and straightforward way to do it with the advantage that you can, e.g., compute summary values to display on-the-fly by adding summarize() and other calls in your magrittr pipeline.

like image 2
martinlu Avatar answered Oct 18 '22 00:10

martinlu