plot gganimado onde os pontos ficam e a linha desaparece

11

Aqui está um exemplo reprodutível de um gráfico estático, que eu quero animar (quero mostrar como um amostrador MCMC se comporta).

library(tidyverse)
library(gganimate)

set.seed(1234)
plot_data <- tibble(x=cumsum(rnorm(100)),
                    y=cumsum(rnorm(100)),
                    time=1:length(x)) 

ggplot(data=plot_data,
       aes(x=y, y=x)) +
  geom_point() + geom_line()

insira a descrição da imagem aqui

O que eu gostaria de ver é que os pontos são visíveis quando são desenhados e um pouco desbotados (ou seja, alfa passa de 1 para 0,3) depois, enquanto haveria uma linha que mostra apenas o histórico recente (e, idealmente, desbota mostrando o história mais recente, menos desbotada e mais do que alguns passos para trás, desaparecendo totalmente).

O seguinte alcança mais ou menos o que eu quero para meus pontos (então, em certo sentido, eu só quero adicionar linhas desbotadas para conectar os últimos pontos - pontos desbotando mais lentamente em alguns quadros seriam ainda mais agradáveis):

ggplot(data=plot_data,
       aes(x=y, y=x)) +
  geom_point() +
  transition_time(time) +
  shadow_mark(past = T, future=F, alpha=0.3)

Gráfico mostrando como os pontos devem desaparecer

O que eu estou lutando é como adicionar dois comportamentos diferentes para dois geoms, por exemplo, ponto e linha. Por exemplo, abaixo os pontos desaparecem (eu não quero que eles) e as linhas não desaparecem (eu quero que eles).

p <- ggplot(data=plot_data,
       aes(x=y, y=x)) +
  geom_point() +
  transition_time(time) +
  shadow_mark(past = T, future=F, alpha=0.3)

p + geom_line() +
  transition_reveal(along = time) +
  shadow_mark(past = T, future=F, alpha=0.3) 
Björn
fonte

Respostas:

17

Tive problemas ao usar as shadow_*funções internas para controlar mais de um comportamento por vez; parecia aplicar apenas o mais recente. (Usando o gganimate 1.0.3.9000)

Uma maneira de contornar isso é calcular as transições manualmente. Por exemplo, podemos copiar os dados 100 vezes, uma cópia para cada quadro e, em seguida, especificar o alfa para nossa camada de pontos e o alfa para nossa camada de segmento separadamente.

plot_data %>%
  uncount(100, .id = "frame") %>%
  filter(time <= frame) %>%
  arrange(frame, time) %>%
  group_by(frame) %>%
  mutate(x_lag = lag(x), 
         y_lag = lag(y),
         tail = last(time) - time,
         # Make the points solid for 1 frame then alpha 0.3
         point_alpha = if_else(tail == 0, 1, 0.3),
         # Make the lines fade out over 20 frames
         segment_alpha = pmax(0, (20-tail)/20)) %>%
  ungroup() %>%

  ggplot(aes(x=y, y=x, xend = y_lag, yend = x_lag, group = time)) +
  geom_segment(aes(alpha = segment_alpha)) +
  geom_point(aes(alpha = point_alpha)) +
  scale_alpha(range = c(0,1)) +
  guides(alpha = F) +
  transition_manual(frame)

insira a descrição da imagem aqui

(Para esta renderização, envolvi-a animate( [everything above], width = 600, height = 400, type = "cairo"))

Jon Spring
fonte
11
Muito obrigado. Um pequeno problema na sua resposta: point_alpha = ... & segment_alpha = ... precisa estar dentro do mutate (...). Modificou a resposta de acordo.
Björn