Search code examples
shinyr-plotlysunburst-diagram

How to get event_data for clicked slices in R plotly's sunburst plot


When using plotly R package to create a sunburst pie chart in Shiny app, the user can click on the plot to zoom in/out dynamically. We would want to be able to download some data for current selected/centered piece.

However we cannot find this information from all the possible eventdata options. There are hover events but that's not enough, as user can click a piece then mouse move around to hover on other pieces without clicking it.

There is no clicking event with zoom in/out. And there is no relayout event. I think there must be some js event fired with zoom in/out, but that is not captured with existing eventdata function.

Update: It seemed there is selectedPath property for js chart, however I don't know how to access this data in Shiny.

Update2: Thanks for the answer which solved the problem. Also it turned out to be a missing feature in plotly R package, and it has been addd in most recent commit.


Solution

  • Currently plotly_click only provides data for the root and the leafs of a sunburst plot. However you can pass the plotly_hover event_data to a reactiveVal once the plot was clicked.

    As you haven't provided any example please see the following - using onclick() from library(shinyjs) for the workaround.

    library(plotly)
    library(shinyjs)
    
    DF <- structure(list(labels = c("total", "A", "C", "B", "F", "E", "F", 
                                    "E", "D", "E", "D", "D", "F", "G", "H", "H", "G", "H", "G", "H", 
                                    "H", "G", "I", "G", "I", "H", "G", "I", "I", "G", "G", "I", "H", 
                                    "H", "I", "I", "I", "H", "I", "G"),
                         values = c(100L, 36L, 29L,
                                    35L, 12L, 14L, 10L, 14L, 8L, 18L, 5L, 10L, 9L, 6L, 5L, 4L, 3L,
                                    7L, 4L, 2L, 6L, 3L, 8L, 3L, 2L, 4L, 4L, 4L, 4L, 4L, 3L, 2L, 5L, 
                                    5L, 2L, 2L, 1L, 1L, 1L, 5L),
                         parents = c(NA, "total", "total", "total", "total - A", "total - C", "total - C", "total - A",
                                     "total - B", "total - B", "total - C", "total - A", "total - B",
                                     "total - A - F", "total - C - E", "total - C - F", "total - A - E",
                                     "total - A - E", "total - B - D", "total - B - D", "total - B - E",
                                     "total - C - D", "total - B - E", "total - A - D", "total - B - D",
                                     "total - B - F", "total - C - F", "total - A - E", "total - C - E",
                                     "total - B - E", "total - B - F", "total - A - D", "total - A - D",
                                     "total - A - F", "total - B - F", "total - C - F", "total - C - D",
                                     "total - C - D", "total - A - F", "total - C - E"),
                         ids = c(
                           "total", "total - A", "total - C", "total - B", "total - A - F", "total - C - E", 
                           "total - C - F", "total - A - E", "total - B - D", "total - B - E", "total - C - D",
                           "total - A - D", "total - B - F", "total - A - F - G", "total - C - E - H",
                           "total - C - F - H", "total - A - E - G", "total - A - E - H", "total - B - D - G",
                           "total - B - D - H", "total - B - E - H", "total - C - D - G", "total - B - E - I",
                           "total - A - D - G", "total - B - D - I", "total - B - F - H", "total - C - F - G",
                           "total - A - E - I", "total - C - E - I", "total - B - E - G", "total - B - F - G",
                           "total - A - D - I", "total - A - D - H", "total - A - F - H", "total - B - F - I",
                           "total - C - F - I", "total - C - D - I", "total - C - D - H", "total - A - F - I",
                           "total - C - E - G"
                         )), row.names = c(NA,-40L), class = "data.frame")
    
    ui <- fluidPage(
      useShinyjs(),
      plotlyOutput("sunburst"),
      htmlOutput("hoverDataOut"),
      htmlOutput("clickDataOut")
    )
    
    server <- function(input, output, session) {
      output$sunburst <- renderPlotly({
        plot_ly(data = DF, source = "sunSource", customdata = ~ids, ids = ~ids, labels= ~labels, parents = ~parents, values= ~values, type='sunburst', branchvalues = 'total')
      })
    
      hoverData <- reactive({
        currentEventData <- unlist(event_data(event = "plotly_hover", source = "sunSource", priority = "event"))
      })
    
      clickData <- reactiveVal()
    
      observe({
        clickData(unlist(event_data(event = "plotly_click", source = "sunSource", priority = "event")))
      })
    
      onclick(id = "sunburst", expr = {clickData(hoverData())})
    
      output$hoverDataOut <- renderText({
        paste("Hover data:", paste(names(hoverData()), unlist(hoverData()), sep = ": ", collapse = " | "))
      })
    
      output$clickDataOut <- renderText({
        paste("Click data:", paste(names(clickData()), unlist(clickData()), sep = ": ", collapse = " | "))
      })
    
    }
    
    shinyApp(ui, server)
    

    Result


    I've created a GitHub issue to get some more information about this behaviour.

    You might also be interested in this post.


    Update: After the latest commit in reaction to this plotly_sunburstclick can be used as follows:

    # install latest r-plotly dev version:
    # devtools::install_github("ropensci/plotly")
    
    library(plotly)
    library(shinyjs)
    
    DF <- structure(list(labels = c("total", "A", "C", "B", "F", "E", "F", 
                                    "E", "D", "E", "D", "D", "F", "G", "H", "H", "G", "H", "G", "H", 
                                    "H", "G", "I", "G", "I", "H", "G", "I", "I", "G", "G", "I", "H", 
                                    "H", "I", "I", "I", "H", "I", "G"),
                         values = c(100L, 36L, 29L,
                                    35L, 12L, 14L, 10L, 14L, 8L, 18L, 5L, 10L, 9L, 6L, 5L, 4L, 3L,
                                    7L, 4L, 2L, 6L, 3L, 8L, 3L, 2L, 4L, 4L, 4L, 4L, 4L, 3L, 2L, 5L, 
                                    5L, 2L, 2L, 1L, 1L, 1L, 5L),
                         parents = c(NA, "total", "total", "total", "total - A", "total - C", "total - C", "total - A",
                                     "total - B", "total - B", "total - C", "total - A", "total - B",
                                     "total - A - F", "total - C - E", "total - C - F", "total - A - E",
                                     "total - A - E", "total - B - D", "total - B - D", "total - B - E",
                                     "total - C - D", "total - B - E", "total - A - D", "total - B - D",
                                     "total - B - F", "total - C - F", "total - A - E", "total - C - E",
                                     "total - B - E", "total - B - F", "total - A - D", "total - A - D",
                                     "total - A - F", "total - B - F", "total - C - F", "total - C - D",
                                     "total - C - D", "total - A - F", "total - C - E"),
                         ids = c(
                           "total", "total - A", "total - C", "total - B", "total - A - F", "total - C - E", 
                           "total - C - F", "total - A - E", "total - B - D", "total - B - E", "total - C - D",
                           "total - A - D", "total - B - F", "total - A - F - G", "total - C - E - H",
                           "total - C - F - H", "total - A - E - G", "total - A - E - H", "total - B - D - G",
                           "total - B - D - H", "total - B - E - H", "total - C - D - G", "total - B - E - I",
                           "total - A - D - G", "total - B - D - I", "total - B - F - H", "total - C - F - G",
                           "total - A - E - I", "total - C - E - I", "total - B - E - G", "total - B - F - G",
                           "total - A - D - I", "total - A - D - H", "total - A - F - H", "total - B - F - I",
                           "total - C - F - I", "total - C - D - I", "total - C - D - H", "total - A - F - I",
                           "total - C - E - G"
                         )), row.names = c(NA,-40L), class = "data.frame")
    
    ui <- fluidPage(
      useShinyjs(),
      plotlyOutput("sunburst"),
      htmlOutput("hoverDataOut"),
      htmlOutput("clickDataOut")
    )
    
    server <- function(input, output, session) {
      output$sunburst <- renderPlotly({
        plot_ly(data = DF, source = "sunSource", customdata = ~ids, ids = ~ids, labels= ~labels, parents = ~parents, values= ~values, type='sunburst', branchvalues = 'total')
      })
    
      hoverData <- reactive({
        currentEventData <- unlist(event_data(event = "plotly_hover", source = "sunSource", priority = "event"))
      })
    
      clickData <- reactive({
        currentEventData <- unlist(event_data(event = "plotly_sunburstclick", source = "sunSource", priority = "event"))
      })
    
      output$hoverDataOut <- renderText({
        paste("Hover data:", paste(names(hoverData()), unlist(hoverData()), sep = ": ", collapse = " | "))
      })
    
      output$clickDataOut <- renderText({
        paste("Click data:", paste(names(clickData()), unlist(clickData()), sep = ": ", collapse = " | "))
      })
    
    }
    
    shinyApp(ui, server)