Skip to content
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

A legend for Sankey networks #240

Open
wlandau opened this issue Jul 13, 2018 · 2 comments
Open

A legend for Sankey networks #240

wlandau opened this issue Jul 13, 2018 · 2 comments

Comments

@wlandau
Copy link

wlandau commented Jul 13, 2018

Any plans for sankeyNetwork(NodeGroup = "column_with_color", legend = TRUE)?

@cjyetman
Copy link
Collaborator

I don't believe anyone is working on that, but suppose we'd be open to PRs for it.

@fbiga
Copy link

fbiga commented Dec 20, 2021

Hello, I faced the same issue. Here's the way to add a legend.

You first need to create a d3.js code and store in the working directory. This d3.js code will create a legend, I started from the description in https://www.d3-graph-gallery.com/graph/custom_legend.html (section: categorical legend, use a loop).
I adapted to let it use data for the sankey as input

the d3.js could be called in R using r2d3::r2d3() function.

Then you need the function manipulateWidget::combineWidgets() to pair the sankey from sankeyNetwork and the legend.

I hope this could be useful for implementing a legend = T argument within the sankeyNetwork function.

Here's an example:
the d3.js code
`// create a list of keys
var keys = data

// Usually you have a color scale in your chart already
var color = d3.scaleOrdinal()
.domain(keys)
.range(d3.schemeCategory10)

// Add one dot in the legend for each name.
svg.selectAll("mydots")
.data(keys)
.enter()
.append("circle")
.attr("cx", 50)
.attr("cy", function(d,i){ return 100 + i*25}) // 100 is where the first dot appears. 25 is the distance between dots
.attr("r", 7)
.style("fill", function(d){ return color(d)})

// Add one dot in the legend for each name.
svg.selectAll("mylabels")
.data(keys)
.enter()
.append("text")
.attr("x", 70)
.attr("y", function(d,i){ return 100 + i*25}) // 100 is where the first dot appears. 25 is the distance between dots
// .style("fill", function(d){ return color(d)})
.text(function(d){ return d})
.attr("text-anchor", "left")
.style("alignment-baseline", "middle")`

and here's the R code:
library(networkD3)
library(dplyr)
library(manipulateWidget)
library(r2d3)

links <- data.frame(
source=c("group_A","group_A", "group_B", "group_C", "group_C", "group_E"),
target=c("group_C","group_D", "group_E", "group_F", "group_G", "group_H"),
value=c(2, 3, 2, 3, 1, 3)
) # Make a connection data frame

nodes <- data.frame(
name=c(as.character(links$source), as.character(links$target)) %>%
unique()
) # Make a nodes data frame

links$IDsource <- match(links$source, nodes$name)-1
links$IDtarget <- match(links$target, nodes$name)-1

links$group <- as.factor(c("type_a","type_a","type_a","type_b","type_b","type_b")) # Add a 'group' column to each connection:
nodes$group <- as.factor(c("my_first_group","my_first_group","my_first_group","my_first_group","my_first_group","my_second_group","my_first_group","my_second_group"))

my_color <- 'd3.scaleOrdinal() .domain(["type_a", "type_b", "my_first_group", "my_second_group"]) .range(d3.schemeCategory10)'

sankey <- sankeyNetwork(Links = links, Nodes = nodes, Source = "IDsource", Target = "IDtarget",
Value = "value", NodeID = "name", colourScale=my_color, LinkGroup="group", NodeGroup="group")

legend <- r2d3(data = unique(c(links$group, nodes$group)), script = "legend_test.js") # legend

combineWidgets(sankey, legend, ncol = 2, colsize = c(5,1)) # Combine plots

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants