rshinyplotlyr-plotly

Errors with plotly_click in R Plotly version 4.9.0. Is there a bug in the new version?


Update 3: new test app with dropdownbutton issue

library(shiny)
library(shinydashboard)
library(plotly)
library(shinyWidgets)

rm(list = ls(), envir = environment()) ## to prevent cross over from old runs

testData = data.frame(day = sample(seq(as.Date('1999/01/01'), as.Date('2000/01/01'), by="day"), 24), frequency = sample(1:5, 24, replace = T ), datecoloring = sample(1:2, 24, replace = T ))
testData$dayPOSIXct <- as.POSIXct(testData$day)

dateRangeMin <- min(testData$day)
dateRangeMax <- max(testData$day)




  ui <- dashboardPage(
    dashboardHeader(),
    dashboardSidebar( 
      menuItem("Testpage", tabName = "Testpage", icon = icon("home"))
                      ),
    dashboardBody( 
      tabItems(
        # 1) Test Tab ---------------------------------------------------------------

        tabItem(tabName = "Testpage",
            actionButton(inputId = 'Load', label = 'Data'),
            dropdownButton(inputId= "TestButton", label = NULL,
              plotlyOutput('testplot', width = 700, height = 500),
              icon = icon("list-alt"), 
              tooltip = tooltipOptions(title = "Click to open and render the plot"), width = "1670px")

        )
      )
      ),
    title = "Dashboard example"
  )


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

  values <- reactiveValues()

  observeEvent(input$Load, { 
    values$testData <- testData
  })

  output$testplot <- renderPlotly({
    req(values$testData)
    p <-  plot_ly(data = values$testData, source = 'testplot',
                  color  = as.factor(values$testData$datecoloring), colors = c('#339fff', '#eaf5ff'),
                  opacity= 0.5, showlegend = T,
                  marker = list(line = list(width = 2, color = '#0000ff')),
                  hoverinfo = "text",
                  text = ~paste('Files:', values$testData$frequency, '<br>Date:', format(values$testData$day, format = '%Y-%m-%d'), sep = ' '))%>%
      add_bars( x = ~dayPOSIXct, y =  ~frequency,   type = "bar", width = 36000000
      )

    p
  })

  relayout_data <- reactive({
    req(values$testData)
    event_data("plotly_relayout", source = "testplot")
  })

  observeEvent(relayout_data(),{
    print(relayout_data())
  })  
}
shinyApp(ui, server)

UPDATE 2: the issue can indeed be circumvented with approaches that properly use req() with or without separating the observing of the event_data from the code that does something with the event_data. such as:

relayout_data <- reactive({
req(values$testData)
event_data("plotly_relayout", source = "testplot")


 })

  observeEvent(relayout_data(),{
    print(relayout_data())
  })

However, this seems not to provide a solution for situations where the plot is inside i.e. a dropdownbutton panel or other tab/page of a shiny App. After the needed data for the plot is loaded, req() is met and the code will fire, yet the plot is still not rendered as it is not in the current screen.

UPDATE: the issue is also reported on github, no real solution yet https://github.com/ropensci/plotly/issues/1528

Original question / post:

Today I updated all my packages in R and suddenly I got a long list of errors coming from the new plotly version 4.9.0 in R with my R shiny App.

all these errors refer to plotly_relayout, plotly_click etc.

Warning: The 'plotly_relayout' event tied a source ID of 'DateRangeHisto' is not registered. In order to obtain this event data, please add event_register(p, 'plotly_relayout') to the plot (p) that you wish to obtain event data from.

I tried to add the event_register in various ways, but no effect. I suppose there is a bug in the new version?

Here is a nonsense dummy app that produces the bug with plotly 4.9.0 and all packages updated.

UPDATE: the error seems to happen when data is not available for the plot despite the req() inside the plot_ly block, the event_data causes an error. This did not happen with the previous versions of plotly..... so, how to get rid of this is now the question

    library(shiny)
    library(plotly)



rm(list = ls(), envir = environment()) ## to prevent cross over from old runs

testData = data.frame(day = sample(seq(as.Date('1999/01/01'), as.Date('2000/01/01'), by="day"), 24), frequency = sample(1:5, 24, replace = T ), datecoloring = sample(1:2, 24, replace = T ))
testData$dayPOSIXct <- as.POSIXct(testData$day)

dateRangeMin <- min(testData$day)
dateRangeMax <- max(testData$day)
if(!require('shiny')){ install.packages('shiny', dependencies=TRUE)}
if(!require('shinyWidgets')){ install.packages('shinyWidgets', dependencies=TRUE)}
if(!require('plotly')){ install.packages('plotly', dependencies=TRUE)}
if(!require('htmlwidgets')){ install.packages('htmlwidgets')}


ui <- fluidPage(
  actionButton(inputId = 'Load', label = 'Data'),
  plotlyOutput('testplot', width = 700, height = 500)

)


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

  values <- reactiveValues()

  observeEvent(input$Load, { 
    values$testData <- testData
    })

  output$testplot <- renderPlotly({ 
    req(values$testData)
    p <-  plot_ly(data = values$testData, source = 'testplot',
                  color  = as.factor(values$testData$datecoloring), colors = c('#339fff', '#eaf5ff'),
                  opacity= 0.5, showlegend = T,
                  marker = list(line = list(width = 2, color = '#0000ff')),
                  hoverinfo = "text",
                  text = ~paste('Files:', values$testData$frequency, '<br>Date:', format(values$testData$day, format = '%Y-%m-%d'), sep = ' '))%>%
      add_bars( x = ~dayPOSIXct, y =  ~frequency,   type = "bar", width = 36000000
      )
    p
  })

  observeEvent(event_data("plotly_relayout", source = "testplot"),{
    #any code here, doesn't matter, bug happens already
  })


}

shinyApp(ui, server)

Session info

sessionInfo()
R version 3.5.3 (2019-03-11)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 7 x64 (build 7601) Service Pack 1

Matrix products: default

locale:
[1] LC_COLLATE=Dutch_Netherlands.1252  LC_CTYPE=Dutch_Netherlands.1252    LC_MONETARY=Dutch_Netherlands.1252 LC_NUMERIC=C                       LC_TIME=Dutch_Netherlands.1252    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] plotly_4.9.0  ggplot2_3.1.1 shiny_1.3.2  

loaded via a namespace (and not attached):
 [1] Rcpp_1.0.1         pillar_1.4.0       compiler_3.5.3     later_0.8.0        colourpicker_1.0.3 plyr_1.8.4         shinyjs_1.0        tools_3.5.3        digest_0.6.19      viridisLite_0.3.0 
[11] jsonlite_1.6       tibble_2.1.1       gtable_0.3.0       pkgconfig_2.0.2    rlang_0.3.4        rstudioapi_0.10    crosstalk_1.0.0    yaml_2.2.0         httr_1.4.0         withr_2.1.2       
[21] dplyr_0.8.1        htmlwidgets_1.3    grid_3.5.3         DT_0.6             tidyselect_0.2.5   glue_1.3.1         data.table_1.12.2  R6_2.4.0           tidyr_0.8.3        purrr_0.3.2       
[31] magrittr_1.5       scales_1.0.0       promises_1.0.1     htmltools_0.3.6    assertthat_0.2.1   mime_0.6           xtable_1.8-4       colorspace_1.4-1   httpuv_1.5.1       miniUI_0.1.1.1    
[41] lazyeval_0.2.2     munsell_0.5.0      crayon_1.3.4    

Solution

  • The problem is that the observeEvent is trying to access the event_data before the plot is rendered. You can work around this behaviour by using req() also for your event_data(). Plotly 4.9.0 indeed seems to be more strict about this.

    library(shiny)
    library(shinydashboard)
    library(plotly)
    library(shinyWidgets)
    
    rm(list = ls(), envir = environment()) ## to prevent cross over from old runs
    
    testData = data.frame(day = sample(seq(as.Date('1999/01/01'), as.Date('2000/01/01'), by="day"), 24), frequency = sample(1:5, 24, replace = T ), datecoloring = sample(1:2, 24, replace = T ))
    testData$dayPOSIXct <- as.POSIXct(testData$day)
    
    dateRangeMin <- min(testData$day)
    dateRangeMax <- max(testData$day)
    
    ui <- dashboardPage(
      dashboardHeader(),
      dashboardSidebar(
        sidebarMenu(
          menuItem("Testpage", tabName = "Testpage", icon = icon("home"))
        )
      ),
      dashboardBody( 
        tabItems(
          # 1) Test Tab ---------------------------------------------------------------
    
          tabItem(tabName = "Testpage",
                  actionButton(inputId = 'Load', label = 'Data'),
                  dropdownButton(inputId = "TestButton", label = NULL,
                                 plotlyOutput('testplot', width = 700, height = 500),
                                 icon = icon("list-alt"), 
                                 tooltip = tooltipOptions(title = "Click to open and render the plot"), width = "1670px")
    
          )
        )
      ),
      title = "Dashboard example"
    )
    
    
    server <- function(input, output, session) {
    
      # output$testplot <- renderPlotly({plot_ly(data.frame(NULL), source = 'testplot')})
    
      values <- reactiveValues()
    
      observeEvent(input$Load, {
        values$testData <- testData
      })
    
      output$testplot <- renderPlotly({
        req(values$testData)
        p <-  plot_ly(data = values$testData, source = 'testplot',
                      color  = as.factor(values$testData$datecoloring), colors = c('#339fff', '#eaf5ff'),
                      opacity= 0.5, showlegend = T,
                      marker = list(line = list(width = 2, color = '#0000ff')),
                      hoverinfo = "text",
                      text = ~paste('Files:', values$testData$frequency, '<br>Date:', format(values$testData$day, format = '%Y-%m-%d'), sep = ' '))%>%
          add_bars( x = ~dayPOSIXct, y =  ~frequency,   type = "bar", width = 36000000)
        p 
      })
    
      relayout_data <- reactive({
        req(values$testData)
        req(input$TestButton_state)
        event_data("plotly_relayout", source = "testplot")
      })
    
      observeEvent(relayout_data(),{
        print(relayout_data())
      })  
    }
    shinyApp(ui, server)