2

I have created an animated plot using ggplot2 and then gganimate. The plot shows points changing in time and I have highlighted in red, a point of interest, and in yellow, points that stick around with the red point over time.

I am trying to have outside of the plot on the right hand side, what the red and yellow points are (as in their identity in the dataframe) and change according to the time point. as you see some yellow points disappear etc - however I cannot make this work. I have tried geom_text(),`` labs() with no luck.

The code for the plot is:

library(gifski)
 library(gganimate)
 library(ggplot2)

    labels = 'word1'
    highlight_red<- words[words$X %in% labels,]#dataframe with word of interest
    
    labels2<-c("word2", "word3")
    highlight_orange<-words[words$X %in% labels2,]#dataframe with word of interest
    
    p <- ggplot(words, aes(x_coord, y=y_coord, col = time)) +
      theme_void()+
      labs(title ="{words$time[words$time == round(frame_time)][1]}") +
      theme(plot.title = element_text(size = 50, face = "bold", colour = "grey", margin = margin(t = 10, b = -20)))+
      geom_point(alpha = 1)+
      geom_point(data=highlight_red, 
                 aes(x_coord, y=y_coord), 
                 color='red',
                 size=3)+
      geom_point(data=highlight_orange, 
                 aes(x_coord, y=y_coord), 
                 color='orange',
                 size=3, alpha=0.8)+
      guides(size=FALSE) +
      theme(legend.title = element_blank()) +
      coord_fixed(ratio = 1)
    
    
    p<-p+
      transition_time(time)+
      shadow_wake(wake_length = 0, alpha = FALSE)+
      enter_fade() + 
      exit_shrink()
    
    animate(p, duration = 5, fps = 20, renderer = gifski_renderer())

Attached is the gif. I would like the words of interest that are closest to the red point (say top 5 for example) to cycle on the right hand side in a list as they do on the scatter plot to reflect what is actually changing around the red point. I have tried adding code such as (to the main ggplot code)

# geom_text(aes(label = "{highlight_orange$X[highlight_orange$time == round(frame_time)][1]}"),
    #        hjust = -0.35,#adjust position
     #       size = 3,
      #      check_overlap = TRUE)

with absolutely no luck - it needs to be in a neat list as well and not overlapping of course. any help is much appreciated. thank you.

enter image description here

Reproducible table (shortened for select words)

         X    x_coord    y_coord time 
1     word1  27.065716  59.019010   1        
2     word2  22.936882  61.470710   1        
3     word3  25.227564  62.780384   1        
4     word4  27.878267  61.130566   1        
5     word5  22.929253  61.345573   1        
6     word6  14.307319 -44.314228   1        
8760  word1   6.607143 -56.996240   2       
8844  word2 -64.222240  -9.363668   2       
10370 word3 -63.630585  -8.037662   2       
10501 word4 -13.532422 -50.246193   2       
13788 word5   5.143321 -56.445950   3       
14583 word6 -67.655820 -29.041885   3       
22566 word1 -48.322063 -24.847290   4       
26496 word3   3.340046  14.917225   5     
27050 word6   2.397841 -53.621520   6       
28818 word3 -19.618414  37.386040   6       
30582 word5 -15.498601 -51.142025   6       
31513 word4  -3.114899 -14.631951   6       
32772 word1  -4.706020  -9.429874   6       
  • this looks interesting, and I'd love to give an upvote for the lovely gif (+1), but *pleeease* make this reproducible (+1 -1 = 0) . You're long enough around, you should know what that means? – tjebo Feb 15 '21 at 14:08
  • apologies, much shortened table (but reproducible) now added to original post, –  Feb 15 '21 at 14:21
  • 1
    getting there :) – tjebo Feb 15 '21 at 14:30
  • 2
    the table isn't directly reproducible as is. You should share the code that reproduces the table. – s_baldur Feb 15 '21 at 14:51
  • done - this should absolutely work now with the table provided, i have tested (the code has been updated, table remains the same).. thank you –  Feb 15 '21 at 15:08

1 Answers1

1

Not sure I understood correctly if this is what you are trying to do. From your question it seems that you would like to show a list with the words in highlight_orange in a list next to the plot. And you would like for the words to move around if they change from one frame to the next.

If this is the case, I kind of found a way to do this. But the only thing is bothering me is that I could not set a different enter and exit property for the geom_text. I would like geom_text to use enter_fly and exit_fly (and let geom_point keep using enter_fade and exit_shrink).

Apparently it is possible to do this, but I could not figure out how to do this...

Anyway, I will put my answer here as is because maybe it helps you.

# get max y and y (for positioning list in plot)
max.y <- ceiling(max(words$y_coord))
max.x <- ceiling(max(words$x_coord))

# calculate x/y position of list of words
highlight_orange <- highlight_orange %>%
  dplyr::group_by(time) %>%
  # position in list
  dplyr::mutate(rank = row_number()) %>%
  # compute x, y position in plot (I had to do trial and error with the y offset so the words would not overlap)
  dplyr::mutate(x_pos=max.x, y_pos=max.y - 4*(rank-1)) %>% dplyr::ungroup()


p <- ggplot(words, aes(x_coord, y=y_coord, col = time)) +
  theme_void()+
  labs(title ="{words$time[words$time == round(frame_time)][1]}") +
  theme(plot.title = element_text(size = 50, face = "bold", colour = "grey", margin = margin(t = 10, b = -20)))+
  geom_point(alpha = 1)+
  geom_point(data=highlight_red, 
             aes(x=x_coord, y=y_coord), 
             color='red',
             size=3)+
  geom_point(data=highlight_orange, 
             aes(x=x_coord, y=y_coord), 
             color='orange',
             size=3, alpha=0.8)+
  geom_text(data=highlight_orange, aes(x=x_pos, y=y_pos, label=X, group=X), hjust=0, vjust=0.5, colour='black') +
  guides(size=FALSE, col=FALSE) +
  theme(legend.title = element_blank()) +
  # set "clip=off" so you can draw the text outside of the plotting area
  coord_fixed(ratio = 1, clip = "off")


# I think you can set different enter/exit for each layer. But I could not figure out how...
p + transition_time(time) + shadow_wake(wake_length = 0, alpha = FALSE) + 
  enter_fade() +  exit_shrink()

enter image description here

kikoralston
  • 1,176
  • 5
  • 6
  • Thank you so much! this does exactly what I am looking for! A couple of questions... I agree with the exit and enter fade - it should be customisable: Is there a way for a smoother transition of words (or is this what you meant by enter and exit fade) when I make the video 60 seconds long, which is what i need in the end - the words are too slow to to move in the order and just look like they overlap each other.. and: when i make the font bigger in geom_text, the words overlap. geom_text_repel does not work as it adds labels to the points on the plot as well - is there a way to do this? –  Feb 17 '21 at 10:12
  • so just a quick edit: I sort of fixed the overlap by doing check.overlap=T in geom_text and i removed enter and exit fade.. this now makes the words appear or disappear without overlapping! –  Feb 17 '21 at 14:15
  • 1
    Great! `check.overlap=T` is a good idea! Did not think about this. Also, when I defined the positions of the words I set an arbitrary y offset value (the `4` value in `y_pos=max.y - 4*(rank-1)`). So another option would be to play around with this value when you changed the size of the words. Good to know that removing enter and exit fade got you the effect you wanted. Hopefully you did not loose a desired effect in the actual points. I think I will create a question in SO to check if someone knows how to define different enter/exit effects for different layers. – kikoralston Feb 17 '21 at 15:13
  • yes! thanks so much again :) actually removing it doesnt change too much and if i set a falloff in shadow_wake, it helps. I just need to figure out how to make each layer stay longer as the change of words from the last layer ands first layer is basically instant and doesnt stay! thanks again! –  Feb 17 '21 at 15:54