-
Notifications
You must be signed in to change notification settings - Fork 266
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding Description to Nodes for sankeyNetwork function #130
base: master
Are you sure you want to change the base?
Conversation
Adding Node Description as a parameter to sankeyNetwork function
fixing missing check
Updating Docs with NodeDesc details
Hi, can you provide a reproducible example for testing? |
Adding JSON file with Node Description example
Hi, I have uploaded energywDesc.json file. In this example desc field shows % share of different sources in the target value. You can test it like below: Load energy projection data with Node DescriptionsURL <- 'https://raw.githubusercontent.com/ivot/networkD3/master/JSONdata/energywDesc.json' PlotsankeyNetwork(Links = energy$links, Nodes = energy_nodes_upd, Source = 'source', |
Hi @ivot. Probably being daft, but where does |
Hi @christophergandrud. I was lazy and used Excel to create node Description and then exported it as JSON. But here is the R code which does the same using standard energy.json file: #' Recreate Bostock Sankey diagram: http://bost.ocks.org/mike/sankey/
#' Load energy projection data
URL <- paste0('https://raw.githubusercontent.com/christophergandrud/networkD3/master/JSONdata/',
'energy.json')
energy <- jsonlite::fromJSON(URL)
add_desc_to_nodes<-function(list_links_nodes){
require(dplyr)
#' Add Source share for each Target
links_wSourceShare<-mutate(group_by(list_links_nodes$links,target), share=paste0(round(value/sum(value)*100, digits = 2),"%") )
#' Get list of Nodes and add ID which starts with 0, so we can join nodes and links data frames
nodes_wID<-list_links_nodes$nodes
nodes_wID$ID<-0:(nrow(nodes_wID)-1)
#' Add Source Names to Links data frame
links_wSourceShare<-merge.data.frame(links_wSourceShare, nodes_wID, by.x = "source", by.y = "ID")
#' Create a Comment as a concatenation of Source Name and Source Share in Target
links_wSourceShare$comment<-paste0(links_wSourceShare$name," - ",links_wSourceShare$share)
#' Order Links so that biggest value for each Target is on the top of the list.
#' This is needed so that concatenated text shows largest Source on the top of the Description field
links_wSourceShare<-arrange(links_wSourceShare, target, desc(value))
#' Combine all Comments into 1 string groupped by Target
Targets_wComments<-aggregate(comment ~ target, data = links_wSourceShare, paste0, collapse = "\n")
#' Add Combined Comment back to nodes data frame
nodes_wComments<-merge.data.frame(nodes_wID, Targets_wComments, by.x = "ID", by.y = "target", all.x = T)
#' Join Target Name and Combined Comment back to nodes data frame. This is to make Node Description in the format:
#' <Target Name>:
#' <Source1 Name> - <Source1 Share in Target>
#' <Source2 Name> - <Source2 Share in Target>
#' ...
nodes_wComments$desc<-paste0(nodes_wComments$name, sapply(nodes_wComments $comment, function(x){if(is.na(x)){""} else {paste0(":\n",x)}} ))
#' Keep only Node Name and Node Description in the final nodes data frame
list_links_nodes$nodes<-nodes_wComments[,c("name","desc")]
return(list_links_nodes)
}
energy<- add_desc_to_nodes(energy)
#' Plot
sankeyNetwork(Links = energy$links, Nodes = energy$nodes, Source = 'source',
Target = 'target', Value = 'value', NodeID = 'name', NodeDesc = 'desc',
units = 'TWh', fontSize = 12, nodeWidth = 30) |
Would it be possible to condense this so that it can be added as an easily understandable example and test? |
I removed function, so it is easy to run step-by-step. #' Recreate Bostock Sankey diagram: http://bost.ocks.org/mike/sankey/
#' Load energy projection data
URL <- paste0('https://raw.githubusercontent.com/christophergandrud/networkD3/master/JSONdata/',
'energy.json')
energy <- jsonlite::fromJSON(URL)
require(dplyr)
require(networkD3)
#' Get the list of Nodes and add ID which starts with 0, so we can join nodes and links data frames
#' (our data frames should both be 0-indexed)
nodes_wID<-as.data.frame(list(name=energy$nodes$name,ID=0:(nrow(energy$nodes)-1)))
#' Add % Source Share for each Target as a % of Source Value in Total Value for each Target
#' Add Source Names to Links data frame joining Source field in Links with ID field in Nodes
#' And sort Links so that biggest value for each Target is at the top of the list.
#' This is needed so that concatenated text shows largest Source on the top of the Description field
links_wSourceShare<-arrange(merge.data.frame(mutate(group_by(energy$links,target)
, share=paste0(round(value/sum(value)*100, digits = 2),"%") )
, nodes_wID, by.x = "source", by.y = "ID")
, target, desc(value))
#' Create a Comment as a concatenation of Source Name and %Source Share in Target
#' This is done by collapsing all Comments into 1 Combined Comment string grouping them by Target.
#' Now each Target has a description which mentions all Sources it depends on and % Source Share in the Target
Targets_wComments<-aggregate( paste0(name," - ",share) ~ target
, data = links_wSourceShare
, paste0, sep = " - ", collapse = "\n")
names(Targets_wComments)<-c("target","comment")
#' Add Combined Comment back to Nodes data frame joining by ID in Nodes and Target in Targets_wComments data frame
nodes_wComments<-merge.data.frame(nodes_wID, Targets_wComments, by.x = "ID", by.y = "target", all.x = T)
#' Combine Node Name with Node description.
#' #' This is to make Node Description in the format:
#' <Target Node Name>:
#' <Source1 Name> - <Source1 Share in Target Node>
#' <Source2 Name> - <Source2 Share in Target Node>
#' ...
nodes_wComments$desc<-paste0(nodes_wComments$name, sapply(nodes_wComments$comment
, function(x){if(is.na(x)){""} else {paste0(":\n",x)}} ))
#' Keep only Node Name and Node Description in the final nodes data frame
energy$nodes<- nodes_wComments[,c("name","desc")]
#' Plot
sankeyNetwork(Links = energy$links, Nodes = energy$nodes, Source = 'source',
Target = 'target', Value = 'value', NodeID = 'name', NodeDesc = 'desc',
units = 'TWh', fontSize = 12, nodeWidth = 30) |
Hm, I ran the example and nothing happens on mouseover. Any thoughts? |
I assume you did install my version of networkD3 devtools::install_github(repo = "ivot/networkD3") |
Same thing with your fork (I'm using Chrome to view the plot). |
Hmm, I think this might be due to the fact that in sankeyNetwork.js I have replaced also " node.append("rect")
.attr("height", function(d) { return d.dy; })
.attr("width", sankey.nodeWidth())
.style("fill", function(d) {
return d.color = color_node(d); })
.style("stroke", function(d) { return d3.rgb(d.color).darker(2); })
.style("opacity", 0.9)
.style("cursor", "move")
.append("title")
.text(function(d) { return d.desc + "\n" + format(d.value) +
" " + options.units; }); Obviously, for Windows "\n" is not enough. To fix this I created a branch ("ChangeBackToBR") for my project, where I changed it now to "\r\n". It works on Mac. Can you please check as well? devtools::install_github(repo = "ivot/networkD3", ref = "ChangeBackToBR") |
Hm, still nothing. |
Hi Christopher,
I suggest to modify sankeyNetwork function by adding a new field (NodeDesc) into Nodes data frame, which contains description of the node, so that on mouse hover-over the node pop-up message shows not the Node name, but a description for the node. If NodeDesc field is not specified when calling sankeyNetwork function then it is defaulted to NodeID.
This adds flexibility to the information displayed about Network Nodes, while keeping backwards compatibility.
Thank you,
Ivan