Creating Org Charts using igraph

By Prakruti Shah | December 10, 2019

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")
Table 1: Nodes data
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")
Table 2: Edges data
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.

  1. There is a distinct list of nodes in the Nodes/Vertices table.
  2. 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.

comments powered by Disqus