I am trying to build a shiny app that includes an animated plotly scatter. My plot has two traces which are different colours. I want to animate the position of the bars (as in the example below) and then animate to the new xaxis scaling (also in the example below). How do I avoid plotly resetting the xaxis scaling after each frame (as in the example below)? This seems like a bug.
In my app data I need to move points between the two traces (i.e. change their colour). I don’t think it is possible to animate this? I could do it if every data point was its own trace. What’s the maximum number of traces? Thanks.
library(shiny)
library(plotly)
library(dplyr)
ui <- fluidPage(
plotlyOutput("plot")
)
gendata <- function(){
cat("gendata\n")
ndata <- 10
d <- tibble(text=LETTERS[1:ndata], f=1, x=runif(ndata)) %>% mutate(r = rank(x))
rbind(mutate(d, x=-1), d, mutate(d, x=-1)) %>%
arrange(text)
}
server <- function(input, output, session){
origdata <- gendata()
axrange <- function(x){
list(-0.1*runif(1), 1+0.1*runif(1))
}
my <- reactiveValues(
data = origdata,
xrange = list(0,1)
)
output$plot <- renderPlotly({
isolate({
cat("renderPlotly\n")
plot_ly() %>%
add_trace(x=my$data$x, y=my$data$r, frame=my$data$f, line=list(width=20, simplify=FALSE), opacity=0.3, color=I("orange"), type="scatter", mode="lines", name="Rank") %>%
add_trace(x=my$data$x + 0.02, y=my$data$r, frame=my$data$f, text=my$data$text, type="scatter", mode="text", showlegend=FALSE) %>%
layout(xaxis=list(range=my$xrange, autorange=FALSE)) %>%
animation_opts(frame=500, transition=500, redraw=FALSE)
})
})
proxy <- plotlyProxy("plot", session=session, deferUntilFlush=FALSE)
# https://shiny.rstudio.com/reference/shiny/0.14/reactiveTimer.html
speed = 1000 # redraw every 1 second
autoInvalidate <- reactiveTimer(speed)
observe({
autoInvalidate()
})
observeEvent(autoInvalidate(), {
# req(NULL)
cat("observeEvent autoInvalidate()\n")
my$data <- gendata() %>% mutate(f = my$data$f + 1)
# print(head(my$data))
# https://plot.ly/javascript/plotlyjs-function-reference/#plotlyanimate
data <- list(list(
x = my$data$x,
y = my$data$r,
line=list(width=20, simplify=FALSE, color=sample(c(I("red"), I("green"), I("blue")), 1)),
frame = my$data$f
),
list(
x = my$data$x + 0.02,
y = my$data$r,
text = my$data$text,
frame = my$data$f
))
cat("animate scatter\n")
plotlyProxyInvoke(proxy, "animate",
# frameOrGroupNameOrFrameList
list(
data = data,
traces = as.list(as.integer(0:1)),
layout = list(xaxis=list(autorange=FALSE))
),
# animationAttributes
list(
frame=as.list(rep(list(duration=speed), length(0:1))),
transition=as.list(rep(list(duration=speed), length(0:1)))
)
)# plotlyProxyInvoke
my$data$f <- my$data$f + 1
my$xrange <- axrange(my$data$x)
data <- list(list(
frame = my$data$f
),
list(
frame = my$data$f
))
cat("animate axis\n")
plotlyProxyInvoke(proxy, "animate",
# frameOrGroupNameOrFrameList
list(
data = data,
traces = as.list(as.integer(0:1)),
layout = list(xaxis=list(range=my$xrange))
),
# animationAttributes
list(
frame=as.list(rep(list(duration=speed), length(0:1))),
transition=as.list(rep(list(duration=speed), length(0:1)))
)
)# plotlyProxyInvoke
}) # observeEvent
}
shinyApp(ui, server)