I'm currently trying to create cumulative animations without accumulating the data for each frame with R-Plotly. The approach described on the plotly website is not applicable for a few thousand rows of data (see p_animation_example
).
I already tried to revive existing questions / issues on GitHub, Plotly Forum and Stack Overflow, but received no replies so far.
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_custom_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_custom_animation
). The steps remain tied to the animation frames (as stated in ?animation_slider
) because the user is not allowed to change the steps:
# don't let the user override steps
slider$steps <- steps.
(see the sources)
Also building a subplot
of both sharing the x-axis wasn't successful.
Here is what I tried so far:
library(plotly)
library(htmlwidgets)
library(dplyr)
library(lazyeval)
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)
}
n <- 100
DF <- data.frame(
n = seq_len(n),
x = seq(1, n, length = n),
y = runif(n = n, min = 0, max = 10)
)
DFacc <- accumulate_by(DF, ~n)
cat("Initial row count: ", nrow(DF), "\nAccumulated row count: ", nrow(DFacc), "\n")
# Plotly example ----------------------------------------------------------
p_animation_example <- plot_ly(
DFacc,
x = ~x,
y = ~y,
type = "scatter",
mode = "markers",
frame = ~frame
)
p_animation_example # expected behaviour but resulting in big files
# saveWidget(p_animation_example, "animation_example.html") # ~20 MB file for n = 1000
# Custom slider -----------------------------------------------------------
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
)
}
p_custom_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_custom_slider # no "Play" button available
# saveWidget(p_custom_slider, "custom_slider.html") # ~3 MB file for n = 1000
# Custom animation slider -------------------------------------------------
p_custom_animation <- 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_custom_animation # axis remains unchanged / custom steps are ignored
# saveWidget(p_custom_animation, "custom_animation.html") # ~3.5 MB file for n = 1000
# subplot -----------------------------------------------------------------
# subplot(p_custom_slider, p_custom_animation, nrows = 2, margin = 0.05, shareX = TRUE) # play button not working
Any other Ideas to approach this are highly appreciated.
Maybe it is possible to reproduce this approach for the python api using a filter transform (avoids axis-rescaling) in R? - Filter in R