Henrique Fernandes
Henrique Fernandes

Reputation: 21

Adding traces to plotly animations in R

I am trying to develop a Business Cycle Clock similar to https://kosis.kr/visual/bcc/index/index.do?language=eng.

I've already achieved most of the things I wanted to replicate, but I can't figure it out how to add these traces (for example, in the link above set speed to 10 and trace length to 5 and then click on 'Apply' to understand what I mean).

Does anyone have any idea how to implement it? It would make the "clock" much easier to read. Thanks in advance.

Reprocible example:

library(plotly)
library(dplyr)
library(magrittr)

variable <- rep('A',10)
above_trend <- rnorm(10)
mom_increase <- rnorm(10)
ref_date <- seq.Date('2010-01-01' %>% as.Date,
                     length.out = 10,by='m')


full_clock_db <- cbind.data.frame(variable, above_trend, mom_increase, ref_date)

freq_aux = 'm'

ct = 'Brazil'

main_title = paste0('Business Cycle Clock para: ', ct)

m <- list(l=60, r=170, b=50, t=70, pad=4)

y_max_abs = 2
x_max_abs = 5

fig = plot_ly(
  data = full_clock_db,
  x = ~mom_increase,
  y = ~above_trend,
  color = ~variable,
  frame = ~ref_date,
  text = ~variable,
  hoverinfo = "text",
  type = 'scatter',
  mode = 'markers'
) %>%
  animation_opts( frame = 800,
                  transition = 500,
                  easing = "circle",
                  redraw = TRUE,
                  mode = "immediate") %>%
  animation_slider(
    currentvalue = list(prefix = "Período", font = list(color="red"))
  )

fig

Upvotes: 1

Views: 297

Answers (2)

thothal
thothal

Reputation: 20329

Another more elegant solution would be to rely on ggplot2 + gganimate:

library(ggplot2)
library(gganimate)

ggplot(full_clock_db, aes(x = mom_increase, y = above_trend)) +
  geom_point(aes(group = 1L)) +
  transition_time(ref_date) +
  shadow_wake(wake_length = 0.1, alpha = .6)

You cna play with different shadow_* functions to find the one to your liking.

Moving point with a trail

Upvotes: 1

thothal
thothal

Reputation: 20329

One way would be to use a line plot and repeat points as necessary. Here's an example as POC:

library(dplyr)
library(plotly)

e <- tibble(x = seq(-3, 3, 0.01)) %>% 
  mutate(y = dnorm(x)) %>% 
  mutate(iter = 1:n())

accumulate <- function(data, by, trace_length = 5L) {
  data_traf <- data %>% 
    arrange({{ by }}) %>% 
    mutate(pos_end = 1:n(),
           pos_start = pmax(pos_end - trace_length + 1L, 1L)) 
  data_traf %>% 
    rowwise() %>% 
    group_map(~ data_traf %>% slice(seq(.x$pos_start, .x$pos_end, 1L)) %>% 
                mutate("..{{by}}.new" := .x %>% pull({{by}}))) %>% 
    bind_rows()
}

enew <- e %>% 
  accumulate(iter, 100) 
plot_ly(x = ~ x, y = ~ y) %>% 
  add_trace(data = e, type = "scatter", mode = "lines", 
            line = list(color = "lightgray", width = 10)) %>% 
  add_trace(data = enew, frame = ~ ..iter.new,
            type = "scatter", mode = "lines") %>% 
  animation_opts(frame = 20, 10)

The idea is that for each step, you keep the trace_length previous steps and assign them to the same frame counter (here ..iter.new). Then you plot lines instead of points and you have a sort of trace..

Upvotes: 0

Related Questions