Search code examples
rplotlyshinysankey-diagramggplotly

Displaying the table details from sankey chart in R shiny


The script below works on the patients data from bupaR package,and creates a sankey plot listing the relation between a resource from the "employee" column with the activity he is involved in from the "handling" column in the patients data. Besides the plot there is a data table available from DT which gives details of every sankey plot path when clicked. I want a functionality such that when I click on any path, say path connecting "r1" employee and "Registration" handling activity, I want all the rows from patients data with both these fields available in the plot besides, similarly for all other paths, this should be dynamic as I shall apply the functionality on larger datasets. Attaching the snapshot for reference. Thanks and please help.

## app.R ##
library(shiny)
library(shinydashboard)
library(devtools)
library(ggplot2)
library(plotly)
library(proto)
library(RColorBrewer)
library(gapminder)
library(stringr)
library(broom)
library(mnormt)
library(DT)
library(bupaR)

ui <- dashboardPage(
dashboardHeader(title = "Sankey Chart"),
dashboardSidebar(
width = 0
),
dashboardBody(
box(title = "Sankey Chart", status = "primary",height = "455" ,solidHeader = T,
    plotlyOutput("sankey_plot")),

box( title = "Case Summary", status = "primary", height = "455",solidHeader = T, 
     dataTableOutput("sankey_table"))
 )
 )
 server <- function(input, output) 
 { 
 output$sankey_plot <- renderPlotly({
 sankeyData <- patients %>% 
  group_by(employee,handling) %>% 
  count()
 sankeyNodes <- list(label = c(sankeyData$employee,sankeyData$handling))
 trace2 <- list(
  domain = list(
    x = c(0, 1), 
    y = c(0, 1)
  ), 
  link = list(
    label = paste0("Case",1:nrow(sankeyData)), 
    source = sapply(sankeyData$employee,function(e) {which(e == 
  sankeyNodes$label) }, USE.NAMES = FALSE) - 1, 
    target = sapply(sankeyData$handling,function(e) {which(e == 
  sankeyNodes$label) }, USE.NAMES = FALSE) - 1, 
    value = sankeyData$n
  ), 
  node = list(label = sankeyNodes$label), 
  type = "sankey"
  )
  data2 <- list(trace2)
  p <- plot_ly()
  p <- add_trace(p, domain=trace2$domain, link=trace2$link, 
               node=trace2$node, type=trace2$type)
  p
  })
  output$sankey_table <- renderDataTable({
  d <- event_data("plotly_click")
  d
  })
  }
  shinyApp(ui, server)

Snapshot


Solution

  • Hi I interpreted the output from event_data as such that pointNumber is the index of the link but I might be wrong here. Any way this is my Solution and it works for this data

    library(shiny)
    library(shinydashboard)
    library(devtools)
    library(ggplot2)
    library(plotly)
    library(proto)
    library(RColorBrewer)
    library(gapminder)
    library(stringr)
    library(broom)
    library(mnormt)
    library(DT)
    library(bupaR)
    library(dplyr)
    
    ui <- dashboardPage(
      dashboardHeader(title = "Sankey Chart"),
      dashboardSidebar(
        width = 0
      ),
      dashboardBody(
        box(title = "Sankey Chart", status = "primary",height = "455" ,solidHeader = T,
            plotlyOutput("sankey_plot")),
    
        box( title = "Case Summary", status = "primary", height = "455",solidHeader = T, 
             dataTableOutput("sankey_table"))
      )
    )
    server <- function(input, output) 
    { 
      sankeyData <- reactive({
        sankeyData <- patients %>% 
          group_by(employee,handling) %>% 
          count()
        sankeyNodes <- list(label = c(sankeyData$employee,sankeyData$handling) %>% unique())
        trace2 <- list(
          domain = list(
            x = c(0, 1), 
            y = c(0, 1)
          ), 
          link = list(
            label = paste0("Case",1:nrow(sankeyData)), 
            source = sapply(sankeyData$employee,function(e) {which(e == 
                                                                     sankeyNodes$label) }, USE.NAMES = FALSE) - 1, 
            target = sapply(sankeyData$handling,function(e) {which(e == 
                                                                     sankeyNodes$label) }, USE.NAMES = FALSE) - 1, 
            value = sankeyData$n
          ), 
          node = list(label = sankeyNodes$label), 
          type = "sankey"
        )
        trace2
      })
    
      output$sankey_plot <- renderPlotly({
        trace2 <- sankeyData()
        p <- plot_ly()
        p <- add_trace(p, domain=trace2$domain, link=trace2$link, 
                       node=trace2$node, type=trace2$type)
        p
      })
      output$sankey_table <- renderDataTable({
        d <- event_data("plotly_click")
        req(d)
        trace2 <- sankeyData()
        sIdx <-  trace2$link$source[d$pointNumber+1]
        Source <- trace2$node$label[sIdx + 1 ]
        tIdx <- trace2$link$target[d$pointNumber+1]
        Target <- trace2$node$label[tIdx+1]
        patients %>% filter(employee == Source & handling == Target)
    
    
      })
    }
    shinyApp(ui, server)
    

    hope it helps!