plotly.R icon indicating copy to clipboard operation
plotly.R copied to clipboard

All `event_data()` reactives needlessly fire whenever a new one is registered

Open dvg-p4 opened this issue 1 year ago • 0 comments

This appears to be due to this line, which (I presume unintentionally) creates a reactive dependency on the names of this reactiveValues list (not just the specific relevant value):

https://github.com/plotly/plotly.R/blob/16261c3318100db899d79af843cc3d64ac32e8aa/R/shiny.R#L196

I believe this is a mainly an issue if you try to avoid the infamous "event tied a source ID" warning by preventing various event_data() calls from running until after their respective plots have (probably) rendered, as recommended.

Reprex

library(shiny)
library(plotly)
options(shiny.reactlog = TRUE)

ui <- fluidPage(
  fluidRow(
    column(4, checkboxInput("faithful_on", "Render `faithful` plot")),
    column(4, checkboxInput("iris_on", "Render `iris` plot")),
    column(4, checkboxInput("cars_on", "Render `cars` plot")),
  ),
  fluidRow(
    column(4, plotlyOutput("faithful_plot")),
    column(4, plotlyOutput("iris_plot")),
    column(4, plotlyOutput("cars_plot")),
  ),
  fluidRow(
    column(4, verbatimTextOutput("faithful_click")),
    column(4, verbatimTextOutput("iris_click")),
    column(4, verbatimTextOutput("cars_click")),
  )
)

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

  output$faithful_plot <- renderPlotly({
    req(input$faithful_on)
    plot_ly(faithful, x=~eruptions, y=~waiting, type = "scatter", mode = "markers", source="faithful")
  })

  output$faithful_click <- renderPrint({
    req(input$faithful_on)
    list(
      updated_at = Sys.time(),
      data = event_data("plotly_click", source="faithful")
    )
  })

  output$iris_plot <- renderPlotly({
    req(input$iris_on)
    plot_ly(iris, x = ~Sepal.Length, y = ~Petal.Length, type = "scatter", mode = "markers", source = "iris")
  })

  output$iris_click <- renderPrint({
    req(input$iris_on)
    list(
      updated_at = Sys.time(),
      data = event_data("plotly_click", source="iris")
    )
  })

  output$cars_plot <- renderPlotly({
    req(input$cars_on)
    plot_ly(cars, x = ~speed, y = ~dist, type = "scatter", mode = "markers", source = "cars")
  })

  output$cars_click <- renderPrint({
    req(input$cars_on)
    list(
      updated_at = Sys.time(),
      data = event_data("plotly_click", source="cars")
    )
  })
}

shinyApp(ui = ui, server = server)

Click on one of the checkboxes to enable a plot and its respective event_data(). Then click on a second. Note the "time updated" on the second plot's output dump as you enable the third plot--it will change, as names(session$userData$plotlyInputStore) triggers a spurious update. (If you refresh and click on a point on the first plot before enabling the second, the first one will spuriously update as well). We can see this dependency in the reactlog:

image image

dvg-p4 avatar Feb 01 '24 18:02 dvg-p4