Plot is redrawn despite using plotlyProxy

My application contains a surface plot made with R plotly and the user can use a sliderInput to specify a level where a contour line (actually a 3D scatterplot) is dynamically drawn. So, when the user clicks on the app's button, the current contour line is deleted and a new one is generated and placed on the plot. My issue; however, is that the use of plotlyProxy and plotlyProxyInvoke do not matter - the surface plot is redrawn and the angle of view is reset, which is exactly what I am trying to avoid. Here is my minimal reproducible code:

library(shiny)
library(plotly)
library(isoband)

ui <- fluidPage(
  
  h1("My simple app"),
  
  sliderInput(
    inputId = "slider", label = "Select contour level", value = 1, min = 1, max = 40),
  
  actionButton(inputId = "btn", "OK"),
  
  plotlyOutput(outputId = "plot")
  
)

server <- function(input, output, session){
  
  rv <- reactiveValues()
  
  x <- y <- 0:100
  z <- outer(X = x, Y = y, function(x, y) x^0.2 * y^0.6)
  
  observeEvent(input$btn, ignoreInit = TRUE, {
    
    rv$iso <- isolines(x = x, y = y, z = z, levels = isolate({input$slider}))
    
    plotlyProxy("plot", session) %>%
      plotlyProxyInvoke(method = "deleteTraces", list(1)) %>% 
      plotlyProxyInvoke(
        method = "addTraces",
        list(
          type = "scatter3d",
          x = rv$iso[[1]]$x,
          y = rv$iso[[1]]$y,
          z = isolate({input$slider})
        )
      )

  })

  
  output$plot <- renderPlotly({
    
    rv$iso <- isolines(x = x, y = y, z = z, levels = isolate({input$slider}))
    
    plot_ly(
      type = "surface",
      x = x,
      y = y,
      z = z
    ) %>%
      add_trace(
        type = "scatter3d",
        x = rv$iso[[1]]$x,
        y = rv$iso[[1]]$y,
        z = isolate({input$slider})
      )
    
  })

This is not trivial, I found there was a lack of clear examples and I struggled with this... but ultimately I think I have a working example, and I learned some new things that could help me in my own work. :slight_smile:

library(shiny)
library(plotly)
library(isoband)

ui <- fluidPage(
  h1("My simple app"),
  sliderInput(
    inputId = "slider",
    label = "Select contour level",
    value = 1,
    min = 1,
    max = 40
  ),
  actionButton(inputId = "btn", "OK"),
  plotlyOutput(outputId = "plot")
)

server <- function(input, output, session) {
  x <- y <- 0:100
  z <- outer(X = x, Y = y, function(x, y) x^0.2 * y^0.6)
  # precompute iso levels
  iso <- isolines(x = x, y = y, z = z, levels = 1:40)


  observeEvent(input$btn,
    ignoreInit = TRUE,
    {
      lvl <- input$slider
      mytrace <- list(
        type = "scatter3d",
        mode = "markers",
        x = iso[[lvl]]$x,
        y = iso[[lvl]]$y,
        z = rep(lvl, length(iso[[lvl]]$id))
      )
      p1 <- plotlyProxy("plot", session)

      plotlyProxyInvoke(p1,
        method = "deleteTraces",
        list(-1)
      )
      plotlyProxyInvoke(p1,
        method = "addTraces",
        list(mytrace)
      )
    }
  )


  output$plot <- renderPlotly({
    isolate({
      lvl <- input$slider
      plot_ly(
        type = "surface",
        x = x,
        y = y,
        z = z
      ) %>%
        add_trace(
          type = "scatter3d",
          mode = "markers",
          x = iso[[lvl]]$x,
          y = iso[[lvl]]$y,
          z = lvl
        )
    })
  })
}
shinyApp(ui, server)
1 Like

Thank you so much @nirgrahamuk. I am not sure how you found it. I spent so much time looking into it and, as you said, examples in R are not many :frowning:

Actually, I made ONE single mistake! I connected my 2 calls to plotlyProxyInvoke() with a pipe operator %>%. My code works perfectly when I remove it. Thank you so much for pointing me in the right direction @nirgrahamuk!!!!

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.