Creating Org Charts using igraph
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
In this post we will create some Organizational charts using the ‘igraph’ package in R. Network diagrams work great for representing team relationships or other connections amongst employees in an Org chart. An employee appears as a “node” or “vertice” of the network, while the relationships are represented by the “edges” or “links” that connect the nodes. We can also use the attributes such as color, shape and size to show team formations, specific roles or hierarchy.
Set-up
Let’s begin by installing and loading some R packages.
#install.packages("igraph") ##load library 'easypackages' to enable loading multiple libraries in the next step library(easypackages) ##load all required libraries for the analysis libraries("dplyr","tidyr","lubridate","ggplot2","igraph","knitr","kableExtra")
Next, we will create some input dataframes to feed into our network diagrams. Here, I am creating a csv file with all the information we need and then loading it in using the “read.csv()” function.
Nodes <- read.csv('Traits.csv') Edges <- read.csv('Relations.csv')
This is how our data looks like.
Nodes %>% kable(format = "html",caption = "Nodes data") %>% kable_styling(bootstrap_options = c("striped", "hover") , full_width = TRUE) %>% scroll_box(height = "200px")
Staff | Role | Department | Color | Shape |
---|---|---|---|---|
Laurence F. | Leadership | Operations | #F5C019 | circle |
Constans G. | Finance | Operations | #999999 | circle |
Caleb M. | Consultant | Services | #90C432 | star |
Antero H. | Office/Facilities Management | Operations | #999999 | circle |
Tahlia O. | Security and Compliance | Operations | #999999 | circle |
Ivona L. | Leadership | Operations | #F5C019 | circle |
Tertia C. | Analyst | Services | #E3F0CC | star |
Samantha L. | Analyst | Services | #E3F0CC | star |
Grady C. | Analyst | Services | #E3F0CC | star |
Riya S. | Leadership | Services | #F5C019 | star |
Medrod P. | Leadership | Business Development | #F5C019 | triangle |
Avinash A. | Project Lead | Services | #5C7D20 | star |
Roshan T. | Project Lead | Services | #5C7D20 | star |
Ursula B. | Leadership | Software | #F5C019 | square |
Arnaq H. | Technical Program Manager | Software | #999999 | square |
Kalyna C. | Developer | Software | #2494b5 | square |
Arij N | Developer | Software | #2494b5 | square |
Mohammad L. | Developer | Software | #2494b5 | square |
Odilia C. | Developer | Software | #2494b5 | square |
Nikhil M. | Consultant | Services | #90C432 | star |
Elena S. | Analyst | Services | #E3F0CC | star |
Matt H. | Project Lead | Services | #5C7D20 | star |
Vali L. | Leadership | Operations | #F5C019 | circle |
Fulbert R. | Director | Business Development | #999999 | triangle |
Rami J. | Consultant | Business Development | #90C432 | triangle |
Note that I have added attributes such as “Color” and “Shape” to the Employee information before loading it in. This will be useful when we start customizing our chart to show specific roles and/or teams. As an alternative, you can skip this step and assign such attributes within the R script.
Edges %>% kable(format = "html",caption = "Edges data") %>% kable_styling(bootstrap_options = c("striped", "hover") , full_width = TRUE) %>% scroll_box(height = "200px")
Manager | Staff |
---|---|
Vali L. | Laurence F. |
Ivona L. | Constans G. |
Riya S. | Caleb M. |
Laurence F. | Antero H. |
Ivona L. | Tahlia O. |
Laurence F. | Ivona L. |
Riya S. | Tertia C. |
Riya S. | Samantha L. |
Riya S. | Grady C. |
Laurence F. | Riya S. |
Laurence F. | Medrod P. |
Matt H. | Avinash A. |
Matt H. | Roshan T. |
Laurence F. | Ursula B. |
Ursula B. | Arnaq H. |
Ursula B. | Kalyna C. |
Arnaq H. | Arij N |
Arnaq H. | Mohammad L. |
Arnaq H. | Odilia C. |
Grady C. | Nikhil M. |
Grady C. | Elena S. |
Riya S. | Matt H. |
Medrod P. | Fulbert R. |
Medrod P. | Rami J. |
In order to avoid errors during the later steps, we should ensure that the following two conditions are met in our input data.
- There is a distinct list of nodes in the Nodes/Vertices table.
- All nodes in the edge list are listed in the Nodes table.
The Igraph Object
We need to create an igraph object to plot our data. Quite intuitively, there is a function in the ‘igraph’ package called “graph_from_data_frame()” to help us do that.
orgnet <- graph_from_data_frame(Edges, directed=TRUE, vertices=Nodes) summary(orgnet) ## IGRAPH 07bdd51 DN-- 25 24 -- ## + attr: name (v/c), Role (v/c), Department (v/c), Color (v/c), Shape ## | (v/c)
And now, just pass the igraph object to the “plot()” function and voila, we have our basic Org chart ready.
plot(orgnet)
Customize
Once the basic Org chart is ready, we can customize it further by using color, shape and size. Here, we will use color to specify roles of each employee and shape to represent teams or departments.
Sprinkle some color
This is where the attribute column “color” pre-loaded with our input data will come handy.
##Adding color to the Nodes V(orgnet)$color <- as.character(Nodes$Color) ##Changing the color of the links from gray to black E(orgnet)$color <- "black" ##Using size parameters in the plot function to adjust size of the arrow heads and labels plot(orgnet,edge.arrow.size = .5, vertex.label.color="black",vertex.label.cex=0.8,vertex.size = 8)
Leverage shapes
The ‘igraph’ package includes some default shapes such as circle and square but you can easily add new shapes using the code provided in the Package documentation. Here is the code provided for creating a triangle.
mytriangle <- function(coords, v=NULL, params) { vertex.color <- params("vertex", "color") if (length(vertex.color) != 1 && !is.null(v)) { vertex.color <- vertex.color[v] } vertex.size <- 1/200 * params("vertex", "size") if (length(vertex.size) != 1 && !is.null(v)) { vertex.size <- vertex.size[v] } symbols(x=coords[,1], y=coords[,2], bg=vertex.color, stars=cbind(vertex.size, vertex.size, vertex.size), add=TRUE, inches=FALSE) } # clips as a circle add_shape("triangle", clip=shapes("circle")$clip, plot=mytriangle)
And, this will create a ‘Star’ with the flexibility of adding as many rays as you want.
mystar <- function(coords, v=NULL, params) { vertex.color <- params("vertex", "color") if (length(vertex.color) != 1 && !is.null(v)) { vertex.color <- vertex.color[v] } vertex.size <- 1/200 * params("vertex", "size") if (length(vertex.size) != 1 && !is.null(v)) { vertex.size <- vertex.size[v] } norays <- params("vertex", "norays") if (length(norays) != 1 && !is.null(v)) { norays <- norays[v] } mapply(coords[,1], coords[,2], vertex.color, vertex.size, norays, FUN=function(x, y, bg, size, nor) { symbols(x=x, y=y, bg=bg, stars=matrix(c(size,size/2), nrow=1, ncol=nor*2), add=TRUE, inches=FALSE) }) } # no clipping, edges will be below the vertices anyway add_shape("star", clip=shape_noclip,plot=mystar, parameters=list(vertex.norays=7))
Now, all we need to do is add the shape attribute to our plot by assigning the column “Shape” that we pre-loaded with our input data.
V(orgnet)$shape <- as.character(Nodes$Shape) plot(orgnet,edge.arrow.size = .5, vertex.label.color="black",vertex.label.font = 1,vertex.label.cex=1,vertex.size = 9,vertex.label.dist=0)
If needed, we can create and add a table with the key to identify the colors and shapes mapped to specific Roles and Teams respectively.
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.