Creating a Sankey Diagram for an Org Chart - r

I have data in an excel table with two pertinent columns:
Employee Name and Manager Name.
I want to use networkD3 in R to create a Sankey Diagram with this data to show how our organization is split up. I'm a relative amateur with R but I've been able to produce Sankey charts by hard-coding each node. Is it possible to do this with the data I have?
library(networkD3)
nodes = data.frame("name" =
c(All_Employees$`Employee Name`))
links = as.data.frame(matrix(c(
All_Employees$`Employee Name`,All_Employees$`Manager Name`,1),
byrow = TRUE, ncol = 3))
names(links) = c("source", "target", "value")
sankeyNetwork(Links = links, Nodes = nodes,
Source = "source", Target = "target",
Value = "value", NodeID = "name",
fontSize= 12, nodeWidth = 30)

A Sankey diagram is probably not the best type of plot for this, but if you arrange your data into the proper format first, it will work...
All_Employees <-
read.csv(header = T, na.strings = "", stringsAsFactors = F, check.names = F,
text = "
Employee Name,Manager Name
Betty,
Tom,Betty
Bob,Betty
Mark,Tom
John,Tom
Sally,Bob")
node_names <- factor(sort(unique(as.character(unname(unlist(All_Employees))))))
nodes <- data.frame(name = node_names)
links <- data.frame(source = match(All_Employees$`Manager Name`, node_names) - 1,
target = match(All_Employees$`Employee Name`, node_names) - 1,
value = 1)
links <- links[!is.na(links$source), ]
library(networkD3)
sankeyNetwork(Links = links, Nodes = nodes,
Source = "source", Target = "target",
Value = "value", NodeID = "name",
fontSize = 12, nodeWidth = 30)
Alternatively, you could use diagonalNetwork() which creates a tree diagram that is probably better suited...
library(dplyr)
library(data.tree)
library(networkD3)
All_Employees %>%
filter(!is.na(`Manager Name`)) %>%
data.tree::FromDataFrameNetwork() %>%
data.tree::ToListExplicit(unname = TRUE) %>%
diagonalNetwork()
Or if you're using the dev version of networkD3, you can more easily use the new treeNetwork() function, which is has more customization (but is still buggy because it's still in dev)...
library(dplyr)
library(networkD3)
All_Employees %>%
rename(nodeId = `Employee Name`, parentId = `Manager Name`) %>%
mutate(name = nodeId) %>%
treeNetwork(direction = "down", linkType = "elbow")

Related

Place nodes explicitly with visNetwork (or an Alternative)

How can I explicitly place nodes on a visNetwork graph?
Or: How can I recreate that graphic in R using visNetwork or an alternative?
Background: The ultimate goal is to represent Causal Loop Diagrams coming from Vensim files. Placing the nodes explicitly is just the first (crucial) step, because in Causal Loop Diagrams the visual mapping of nodes is part of the information (unlike in general graph theory). So if anybody has advice on the bigger picture aka. 'Bringing Causal Loop Diagram Modeling to R', I'll be more than happy.
What I tried:
library("visNetwork")
nodes <- data.frame(id = 1:3, label = c("one", "two", "three"))
edges <- data.frame(from = c(1,1,2), to = c(2,3,1))
visNetwork(nodes, edges, width = "100%", title = nodes$labels, stringsAsFactors = FALSE) %>% visEdges(arrows = "to")
which plots something like (exact layout will change, because of random seed):
With the Q&A from here I tried to place nodes manually by setting x and y values.
library("visNetwork")
nodes <- data.frame(id = 1:3, label = c("one", "two", "three"), x = c(0,1,2), y = c(0,1,2))
edges <- data.frame(from = c(1,1,2), to = c(2,3,1))
visNetwork(nodes, edges, width = "100%", title = nodes$labels, stringsAsFactors = FALSE) %>% visEdges(arrows = "to")
which plots:
..and I really don't understand what's the correspondance between x, y and the placing on the screen..
Also I could not find anything in the docs for visLayout.
It somehow turns out, that the x and y args are not working. Here a solution:
library("visNetwork")
nodes <- data.frame(id = 1:3, label = c("one", "two", "three"))
edges <- data.frame(from = c(1,1,2), to = c(2,3,1))
coords <- as.matrix(data.frame(x = c(0,1,2),
y = c(0,1,2),
stringsAsFactors = FALSE))
visNetwork(nodes, edges, width = "100%", title = nodes$labels) %>%
visNodes() %>%
visOptions(highlightNearest = TRUE) %>%
visInteraction(navigationButtons = TRUE,
dragNodes = TRUE, dragView = TRUE,
zoomView = FALSE) %>%
visEdges(arrows = 'to') %>%
visIgraphLayout(layout = "layout.norm", layoutMatrix = coords)
For history see also here.
Perhaps these links might be helpful for what you want to achive: causaleffect and plot.CLD
Using ggraph instead of visNetwork simplifies things.
library(ggraph)
library(igraph)
g <- make_graph(edges = c(1,2,2,1,1,3))
V(g)$name <- c('one', 'two', 'three')
ggraph(g, layout = 'manual', node.positions = data.frame(x = c(1,1,2), y = c(2,1,2.1))) +
geom_edge_arc(aes(start_cap = label_rect(node1.name),
end_cap = label_rect(node2.name)),
angle_calc = 'along',
label_dodge = unit(2.5, 'mm'),
arrow = arrow(length = unit(4, 'mm'))) +
geom_node_text(aes(label = name, x = x, y = y))
This plots
which is (apart from gridlines and colours) what I was searching for.

igraph/visNetwork with R: How to disable forward linking?

The following code produces a nice network diagram:
library(igraph);library(visNetwork);library(dplyr)
set.seed(123)
nnodes <- 10
nnedges <- 20
nodes <- data.frame(id = 1:nnodes)
edges <- data.frame(from = sample(1:nnodes, nnedges, replace = T),
to = sample(1:nnodes, nnedges, replace = T))
visNetwork(nodes, edges) %>%
visIgraphLayout(layout = "layout_in_circle") %>%
visNodes(shape="circle") %>%
visOptions(highlightNearest = list(enabled = T, hover = T), nodesIdSelection = T)
My question is: How can I disable that edges that leave from a neighboring node are displayed as well (e.g. when node 8 is selected, I don't want the edge from 3 to 9 to be shown).
Edit: Libraries added, thx for poining that out
Using the comment from Djack and wici, I achieved the following solution:
library(igraph);library(visNetwork);library(dplyr)
set.seed(123)
nnodes <- 10
nnedges <- 20
nodes <- data.frame(id = 1:nnodes, label = 1:nnodes)
edges <- data.frame(from = sample(1:nnodes, nnedges, replace = T),
to = sample(1:nnodes, nnedges, replace = T))
visNetwork(nodes, edges) %>%
visIgraphLayout(layout = "layout_in_circle") %>%
visNodes(shape="circle") %>%
visOptions(highlightNearest = list(enabled = T, hover = T, algorithm="hierarchical"),nodesIdSelection = T) %>%
visInteraction(hover = T)
I hope, thats what you're looking for.

r visNetwork node position issue

I am creating graph structure
id <- c(1,2,3,4,5,6,7,8,9)
label <- c("All", "Cat", "Dog", "Rice","Fish", "Bread","Rice","Fish", "Bread")
nodes <- data.frame(id, label)
edges <- data.frame(
from = c(1,1,2,2,2,3,3,3),
to = c(2,3,4,5,6,7,8,9)
)
visNetwork(nodes, edges, width = "100%",height = "800px") %>% visNodes(shape = "square") %>%
visEdges(arrows = "to") %>%
visInteraction(navigationButtons = TRUE)%>%
visHierarchicalLayout(levelSeparation = 200) %>%
visOptions(manipulation = TRUE)
expecting it to show up like this.
However the actual output is like this
The node positions are incorrect , I cannot manually move the nodes and this makes it very hard to explain. Need help rearranging the nodes based on the expected output above.
You can specify the level for each node to get the orientation you want.
library(visNetwork)
id <- c(1,2,3,4,5,6,7,8,9)
label <- c("All", "Cat", "Dog", "Rice","Fish", "Bread","Rice","Fish", "Bread")
nodes <- data.frame(id, label, level = c( 1,2,2,3,3,3,3,3,3))
edges <- data.frame(
from = c(1,1,2,2,2,3,3,3),
to = c(2,3,4,5,6,7,8,9)
)
visNetwork(nodes, edges, width = "100%",height = "800px") %>% visNodes(shape = "square") %>%
visEdges(arrows = "to") %>%
visInteraction(navigationButtons = TRUE)%>%
visHierarchicalLayout(levelSeparation = 200) %>%
visOptions(manipulation = TRUE)

How to add text to a graph in diagrammeR

I want to create a nice graph that illustrates some of my data.
I have created the graph but I would like to add some calculated text to the node. How do I do this.
This is my graph but how/ where do I add a field I have calculated in R?:
library(magrittr)
library(DiagrammeR)
# Create a simple NDF
nodes <-
create_nodes(nodes = c("Index", "Surveillance", "Intervention", "Lost to Follow-up"))
# Create a simple EDF
edges <-
create_edges(from = c("Index", "Surveillance", "Index", "Surveillance","Intervention","Surveillance","Intervention"),
to = c("Surveillance", "Intervention", "Lost to Follow-up", "Lost to Follow-up","Intervention","Surveillance","Lost to Follow-up"),
)
graph <-
create_graph(
nodes_df = nodes,
edges_df = edges,
graph_attrs = "layout = twopi",
node_attrs = "fontname = Helvetica",
edge_attrs = "color = gray20"
)
# View the graph
render_graph(graph,output = "visNetwork")
require(visNetwork, quietly = TRUE)
nb = "Information here"
nodes <- data.frame(id = 1:5, group = c(rep("A", 2), rep("B", 3)),
title = paste("<p>", 1:5,"<br>",nb, sep = ""), stringsAsFactors = FALSE)
edges <- data.frame(from = c(2,5,3,3), to = c(1,2,4,2))
### USE
visNetwork(nodes, edges, width = "100%") %>% visOptions(highlightNearest = list(enabled =TRUE,algorithm="hierarchical"))
You will see your info when you pass the mouse on your node.

How to color groups in networkD3's sankeyNetwork?

My nodes consists of names and groups yet I can't seem to implement distinct colors for groups in my sankey diagram. The colors are either all blue with defaults or all black using the code below.
Here's the code I use:
sankeyNetwork(
Links = data$links,
Nodes = data$nodes,
Source= "source",
Target = "target",
Value = "weight",
NodeID = "names",
fontSize = 15,
NodeGroup = "group"
))
Here's the output I'm getting:
The NodeGroup vector in the Nodes data frame needs to be non-numeric. That's not obvious from the documentation. Because you didn't provide the data you're working with, we can't be sure if that is the problem you were having, but in the example that #john-friel made, that is the problem. Here's a working example with the only change being that the group vector is coerced to a character vector...
library(networkD3)
source <- c(0,1,2,3,4,5)
target <- c(2,2,2,3,1,0)
value <- c(33,44,55,66,77,88)
sankeydata <- data.frame(source,target, value)
names <- c('a', 'b', 'c', 'd', 'e', 'f')
id <- c(0,1,2,3,4,5)
group <- as.character(c(1,1,1,2,2,2)) # this is the only line changed
sankeyNodes <- data.frame(names,id, group)
sankeyNetwork(Links = sankeydata, Nodes = sankeyNodes, Source = "source",
Target = "target", Value = "value", NodeID = "names",
NodeGroup = "group", fontSize = 12, nodeWidth = 30)
library(networkD3)
source <- c(0,1,2,3,4,5)
target <- c(2,2,2,3,1,0)
value <- c(33,44,55,66,77,88)
sankeydata <- data.frame(source,target, value)
names <- c('a', 'b', 'c', 'd', 'e', 'f')
id <- c(0,1,2,3,4,5)
group <- c(1,1,1,2,2,2)
sankeyNodes <- data.frame(names,id, group)
sankeyNetwork(Links = sankeydata, Nodes = sankeyNodes, Source = "source",
Target = "target", Value = "value", NodeID = "names", NodeGroup = "group", fontSize = 12, nodeWidth = 30)
I would expect two colors ( since there are two groups), but no colors return. I have the same issue as OP.
The help text suggests NodeGroup is responsible for the color.
If you run a similar code for another graph in library(networkD3):
#same data
forceNetwork(Links = sankeydata, Nodes = sankeyNodes , Source = "source",
Target = "target", Value = "value", NodeID = "names",
Group = "group", opacity = 0.8, zoom = TRUE)
Plots two different colors for in the network graph.

Resources