Reputation: 53
I have a networkd3 Sankey diagram in my R/Shiny application, which pulls data from a MySQL connection. I am trying to find a way to 'drill-down' into the chart - click on a node and this will return the name of the node. I will then use this to pass another query to the DB which will populate a table in the application.
Here's what I have -
san <- sankeyNetwork(Links = sanData, Nodes = nodes, Source = "source",
Target = "target", Value = "value")
This plots the chart which works just fine.
Here's what I've tried so far -
Use R package htmlwidgets
, and run the followning JS script using onRender on my sankey chart.
Placeholder for the JS script:
clickFun <- 'd3.selectAll(".link").on("click",function(d) {alert(d.value);})'
In my sankey output:
onRender(san, clickFun)
This returns the value of the link as an alert. I tried using ".node"
and d.data.name
as suggested by some other examples, but I was never able to get this to work and no alert pops up.
Here are my questions:
1. How can I retrieve the name of the node from the sankey plot on mouse click?
2. Assuming I've achieved the above, how can I use the value returned by my JS script in my shiny application? I will change the alert()
bit to return()
, but I am at a loss as to how I can use this in my server application.
Upvotes: 5
Views: 1279
Reputation: 8848
The reason your click event works on the links, but not on the nodes is because the nodes also have a drag behavior attached to them. The easiest way to get around that is to nullify the drag behavior and then add the click behavior, like this...
library(networkD3)
library(htmlwidgets)
URL <- paste0('https://cdn.rawgit.com/christophergandrud/networkD3/',
'master/JSONdata/energy.json')
energy <- jsonlite::fromJSON(URL)
san <-
sankeyNetwork(Links = energy$links, Nodes = energy$nodes, Source = 'source',
Target = 'target', Value = 'value', NodeID = 'name',
units = 'TWh', fontSize = 12, nodeWidth = 30)
clickFun <-
'function() {
d3.selectAll(".node").on("mousedown.drag", null);
d3.selectAll(".node").on("click",function(d) { alert(d.name); })
}'
onRender(san, clickFun)
here's a working example where the onclick event returns the name of the clicked node, which is then passed to an R function that process an SQL command and returns the result to a datatable command, which displays the links that follow from that node...
library(shiny)
library(networkD3)
library(DT)
library(sqldf)
library(htmlwidgets)
URL <- paste0('https://cdn.rawgit.com/christophergandrud/networkD3/',
'master/JSONdata/energy.json')
energy <- jsonlite::fromJSON(URL)
energy$links$name <- energy$nodes$name[energy$links$source + 1]
df <- energy$links
funct <-
function (n) {
isp <- sprintf("Select * From df Where df.name='%s';", n)
isd <- sqldf::sqldf(isp)
return(isd)
}
ui <- shinyUI(fluidPage(
fluidRow(
column(4, sankeyNetworkOutput("sankey")),
column(4, DT::dataTableOutput("table"))
)
))
server <- shinyServer(function(input, output, session) {
session$onSessionEnded(stopApp)
output$sankey <- renderSankeyNetwork({
san <-
sankeyNetwork(Links = energy$links, Nodes = energy$nodes, Source = 'source',
Target = 'target', Value = 'value', NodeID = 'name',
units = 'TWh', fontSize = 12, nodeWidth = 30)
clickFun <-
'function() {
d3.selectAll(".node").on("mousedown.drag", null);
d3.selectAll(".node").on("click",function(d) { Shiny.onInputChange("id", d.name); });
}'
onRender(san, clickFun)
})
output$table <- DT::renderDataTable(DT::datatable(funct(input$id)))
})
shinyApp(ui = ui, server = server)
Upvotes: 5