rshinyplotly

How can I synchronize selected points shown to user and selected points shown to server in a plotly plot in a shiny app?


I have an app where highlighting points in a plotly plots changes the behaviour in another plot. However, you can also change the plotly plot by changing the some selectInputs.

Now it is inconvenient that after the plotly plot is updated, the selection in it is not visible to the user anymore in the plot, however R still thinks the formally selected points are still selected. What can I do so that the user and the server (meaning the plotlyplot and R) always have the same information about the selected points?

Please see my minimal example:

library(shiny)
library(ggplot2)
library(plotly)

ui <- fluidPage(
  plotlyOutput("po"),
  selectInput("x", "x axis", names(iris)[1:4]),
  selectInput("y", "y axis", names(iris)[1:4]),
  verbatimTextOutput("vo")
)

server <- function(input, output, session) {
  output$po <- renderPlotly({
    p <- ggplot(iris) + geom_point(aes(.data[[input$x]], .data[[input$y]], color=Species))
    p <- ggplotly(p, source = "iris")
    p <- layout(p, dragmode = "lasso")
    p
  })
  output$vo <- renderPrint({
    event_data("plotly_selected", source = "iris")
  })
}

shinyApp(ui, server)

When you select points with the lasso, the renderPrint shows what you have selected. When you change the coordinates, the renderPrint stays the same, but the plot does not have any selection.

What is the easiest way to correct that? Both obvious solution are OK:

I personally think this behaviour should be regarded as a bug, although I might miss something.

And I have one bonus question: I do not really understand how to reset the selection: To me it seems I have to click about 10 times very fast (so normally a double click is not enough) and then sometimes it works. Do other people also experience that?


Solution

  • You can use shinyjs to reset. Try this

    library(shiny)
    library(ggplot2)
    library(plotly)
    library(shinyjs)
    
    ui <- fluidPage(
      useShinyjs(),
      actionButton("reset", "Reset"),
      plotlyOutput("po"),
      selectInput("x", "x axis", names(iris)[1:4]),
      selectInput("y", "y axis", names(iris)[1:4]),
      verbatimTextOutput("vo")
    )
    
    server <- function(input, output, session) {
      
      myplot <- eventReactive(c(input$reset,input$x,input$y), {
        p <- ggplot(iris) + geom_point(aes(.data[[input$x]], .data[[input$y]], color=Species))
        p <- ggplotly(p, source = "iris")
        p <- layout(p, dragmode = "lasso")
        p
      })
      
      output$po <- renderPlotly({ myplot()
        # p <- ggplot(iris) + geom_point(aes(.data[[input$x]], .data[[input$y]], color=Species))
        # p <- ggplotly(p, source = "iris")
        # p <- layout(p, dragmode = "lasso")
        # p
      })
      
      observeEvent(input[["reset"]], {
        runjs("Shiny.setInputValue('plotly_selected-iris', null);")
      })
      
      output$vo <- renderPrint({
        event_data("plotly_selected", source = "iris")
      })
    }
    
    shinyApp(ui, server)