Demo 1: Network Data and Visualization

SIOP 2021 Workshop:

Network Analysis for Teams and Organizations

This demonstration will introduce you to working with network data in programming language R and the RStudio Integrated Development Environment for R.

We will examine data gathered from employees at a small company that produces wines and spirits in Spain. As the company grew, they were concerned about inter-departmental relationships between employeed and how to foster a common organizational culture.

38 employees in the company were asked how energizing their interactions with each of their co-workers were. These responses can be converted into a network, in which a tie from node i to node j indicates that employee i found their interactions with employee j to be energizing.

Data taken from: Casciaro, Tiziana, Vincent Dessain, and Elena Corsi. “Moët Hennessy España.” Harvard Business School Case 408-108, February 2008.

Load packages for network analysis

# Setup the igraph package for network analysis and plotting
# Check if igraph is installed. If not - installs the package automatically
if (!"igraph" %in% installed.packages()) install.packages("igraph")
# Load the igraph package, so that we can use functions from it for network analysis
library(igraph)
## 
## Attaching package: 'igraph'
## The following objects are masked from 'package:stats':
## 
##     decompose, spectrum
## The following object is masked from 'package:base':
## 
##     union

Load network data

# Pull network data from the web, in the form of adjacency matrices for each type of tie
energizingMatrix <- as.matrix(read.csv("https://sites.northwestern.edu/nearfutureofwork2021/files/2021/04/Energizing.csv",header=F))

# Preview the first ten rows and columns of the data
energizingMatrix[1:10,1:10]
##       V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
##  [1,]  0  0  0  0  0  0  0  0  0   0
##  [2,]  0  0  0  1  0  0  0  0  0   0
##  [3,]  0  0  0  1  0  0  0  0  0   0
##  [4,]  0  0  0  0  0  0  0  0  0   0
##  [5,]  0  0  0  0  0  0  0  0  0   0
##  [6,]  0  0  0  0  0  0  0  0  0   0
##  [7,]  0  0  0  0  0  0  0  0  0   0
##  [8,]  0  0  0  0  0  1  0  0  0   0
##  [9,]  0  0  0  0  0  0  0  0  0   0
## [10,]  0  0  0  0  0  0  0  0  0   0
# Visualize the entire adjacency matrix using the sna package
if (!"sna" %in% installed.packages()) install.packages("sna")
sna::plot.sociomatrix(energizingMatrix)

Load individual differences data

# Pull node attributes from the web
node_att <- read.csv("https://sites.northwestern.edu/nearfutureofwork2021/files/2021/04/Moet_NodeAttributes.csv")
# Preview the first 5 rows of the data - each node's department
node_att[1:5,]

Create a network object and find descriptives

# Create a network object in R
energizingNetwork <- graph_from_adjacency_matrix(energizingMatrix)
# Store the department of each node (vertex)
V(energizingNetwork)$department <- node_att$Department


# Find the number of nodes (vertices)
vcount(energizingNetwork)
## [1] 38
# Find the number of ties (edges)
ecount(energizingNetwork)
## [1] 86
# Compute the density of the network
graph.density(energizingNetwork) # Sanity check - do these values equal numEdges / (numVertices * numVertices-1)?
## [1] 0.06116643

Plot the network

# Reduce the plot margins for current and future plots
par(mar=c(0,0,0,0))
# Plot the network
plot(
     energizingNetwork,
     vertex.label = NA,    # Whether to label the nodes with names
     vertex.size = 6,      # Size of the nodes (vertices)
     edge.arrow.size = 0.5 # Size of the arrows
     )

Colors each node based on department

par(mar=c(0,0,0,0))
# Generate colors for each department that employees are in
colbar = rainbow(4) # Select 4 colors
# Store the colors as a node (vertex) attribute
V(energizingNetwork)$color <- colbar[as.factor(V(energizingNetwork)$department)]
# Incorporate the colors into the plot
plot(
     energizingNetwork,
     vertex.label = NA,
     vertex.size = 6,
     edge.arrow.size = 0.5,
     vertex.color = V(energizingNetwork)$color # Colors nodes based on department
     )

Change Node Size Based off of Indegree

par(mar=c(0,0,0,0))
# Change the size of nodes based on their indegree
V(energizingNetwork)$indegree <- degree(energizingNetwork, mode = "in") # Compute indegree
# Plot, sizing nodes by indegree
plot(
  energizingNetwork,
  vertex.label = NA,
  vertex.size = V(energizingNetwork)$indegree + 5,
  edge.arrow.size = 0.5,
  vertex.color = V(energizingNetwork)$color
)

Try organizing plots with different layout algorithms for networks

Fruchterman-Reingold algorithm: Fruchterman, T.M.J. and Reingold, E.M. (1991). Graph Drawing by Force-directed Placement. Software - Practice and Experience, 21(11):1129-1164.

Davidson and Harel algorithm: Ron Davidson, David Harel: Drawing Graphs Nicely Using Simulated Annealing. ACM Transactions on Graphics 15(4), pp. 301-331, 1996.

Spring algorithm: Kamada, T. and Kawai, S.: An Algorithm for Drawing General Undirected Graphs. Information Processing Letters, 31/1, 7–15, 1989.

# Different algorithms can generate different layouts for the network
# There is no single best layout algorithm for networks - It's more art than science
par(mar=c(0,0,0,0))
# Fruchterman-Reingold layout algorithm:
plot(
  energizingNetwork, vertex.label = NA, vertex.size = V(energizingNetwork)$indegree+5, edge.arrow.size = 0.5,
  vertex.color = V(energizingNetwork)$color,
  layout = layout_with_fr(energizingNetwork)
)

# Davidson and Harel layout algorithm:
plot(
  energizingNetwork, vertex.label = NA, vertex.size = V(energizingNetwork)$indegree+5, edge.arrow.size = 0.5,
  vertex.color = V(energizingNetwork)$color,
  layout = layout_with_dh(energizingNetwork)
)

# Spring layout algorithm:
plot(
  energizingNetwork, vertex.label = NA, vertex.size = V(energizingNetwork)$indegree+5, edge.arrow.size = 0.5,
  vertex.color = V(energizingNetwork)$color,
  layout = layout_with_kk(energizingNetwork)
)

Repeat this process with other social relationships

Data was gathered from employees on two other questions: (i) required relationships - how much input from others was required as part of their job, and (ii) informal relationshiips - who employees sought out for work-related input.

Alongside the energizing network, we can plot the network of formal/required interactions, and the network of informal reliance.

# Finally, we can repeat this process to visualize different kinds of social relationships
# Set up required reliance network
requiredMatrix <- as.matrix(read.csv("https://sites.northwestern.edu/nearfutureofwork2021/files/2021/04/Required.csv",header=F))
requiredNetwork <- graph_from_adjacency_matrix(requiredMatrix)
V(requiredNetwork)$department <- node_att$Department
V(requiredNetwork)$color <- colbar[as.factor(V(requiredNetwork)$department)]
V(requiredNetwork)$indegree <- degree(requiredNetwork, mode = "in")

# Set up informal reliance network
informalMatrix <- as.matrix(read.csv("https://sites.northwestern.edu/nearfutureofwork2021/files/2021/04/Informal.csv",header=F))
informalNetwork <- graph_from_adjacency_matrix(informalMatrix)
V(informalNetwork)$department <- node_att$Department
V(informalNetwork)$color <- colbar[as.factor(V(informalNetwork)$department)]
V(informalNetwork)$indegree <- degree(informalNetwork, mode = "in")

# Save one layout to use for all of the plots
myLayout <- layout_with_fr(energizingNetwork)
# Plot all three networks using this layout
par(mar=c(0,0,0,0))
plot(
  energizingNetwork, vertex.label = NA, vertex.size = V(energizingNetwork)$indegree+5, edge.arrow.size = 0.5,
  vertex.color = V(energizingNetwork)$color, 
  layout = myLayout
)

plot(
  requiredNetwork, vertex.label = NA, vertex.size = V(requiredNetwork)$indegree+5, edge.arrow.size = 0.5,
  vertex.color = V(requiredNetwork)$color, edge.color = "#000080", 
  layout = myLayout
)

plot(
  informalNetwork, vertex.label = NA, vertex.size = V(informalNetwork)$indegree+5, edge.arrow.size = 0.5,
  vertex.color = V(informalNetwork)$color, edge.color = "#004d00",
  layout = myLayout
)