Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any other way to implement plotly R’s cumulative animation?

accumulate_by <- function(dat, var) {
  var <- lazyeval::f_eval(var, dat)
  lvls <- plotly:::getLevels(var)
  dats <- lapply(seq_along(lvls), function(x) {
    cbind(dat[var %in% lvls[seq(1, x)], ], frame = lvls[[x]])
  })
  dplyr::bind_rows(dats)
}

d <- txhousing %>%
  filter(year > 2005, city %in% c("Abilene", "Bay Area")) %>%
  accumulate_by(~date)

If you implement a cumulative animation in the manner of the function above, the number of rows will increase too much.

I use a thousand frames and a row of ten thousand. Because of the large number of data, the work in progress has been disturbed.

https://plot.ly/r/cumulative-animations/

Is there any way to create a cumulative animation other than the example? Help me!

like image 537
Ungurrer Avatar asked Apr 17 '18 06:04

Ungurrer


1 Answers

I'm currently facing the same issue. The approach described here is not applicable for a few thousand rows of data.

I don't have a fully working solution, but my idea was to adapt the x-axis range based on the slider value instead of re-using the data for each frame (see example plot p_range_slider). This unfortunately doesn't provide us with the "Play"-button.

I thought it might be possible to use animation_slider() in a similar way but the steps argument passed to animation_slider() is not evaluated (see example plot p_animation_slider). The steps remain tied to the animation frames (as stated in ?animation_slider).

Update: this behaviour is intended by design see the sources:

  # don't let the user override steps
  slider$steps <- steps

Also building a subplot of both sharing the x-axis wasn't successful.

library(plotly)

DF <- data.frame(
  n = 1:50,
  x = seq(0, 12, length = 50),
  y = runif(n = 50, min = 0, max = 10)
)

steps <- list()

for (i in seq_len(nrow(DF))) {
  steps[[i]] <- list(
    args = list("xaxis", list(range = c(0, i))),
    label = i,
    method = "relayout",
    value = i
  )
}

# Custom range slider -----------------------------------------------------

p_range_slider <- plot_ly(
  DF,
  x = ~ x,
  y = ~ y,
  type = "scatter",
  mode = "markers"
) %>% layout(title = "Custom range slider",
       xaxis = list(range = steps[[1]]$args[[2]]$range),
       sliders = list(
         list(
           active = 0, 
           currentvalue = list(prefix = "X-max: "), 
           pad = list(t = 20), 
           steps = steps)))

p_range_slider


# Animation slider --------------------------------------------------------

p_animation_slider <- plot_ly(
  DF,
  x = ~ x,
  y = ~ y,
  type = "scatter",
  mode = "markers",
  frame = ~ n
) %>% layout(title = "Animation slider") %>% animation_slider(
  active = 6,
  currentvalue = list(prefix = "X-max: "),
  pad = list(t = 20),
  steps = steps # custom steps are ignored
)

p_animation_slider

# subplot(p_range_slider, p_animation_slider, nrows = 2, margin = 0.05, shareX = TRUE)

It seems for this approach to work animation_slider() would need to allow it's steps argument to perform custom actions (untied from the defined frames). Any other Ideas to approach this are highly appreciated.

Maybe it is possible to reproduce this approach for the python api using a filter (avoids axis-rescaling) in R? - Filter in R

Here is an example on how to use filter transform and a custom range slider in R, however, still no animation (without precomputing each frame):

DF <- data.frame(x = rep(1:10, 2), y = runif(20), group = rep(LETTERS[1:2], each = 10))

steps <- list()

for (i in seq_along(unique(DF$x))) {
  steps[[i]] <- list(
    args = list('transforms[0].value', i),
    label = i,
    method = "restyle",
    value = i
  )
}

p_filter_slider <- plot_ly(
  DF,
  x = ~ x,
  y = ~ y,
  color = ~ group,
  type = "scatter",
  mode = "lines+markers",
  transforms = list(
    list(
      type = 'filter',
      target = 'x',
      operation = '<=',
      value = ~ x
    )
  )
) %>% layout(title = "Custom filter slider",
             xaxis = list(range = c(0.5, length(unique(DF$x))+0.5)),
             sliders = list(
               list(
                 active = 0, 
                 currentvalue = list(prefix = "X-max: "), 
                 pad = list(t = 20), 
                 steps = steps))
             )

p_filter_slider

Result


Additional Infos:

animation_slider documentation

JS slider attributes

Related GitHub issue

RStudio Community question

Here is the same question on the plotly forum.

like image 170
ismirsehregal Avatar answered Oct 11 '22 01:10

ismirsehregal