5

Everytime a plotly object is created by R in shiny, (or just in R), the widget is recreated completely. For small data sets this is not a problem, but i'm working with plots that contain thousands of scatter points, making it take 10-20 seconds to recreate a plot in my shinyapp.

I'm looking for a way to update the data through a javascript solution that doesn't trigger the widget to be rebuild, but simply replaces it's data.

Here is a dummy app with 2 small data sets between which the app can switch. In the dummy app it does it by recreating the widget. Quite fast here due to the limited datapoints, but not ideal for massive data sets.

If anyone knows how to accomplish this, it would be a major improvement for my app.

TO CLARIFY: An answer like this one here: enter link description here won't do the trick for me. The point is, in my app data is changed many times AFTER the plot has been build so I can't pre-load a list of data frames.

I have the feeling the solution would have to be a javascript solution that can grab the data to overwrite the currently plotted data, but not sure how or whether this can be done.

library("shiny")
library("plotly")

ui <- fluidPage(
  selectInput("dataset", "Choose a dataset:", choices = c("rock", "mtcars")),

  plotlyOutput("Plot1")
)


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

  dataSource <- reactive({switch(input$dataset,"rock" = rock,"mtcars" = mtcars)})

  output$Plot1 <-  renderPlotly({plot_ly(data = dataSource(), x = dataSource()[,1], 
                                         y =dataSource()[,2], mode = 'markers', type = 'scatter')})
}

shinyApp(ui, server)
Mark
  • 2,789
  • 1
  • 26
  • 66

1 Answers1

5

Take a look at these resources that might be useful to your case:

  1. Plotly R book by Carson Sievert chapters 3, 4 & 6
  2. Plotly proxy function explanation

This is the code to get you started. You have a bit of work to adjust the axis labels but this should not be that difficult.

Hope this helps!

The code:

    library("shiny")
    library("plotly")

    ui <- fluidPage(
            selectInput("dataset", "Choose a dataset:", choices = c("rock", "mtcars")),

            plotlyOutput("Plot1")
    )


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

            dataSource <- reactive({switch(input$dataset,"rock" = rock,"mtcars" = mtcars)})

            output$Plot1 <-  renderPlotly({plot_ly(data = rock, x = ~area, 
                                                   y =~peri, mode = 'markers', type = 'scatter')})

            observeEvent(input$dataset, {
                    f <- list(
                            family = "Courier New, monospace",
                            size = 18,
                            color = "#7f7f7f"
                    )
                    x <- list(
                            title = "x Axis",
                            titlefont = f, 
                            range = c(0, 1000)
                    )
                    y <- list(
                            title = "y Axis",
                            titlefont = f,
                            range = c(0, 100)
                    )
                    plotlyProxy("Plot1", session) %>%
                            plotlyProxyInvoke("addTraces", list(x = dataSource()[,1], 
                                                                y = dataSource()[,2],
                                                                type = 'scatter',
                                                                mode = 'markers')) %>% 
                            plotlyProxyInvoke("deleteTraces", list(as.integer(0))) %>% 
                            plotlyProxyInvoke("relayout", list(xaxis = x, yaxis = y))
            })



    }

    shinyApp(ui, server)
Valter Beaković
  • 3,140
  • 2
  • 20
  • 30
  • Hey Valter, that looks very promissing. I'll play around with it to get move familiar with it and adjust it so that it works in my app. Quick follow up question, how do I remove all existing traces if there are several (My model creates 'n' groups on each run, which determines the traces and I need to clear all of them ) – Mark May 14 '18 at 10:07
  • Ok figured out how to do it, but not how to add a trace per factor. Will post a new SO question on it – Mark May 14 '18 at 11:01
  • Thanks a lot for the help Valter! It can be found here: https://stackoverflow.com/questions/50329111/use-plotlyproxy-to-add-multiple-traces-when-data-changes – Mark May 14 '18 at 11:24
  • 1
    Funny fact, I just tested with two datasets of 5000*100 size dfs, and I don't see any difference between rebuild widget and proxyinvoke. Both very fast (1 sec render time). Also when I put this in my main app, both work fast, until I load the other data my app works on, and then suddenly all plotly actions are slow again (10sec to render). Starting to think it's overall memory capacity – Mark May 14 '18 at 13:53
  • I have managed to add more traces, take a look at the answer of your new question... – Valter Beaković May 14 '18 at 18:37