12

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.

Giora Simchoni
  • 3,487
  • 3
  • 34
  • 72
  • Good that you have done background study & formatted well. This helps in the comprehension & quick dispersal of knowledge. – massisenergy Dec 20 '18 at 08:41
  • What if you create a dedicated new variable to use in `transition_states`? Maybe this is not desired, so I'll use a comment and will delete if it's not what you intended, but: `df <- mutate(df, title_var = paste(x, y, sep="-"))` then `+ transition_states(title_var, transition_length = 0.1, state_length = 0.1)` – RLave Dec 20 '18 at 08:59
  • Great direction! However: 1. It doesn't work yet, `title_var` is a character vector sorted in the title like "1-a", "10-a", etc, not sorted by `x` ; 2. What if I didn't want `x` in the title? `y` is the important variable here, I think we should have a solution which lets you have that different variable in the title, in general. – Giora Simchoni Dec 20 '18 at 09:10
  • I might be wrong but I don't see any way to include another variable [in the doc](https://gganimate.com/reference/transition_states.html?q=label#label-variables) (other than what @RLave suggested).Maybe you should [open an issue on github](https://github.com/thomasp85/gganimate/issues/new)? – 7hibault Dec 20 '18 at 09:13
  • @RLave this fixes my (1) item: `df <- mutate(df, title_var = factor(paste(x, y, sep="-"), levels = paste(x, y, sep="-")))`, now `title_var` is a sorted factor and this is the best we have so far. – Giora Simchoni Dec 20 '18 at 09:27
  • Yes, I wouldn't be surprised if that's the best we can do at the moment, @7hibault I'll open that issue anyway. – Giora Simchoni Dec 20 '18 at 09:40
  • 1
    issue submitted https://github.com/thomasp85/gganimate/issues/252 – Giora Simchoni Dec 20 '18 at 09:48

3 Answers3

5

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

RLave
  • 8,144
  • 3
  • 21
  • 37
4

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...

Giora Simchoni
  • 3,487
  • 3
  • 34
  • 72
2

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.

martinlu
  • 41
  • 4