1

I want an R-shiny-plotly plot to smoothly transition when the data changes. I don't want the action button approach provided by R-plotly. So I am trying to get animations as per the linked example via plotlyProxyInvoke("animate", ...):

https://plot.ly/javascript/plotlyjs-function-reference/#plotlyanimate

My app runs but the plot does not animate. I'm missing something.

library(shiny)
library(plotly)
library(dplyr)

ui <- fluidPage(
    actionButton("go", "Click to recalc"),
    plotlyOutput("plot")
)

gendata <- function(){
    ndata <- 10
    tibble(text=LETTERS[1:ndata], f=1, x=runif(ndata)) %>% mutate(r = rank(x))
}

server <- function(input, output, session){

    origdata <- gendata()
    if (FALSE){ # for offline testing
        print(head(origdata))
        my <- list(olddata = origdata, newdata = origdata)
    }

    my <- reactiveValues(
        olddata = origdata,
        newdata = origdata
        )

    output$plot <- renderPlotly({
        cat("renderPlotly\n")
        plot_ly() %>%
            add_trace(x=origdata$x, y=origdata$r, frame=origdata$f, width=0.8, type="bar", orientation="h", name="Rank") %>%
            add_trace(x=origdata$x + 0.02, y=origdata$r, frame=origdata$f, text=origdata$text, type="scatter", mode="text", showlegend=FALSE)
    })

    observeEvent(input$go, {
        req(my$newdata)
        cat("observeEvent input$go\n")
        my$olddata <- my$newdata # save old data
        my$newdata <- gendata() %>% # generate new data
            mutate(f=my$olddata$f+1)
        print(head(my$newdata))
        # https://plot.ly/javascript/plotlyjs-function-reference/#plotlyanimate
        plotlyProxy("plot", session=session, deferUntilFlush=FALSE) %>%
            plotlyProxyInvoke("animate",
                              # frameOrGroupNameOrFrameList
                              list(
                                list(
                                    traces = list(as.integer(0)),
                                    data = list(
                                        x = my$newdata$x,
                                        y = my$newdata$r,
                                        frame = my$newdata$f
                                    )
                                ),
                                list(
                                    traces = list(as.integer(1)),
                                    data = list(
                                        x = my$newdata$x + 0.02,
                                        y = my$newdata$r,
                                        text = my$newdata$text,
                                        frame = my$newdata$f
                                    )
                                )
                              ),
                              # animationAttributes
                              list(
                                transition = list(duration = 500, easing="linear"),
                                frame = list(duration = 500)
                              )
                              )# plotlyProxyInvoke
    })

}

shinyApp(ui, server)


1 Answer 1

3

It turns out I only had to modify the list structure. Also bar traces can't currently be animated in plotly, so I had to fake it using fat lines.

library(shiny)
library(plotly)
library(dplyr)

ui <- fluidPage(
    actionButton("go", "Click to recalc"),
    plotlyOutput("plot")
)

gendata <- function(){
    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()
    if (FALSE){ # for offline testing
        print(head(origdata))
        my <- list(olddata = origdata, newdata = origdata)
    }

    my <- reactiveValues(
        olddata = origdata,
        newdata = origdata
        )

    output$plot <- renderPlotly({
        cat("renderPlotly\n")
        plot_ly() %>%
            add_trace(x=origdata$x, y=origdata$r, frame=origdata$f, line=list(width=20, simplify=FALSE), type="scatter", opacity=0.5, mode="lines", name="Rank") %>%
            add_trace(x=origdata$x + 0.02, y=origdata$r, frame=origdata$f, text=origdata$text, type="scatter", mode="text", showlegend=FALSE) %>%
            layout(xaxis=list(range=list(0,1.1))) %>%
            animation_opts(frame=500, transition=500, redraw=FALSE)
    })

    observeEvent(input$go, {
        req(my$newdata)
        cat("observeEvent input$go\n")
        my$olddata <- my$newdata # save old data
        my$newdata <- gendata() %>% # generate new data
            mutate(f=my$olddata$f+1)
        print(head(my$newdata))
        # https://plot.ly/javascript/plotlyjs-function-reference/#plotlyanimate
        plotlyProxy("plot", session=session, deferUntilFlush=FALSE) %>%
            plotlyProxyInvoke("animate",
                              # frameOrGroupNameOrFrameList
                              list(
                                data = list(list(
                                                x = my$newdata$x,
                                                y = my$newdata$r,
                                                frame = my$newdata$f
                                            ),
                                            list(
                                                x = my$newdata$x + 0.02,
                                                y = my$newdata$r,
                                                text = my$newdata$text,
                                                frame = my$newdata$f
                                         )),
                                traces = list(as.integer(0), as.integer(1)),
                                layout = list()
                              ),
                              # animationAttributes
                              list()
                              )# plotlyProxyInvoke
    })

}

shinyApp(ui, server)
Sign up to request clarification or add additional context in comments.

2 Comments

This is very interesting to me. How can I learn about the structure of the frameOrGroupNameOrFrameList argument? It seems like a complicated nested list.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.