Skip to content

event_data() triggering unexpected warning about registering #1528

Closed

Description

@bklingen

Using event_data("plotly_hover", source="mysource") seems to trigger the following warning with the newest plotly version:
Warning: The 'plotly_hover' event tied a source ID of 'mysource' is not registered. In order to obtain this event data, please add event_register(p, 'plotly_hover') to the plot (p) that you wish to obtain event data from.

library(shiny)
library(plotly)

ui <- fluidPage(
        plotlyOutput("myplot"),
        verbatimTextOutput("hovered")
      )

server <- function(input, output, session) {
    
    output$myplot <- renderPlotly({
        p <- plot_ly(faithful, x=~eruptions, y=~waiting, source="mysource")
        return(p)
    })
    
    output$hovered <- renderPrint({
      event_data("plotly_hover", source="mysource")
    })

}

shinyApp(ui = ui, server = server)

Activity

  1. bklingen commented on May 10, 2019

    @bklingen
    Author

    The relevant entry from the plotly source code:

    # It's possible for event_data() to execute before any 
      # relevant input values have been registered (i.e, before 
      # relevant plotly graphs have been executed). Therefore, 
      # we delay checking that a relevant input value has been 
      # registered until shiny flushes
      session$onFlushed(
        function() {
          eventIDRegistered <- eventID %in% session$userData$plotlyShinyEventIDs
          if (!eventIDRegistered) {
            warning(
              "The '", event, "' event tied a source ID of '", source, "' ",
              "is not registered. In order to obtain this event data, ", 
              "please add `event_register(p, '", event, "')` to the plot (`p`) ",
              "that you wish to obtain event data from.",
              call. = FALSE
            )
          }
        }
      )```
    
  2. cpsievert commented on May 14, 2019

    @cpsievert
    Collaborator

    Huh, the warning seems to go away if you avoid return()

    library(shiny)
    library(plotly)
    
    ui <- fluidPage(
      plotlyOutput("myplot"),
      verbatimTextOutput("hovered")
    )
    
    server <- function(input, output, session) {
      
      output$myplot <- renderPlotly({
        plot_ly(faithful, x=~eruptions, y=~waiting, source="mysource")
      })
      
      output$hovered <- renderPrint({
        event_data("plotly_hover", source="mysource")
      })
      
    }
    
    shinyApp(ui = ui, server = server)
  3. baj12 commented on May 15, 2019

    @baj12

    How would you handle returning NULL?
    I need to stop plot when there is no data (or other criteria are not matched). Currently, I return(NULL),
    but I guess this is not optimal. I would rather see a message saying that data needs be loaded, but I still haven't figured out how to do this...
    And yes, I have the impression that without the return I see fewer warnings, but I still see some, most probably due to the return(NULL)...
    Thanks a lot.
    B

  4. dchen71 commented on May 17, 2019

    @dchen71

    Are there any docs on how to use event_register? I recently upgrade to the newest plotly r version and am getting event_register errors on all of my scatter plots. I have two different sources for two different plots.

    Edit: I figured it out but it would be helpful if there were additional documentation and examples outside of the webinar for this update.

  5. deleted a comment from on May 24, 2019
  6. added a commit that references this issue on May 24, 2019
    a782740
  7. cpsievert commented on May 24, 2019

    @cpsievert
    Collaborator

    How would you handle returning NULL?

    Avoid calling event_data() until the relevant output is non-NULL, like this #1538 (comment)

    If someone can some with an example where this is sufficiently hard, I might be willing to add an official way to suppress the warning in event_data()

    Are there any docs on how to use event_register?

    Sort of, see ?event_register. It's worth noting though that you shouldn't need to use event_register() unless you need an event that isn't registered by default...here's a hack to get at the default events:

    p <- plotly_build(plot_ly())
    p$x$shinyEvents
     [1] "plotly_hover"          
     [2] "plotly_click"          
     [3] "plotly_selected"       
     [4] "plotly_relayout"       
     [5] "plotly_brushed"        
     [6] "plotly_brushing"       
     [7] "plotly_clickannotation"
     [8] "plotly_doubleclick"    
     [9] "plotly_deselect"       
    [10] "plotly_afterplot" 
  8. added 2 commits that reference this issue on Aug 26, 2019
    720a839
    dd474e2
  9. added a commit that references this issue on Aug 30, 2019
    d416cea
  10. added a commit that references this issue on Mar 12, 2020
    32dde41
  11. CDorich commented on Sep 15, 2021

    @CDorich

    I am still running into this issue of Warning: The 'plotly_hover' event tied a source ID of 'mysource' is not registered. In order to obtain this event data, please add event_register(p, 'plotly_hover') to the plot (p) that you wish to obtain event data from.
    I've copied Carson's code from this post, and mixed it with my own editable plotly in a test shiny app and can get it to work. When I run it in a larger app I am getting the same warning but the observe() or event_data("plotly_relayout") does not seem to be working with this app. I can get the shape to move but no underlying data is changing. I am completely stuck about how to get an event_register() to work and why I am not seeing any observe occur with the edited plot.... any guidance on how to code in an event_register() or why I can't see any interaction on this plot?

  12. samssann commented on Nov 2, 2021

    @samssann

    You could give the warning a class so that these specific warnings could be turned off.

      session$onFlushed(
        function() {
          eventIDRegistered <- eventID %in% session$userData$plotlyShinyEventIDs
          if (!eventIDRegistered) {
            rlang::warn(
              paste0("The '", event, "' event tied a source ID of '", source, "' ",
              "is not registered. In order to obtain this event data, ", 
              "please add `event_register(p, '", event, "')` to the plot (`p`) ",
              "that you wish to obtain event data from."),
              class = "plotly_unregistered_event_warning"
            )
          }
        }
      )
    

    These warnings can be disabled in the shiny server code by wrapping this around the desired code

    suppressWarnings(..., classes = "plotly_unregistered_event_warning")
    
  13. sanjmeh commented on Dec 4, 2021

    @sanjmeh

    I started getting this warning as soon as I started using source argument in plot_ly(). Seems there is no clear cut solution to this as I see above. Is there any?

  14. davidseres commented on Apr 27, 2022

    @davidseres

    You could give the warning a class so that these specific warnings could be turned off.

      session$onFlushed(
        function() {
          eventIDRegistered <- eventID %in% session$userData$plotlyShinyEventIDs
          if (!eventIDRegistered) {
            rlang::warn(
              paste0("The '", event, "' event tied a source ID of '", source, "' ",
              "is not registered. In order to obtain this event data, ", 
              "please add `event_register(p, '", event, "')` to the plot (`p`) ",
              "that you wish to obtain event data from."),
              class = "plotly_unregistered_event_warning"
            )
          }
        }
      )
    

    These warnings can be disabled in the shiny server code by wrapping this around the desired code

    suppressWarnings(..., classes = "plotly_unregistered_event_warning")
    

    Where does eventID come from?

  15. added a commit that references this issue on Jun 26, 2022
    504c33f
  16. added a commit that references this issue on Jul 4, 2022
    55f49ee
  17. dvg-p4 commented on Jan 31, 2024

    @dvg-p4
    Contributor

    How would you handle returning NULL?

    Avoid calling event_data() until the relevant output is non-NULL, like this #1538 (comment)

    If someone can some with an example where this is sufficiently hard, I might be willing to add an official way to suppress the warning in event_data()

    Are there any docs on how to use event_register?

    Sort of, see ?event_register. It's worth noting though that you shouldn't need to use event_register() unless you need an event that isn't registered by default...here's a hack to get at the default events:

    @cpsievert I'm a bit confused, if the recommended way to avoid this warning is a req() above the call, why is the warning message itself talking about event_register()?

  18. dvg-p4 commented on Jan 31, 2024

    @dvg-p4
    Contributor

    Also, the req() method isn't working consistently for me in a larger app. IIUC when the renderPlotly() and the reactive holding event_data() are both depending on the same reactive, there's no guarantee as to which will be executed first when that reactive becomes available--so if the shiny reactive queue happens to execute the event_data first, we see the warning.

  19. asadow commented on Oct 16, 2024

    @asadow

    @dvg-p4

    Hmm, maybe this will help.

  20. trafficonese commented on Dec 3, 2024

    @trafficonese

    Addressing the Need to Suppress Warnings in event_data()

    Regarding this statement, @cpsievert:

    If someone can some with an example where this is sufficiently hard, I might be willing to add an official way to suppress the warning in event_data()

    Creating a minimal reproducible example from such applications is not only quite time-consuming but often fails to replicate the issue, as the warning tends to disappear in simpler scenarios while persisting in the more complex app. Additionally, the suggestion provided in the warning message itself does not address the root problem effectively.

    "In order to obtain this event data, please add event_register(p, 'plotly_click') to the plot (p) that you wish to obtain event data from."

    Even when the recommended event_register calls are added to the plot_ly() function, the warnings persist:

    output$plotlyplot <- renderPlotly({
      plot_ly(
        data = mtcars,
        x = ~mpg, y = ~carb,
        type = "scatter",
        mode = "markers"
      ) %>%
        event_register('plotly_hover') %>% 
        event_register('plotly_click') %>% 
        event_register('plotly_doubleclick')
    })
    

    Cluttered Logs

    In larger Shiny applications with multiple pages for example and several interactive Plotly plots on each page, these warnings can quickly accumulate, so that the Log files become cluttered with unnecessary warnings, obscuring genuinely important warnings that need attention. This makes debugging significantly harder. Another complication is that we can't simply use suppressWarnings() to handle this issue effectively. In one of my apps, I had to resort to a workaround like this:

    options(warn = -1)
    # Perform some calculations and then create a Plotly plot
    options(warn = 0)
    

    This is far from ideal and can suppress more warnings than intended.

    Debugging Becomes Impossible with options(warn = 2)

    Setting options(warn = 2) -which turns warnings into errors- causes the app to crash simply because interactive Plotly plots are used. This behavior blocks effective debugging.

    Example Shiny App

    To illustrate, consider a Shiny app where users dynamically generate multiple plots based on selected time ranges. For simplicity, I’ve adapted the scenario to use a numeric input, allowing users to specify between 1 and 5 plots. Each plot supports interactivity via hover, click, and double-click events.
    In such a case, the repetitive warnings for multiple plots add unnecessary noise to the logs (especially since everything seems to be working correctly!). While it might technically be possible to suppress these warnings correctly in this scenario, the process is neither obvious nor straightforward. This is evidenced by the number of related GitHub issues and StackOverflow questions, highlighting that many developers struggle with this same problem. The current behavior adds unnecessary complexity and frustration, making a proper solution or clear guidance essential.

    library(shiny)
    library(plotly)
    
    # Simulated dataset generator
    generate_data <- function(id) {
      data.frame(
        x = rnorm(50, mean = id * 5),
        y = rnorm(50, mean = id * 3),
        group = sample(letters[1:3], 50, replace = TRUE)
      )
    }
    
    # UI
    ui <- fluidPage(
      titlePanel("Dynamic Plotly Plots"),
      sidebarLayout(
        sidebarPanel(
          numericInput("num_plots", "Number of Plots:", value = 1, min = 1, max = 5),
          verbatimTextOutput("hover_info"),
          verbatimTextOutput("click_info"),
          verbatimTextOutput("dblclick_info")
        ),
        mainPanel(
          uiOutput("plots_ui") # Placeholder for dynamically generated plots
        )
      )
    )
    
    # Server
    server <- function(input, output, session) {
      plot_data <- reactive({
        lapply(1:input$num_plots, generate_data)
      })
      
      # Dynamically generate UI for plots
      output$plots_ui <- renderUI({
        num <- input$num_plots
        plot_output_list <- lapply(1:num, function(i) {
          plotlyOutput(outputId = paste0("plot_", i), height = "300px")
        })
        do.call(tagList, plot_output_list)
      })
      
      # Render dynamic plots
      observe({
        lapply(1:input$num_plots, function(i) {
          local({
            id <- i
            output[[paste0("plot_", id)]] <- renderPlotly({
              plot_ly(
                data = plot_data()[[id]],
                x = ~x, y = ~y,
                type = "scatter",
                mode = "markers",
                color = ~group,
                source = paste0("plot_source_", id),
                text = ~paste("Point ID:", 1:nrow(plot_data()[[id]]))
              ) %>%
                layout(title = paste("Dynamic Plot", id))
            })
          })
        })
      })
      
      # Observe Events (Click, Dbclick, Hover) for all plots
      observe({
        lapply(1:input$num_plots, function(i) {
          local({
            id <- i
            # observeEvent(event_data("plotly_hover", source = paste0("plot_source_", id)), {
            observe({
              req(plot_data())
              hover <- event_data("plotly_hover", source = paste0("plot_source_", id))
              if (!is.null(hover)) {
                output$hover_info <- renderText({
                  paste("Hover on Plot", id, ":\nX =", hover$x, "\nY =", hover$y)
                })
              }
            })
            # observeEvent(event_data("plotly_click", source = paste0("plot_source_", id)), {
            observe({
              req(plot_data())
              click <- event_data("plotly_click", source = paste0("plot_source_", id))
              if (!is.null(click)) {
                output$click_info <- renderText({
                  paste("Click on Plot", id, ":\nX =", click$x, "\nY =", click$y)
                })
              }
            })
            observe({
              req(plot_data())
              click <- event_data("plotly_doubleclick", source = paste0("plot_source_", id))
              if (!is.null(click)) {
                output$dblclick_info <- renderText({
                  paste("DBL-Click on Plot", id, ":\nX =", click$x, "\nY =", click$y)
                })
              }
            })
          })
        })
      })
    }
    
    # Run the app
    shinyApp(ui = ui, server = server)
    
  21. wmay commented on Mar 18, 2025

    @wmay

    @cpsievert, I have an example where this is sufficiently hard-- seemingly impossible for all practical purposes.

    I have an app where the plot height is set dynamically. This leads to a catch-22 situation where it is impossible to get the correct behavior without needless warnings that can't be suppressed.

    Here's a simplified version:

    # dynamic plot height with click event
    library(shiny)
    library(plotly)
    
    ui = fluidPage(
        titlePanel('event_data bug report'),
        radioButtons('height', 'Plot height',
                     c('Short' = '200', 'Tall' = '400'), '200'),
        h3('Last click update'),
        verbatimTextOutput('clickInfo'),
        uiOutput('dynamicTimeSeries')
    )
    
    server = function(input, output) {
      time_series_output = renderPlotly({
        y = if (input$height == '200') 1:5 else seq(1, 9, 2)
        plot_ly(x = 1:5, y = y, type = 'scatter', mode = 'lines',
                source = 'example') %>%
          event_register('plotly_click')
      })
      output$timeSeries = reactive(time_series_output())
      output$dynamicTimeSeries = renderUI({
        plotlyOutput('timeSeries', height = as.numeric(input$height))
      })
      output$clickInfo = renderPrint({
        req(time_series_output())
        print(Sys.time())
        event_data('plotly_click', 'example')
      })
    }
    
    shinyApp(ui = ui, server = server)

    In general, using event_data with a dynamic plot has been a huge pain.

    First, whatever you're trying to do with session$onFlushed when emitting the warning doesn't seem to work with a dynamic plot. I get false positive warnings.

    To fix that, when responding to clicks, I need to call req to make sure the plot exists. I had to create a layer of indirection with a new variable, time_series_output, so that I have something to call req on.

    Here's the catch-22: when I add this req statement before checking the click event, it adds a reactive dependency to the plot. That means every time the plot is updated, this code runs again. So now I can't update the plot without the click event running. When you run this example app, it shows that the click event is run every time the plot height is changed. Not only is it run again, but there's no way to distinguish real clicks from plot updates.

    So I can either remove the false warnings, or I can have an app that responds correctly to click events, but I can't do both.

    I propose a rule of thumb: if the warning is not suppressible, there should be an option to remove it. There's too much weird stuff happening within Shiny for you to guarantee users that it'll only warn at the correct times, and the hoops you want us to jump through are a lot more burdensome than simply turning off the warning.

    Edit: Ok, I actually did find a workaround. It requires manually removing the event from the session object after event_data is called.

    # remove the click event
    eventID = paste('plotly_click', 'example', sep = "-")
    session = shiny::getDefaultReactiveDomain()
    session$userData$plotlyInputStore[[eventID]] = NULL
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions