In this document we will practice creating and examining graph objects in R, and visualizing those graphs using common visualization packages.

Exercise 1 - Creating an undirected graph object

# Download the karate dataset from the URL provided
url <- "https://ona-book.org/data/karate.csv"

karate_edgelist <- read.csv(url)
# this dataset is the edgelist from a study of a karate club by Wayne W. Zachary in 1977
# an edge between two vertices means that the two members socialized outside the club

# create an undirected graph from the edgelist
library(igraph)
## 
## Attaching package: 'igraph'
## The following objects are masked from 'package:stats':
## 
##     decompose, spectrum
## The following object is masked from 'package:base':
## 
##     union
karate_graph <- igraph::graph_from_data_frame(
  karate_edgelist,
  directed = FALSE
)
# View the graph object - how many vertices and edges are there?
karate_graph
## IGRAPH bb139a8 UN-- 34 78 -- 
## + attr: name (v/c)
## + edges from bb139a8 (vertex names):
##  [1] Mr Hi  --Actor 2  Mr Hi  --Actor 3  Mr Hi  --Actor 4  Mr Hi  --Actor 5 
##  [5] Mr Hi  --Actor 6  Mr Hi  --Actor 7  Mr Hi  --Actor 8  Mr Hi  --Actor 9 
##  [9] Mr Hi  --Actor 11 Mr Hi  --Actor 12 Mr Hi  --Actor 13 Mr Hi  --Actor 14
## [13] Mr Hi  --Actor 18 Mr Hi  --Actor 20 Mr Hi  --Actor 22 Mr Hi  --Actor 32
## [17] Actor 2--Actor 3  Actor 2--Actor 4  Actor 2--Actor 8  Actor 2--Actor 14
## [21] Actor 2--Actor 18 Actor 2--Actor 20 Actor 2--Actor 22 Actor 2--Actor 31
## [25] Actor 3--Actor 4  Actor 3--Actor 8  Actor 3--Actor 9  Actor 3--Actor 10
## [29] Actor 3--Actor 14 Actor 3--Actor 28 Actor 3--Actor 29 Actor 3--Actor 33
## + ... omitted several edges
# View the vertex set
V(karate_graph)
## + 34/34 vertices, named, from bb139a8:
##  [1] Mr Hi    Actor 2  Actor 3  Actor 4  Actor 5  Actor 6  Actor 7  Actor 9 
##  [9] Actor 10 Actor 14 Actor 15 Actor 16 Actor 19 Actor 20 Actor 21 Actor 23
## [17] Actor 24 Actor 25 Actor 26 Actor 27 Actor 28 Actor 29 Actor 30 Actor 31
## [25] Actor 32 Actor 33 Actor 8  Actor 11 Actor 12 Actor 13 Actor 18 Actor 22
## [33] Actor 17 John A
# View the edge set
E(karate_graph)
## + 78/78 edges from bb139a8 (vertex names):
##  [1] Mr Hi  --Actor 2  Mr Hi  --Actor 3  Mr Hi  --Actor 4  Mr Hi  --Actor 5 
##  [5] Mr Hi  --Actor 6  Mr Hi  --Actor 7  Mr Hi  --Actor 8  Mr Hi  --Actor 9 
##  [9] Mr Hi  --Actor 11 Mr Hi  --Actor 12 Mr Hi  --Actor 13 Mr Hi  --Actor 14
## [13] Mr Hi  --Actor 18 Mr Hi  --Actor 20 Mr Hi  --Actor 22 Mr Hi  --Actor 32
## [17] Actor 2--Actor 3  Actor 2--Actor 4  Actor 2--Actor 8  Actor 2--Actor 14
## [21] Actor 2--Actor 18 Actor 2--Actor 20 Actor 2--Actor 22 Actor 2--Actor 31
## [25] Actor 3--Actor 4  Actor 3--Actor 8  Actor 3--Actor 9  Actor 3--Actor 10
## [29] Actor 3--Actor 14 Actor 3--Actor 28 Actor 3--Actor 29 Actor 3--Actor 33
## [33] Actor 4--Actor 8  Actor 4--Actor 13 Actor 4--Actor 14 Actor 5--Actor 7 
## [37] Actor 5--Actor 11 Actor 6--Actor 7  Actor 6--Actor 11 Actor 6--Actor 17
## + ... omitted several edges

Exercise 2 - Creating a directed graph object

# Download the schoolfriends edgelist from the URL provided
url <- "https://ona-book.org/data/schoolfriends_edgelist.csv"

schoolfriends_edgelist <- read.csv(url)
# This network is from a research project on French high school children
# This edgelist gives two types of relationships.
# The first type is a reported friendship, where the first person reported
# the second person as a a friend in a survey.
# The second type is a known Facebook friendship connection between the two.

# filter the edgelist to just the reported friendships.
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:igraph':
## 
##     as_data_frame, groups, union
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
schoolfriends_rp_edgelist <- schoolfriends_edgelist |> 
  dplyr::filter(type == "reported")
# create an appropriate graph object from this filtered edgelist. 
schoolfriends_rp_graph <- igraph::graph_from_data_frame(
  schoolfriends_rp_edgelist,
  directed = TRUE
)
# Examine the graph object - how many vertices and edges does it have
schoolfriends_rp_graph
## IGRAPH aa32e60 DN-- 134 668 -- 
## + attr: name (v/c), type (e/c)
## + edges from aa32e60 (vertex names):
##  [1] 1 ->55  1 ->205 1 ->272 1 ->494 1 ->779 1 ->894 3 ->1   3 ->28  3 ->147
## [10] 3 ->272 3 ->407 3 ->674 3 ->884 27->63  27->173 28->202 28->327 28->353
## [19] 28->407 28->429 28->441 28->492 28->545 32->440 32->624 32->797 32->920
## [28] 34->151 34->277 34->502 34->866 45->48  45->79  45->335 45->496 45->601
## [37] 45->674 45->765 46->117 46->196 46->257 46->268 48->45  48->79  48->496
## [46] 55->1   55->170 55->205 55->252 55->272 55->779 55->883 55->894 61->797
## [55] 63->27  63->125 63->173 70->101 70->132 70->240 70->425 70->447 72->407
## [64] 72->674 72->857 79->45  79->48  79->335 79->496 79->601 79->674 79->765
## + ... omitted several edges

Exercise 3 - Comparing graphs

# Filter the schoolfriends data set to just the facebook friendships
schoolfriends_fb_edgelist <- schoolfriends_edgelist |> 
  dplyr::filter(type == "facebook")
# Create and examine an appropriate graph object from this filtered data set
(schoolfriends_fb_graph <- igraph::graph_from_data_frame(
  schoolfriends_fb_edgelist,
  directed = FALSE
))
## IGRAPH 14bdb55 UN-- 156 1437 -- 
## + attr: name (v/c), type (e/c)
## + edges from 14bdb55 (vertex names):
##  [1] 1 --883  1 --132  1 --339  1 --653  1 --545  1 --171  1 --117  1 --196 
##  [9] 1 --587  1 --372  1 --147  1 --55   1 --859  1 --106  1 --504  1 --471 
## [17] 1 --425  1 --170  1 --939  1 --272  1 --3    1 --119  1 --494  1 --205 
## [25] 1 --265  1 --779  1 --364  1 --240  1 --477  1 --101  1 --884  3 --504 
## [33] 3 --171  3 --545  3 --147  3 --441  3 --477  3 --272  3 --653  3 --884 
## [41] 3 --471  3 --372  9 --1594 9 --488  9 --471  9 --190  9 --272  9 --779 
## [49] 9 --55   9 --106  9 --325  14--232  14--520  14--65   14--605  14--621 
## [57] 20--387  20--615  20--151  20--977  20--1232 20--513  20--634  20--156 
## + ... omitted several edges

Write below a comparison of the basic properties of the two types of schoolfriends networks:

  1. The reported friendship graph is directed, whereas the Facebook friendship graph is undirected.
  2. The reported friendship graph has 134 vertices, compared to 156 vertices for the Facebook friendship graph, indicting that it is more more students had Facebook friendships versus reported friendships.
  3. There are 668 edges in the reported friendship graph, but 1437 in the Facebook friendship graph. This indicates that Facebook friendships are more common than reported friendships.

Exercise 4 - Loading a graph with edge properties

# Load the workfrance_edgelist data set from the URL provided.
# This is an edgelist of a network of interactions between office employees
# in various departments based on how much time they spent together during a given day
url <- "https://ona-book.org/data/workfrance_edgelist.csv"
workfrance_edgelist <- read.csv(url)
# Create a undirected graph object from this edgelist including any edge properties
workfrance_graph <- igraph::graph_from_data_frame(
  workfrance_edgelist,
  directed = FALSE
)
# verify that there is an edge property called mins and show the first ten values
# of this edge property
E(workfrance_graph)$mins[1:10]
##  [1]  8 14 17 10  7  7 20  7 21  6

Exercise 5 - Loading a graph with vertex properties

# Load the workfrance_vertices data set from the URL provided
url <- "https://ona-book.org/data/workfrance_vertices.csv"
workfrance_vertices <- read.csv(url)
# Recreate the undirected graph object with both edge and vertex properties
workfrance_graph <- igraph::graph_from_data_frame(
  workfrance_edgelist,
  vertices = workfrance_vertices,
  directed = FALSE
)
# find the vertex properties in your new graph
# choose one vertex property and show the first ten values
V(workfrance_graph)$dept[1:10]
##  [1] "DCAR" "DCAR" "DCAR" "DCAR" "DCAR" "DCAR" "DCAR" "DCAR" "DCAR" "DCAR"

Exercise 6 - Examining graph properties

# Identify the data types of each of the edge and vertex properties in your
# workfrance graph
workfrance_graph
## IGRAPH 3edafda UN-- 211 932 -- 
## + attr: name (v/c), dept (v/c), mins (e/n)
## + edges from 3edafda (vertex names):
##  [1] 3  --159  253--3    3  --447  3  --498  3  --694  3  --751  3  --859 
##  [8] 3  --908  14 --18   99 --14   14 --441  520--14   14 --544  14 --653 
## [15] 14 --998  15 --120  15 --160  15 --162  15 --178  15 --259  15 --261 
## [22] 15 --295  15 --353  15 --372  15 --464  15 --491  15 --498  15 --909 
## [29] 15 --1090 39 --18   99 --18   429--18   488--18   527--18   18 --621 
## [36] 18 --650  753--18   18 --797  18 --845  99 --27   160--27   259--27  
## [43] 295--27   27 --346  27 --1392 34 --156  34 --250  34 --259  34 --489 
## [50] 34 --615  34 --694  34 --884  34 --959  219--38   38 --435  39 --71  
## + ... omitted several edges
# Use the graph object to find the mean number of mins for all edges in your 
# workfrance graph
mean(E(workfrance_graph)$mins)
## [1] 23.9088
# EXTENSION - Create a subgraph of all vertices in the 'SSI' department
# calculate the mean number of mins for all edges in this subgraph
# Hint: try the igraph::induced_subgraph() function

SSI_vertices <- V(workfrance_graph)[V(workfrance_graph)$dept == 'SSI']

SSI_subgraph <- igraph::induced_subgraph(
  workfrance_graph,
  vids = SSI_vertices
)

mean(E(SSI_subgraph)$mins)
## [1] 26.4

Exercise 7 - Plotting a network graph

# Run a basic plot of the undirected karate graph
plot(karate_graph)

# Remove all labels except 'Mr Hi' and 'John A'
V(karate_graph)$label <- ifelse(V(karate_graph)$name %in% c('Mr Hi', 'John A'),
                                V(karate_graph)$name,
                                "")

plot(karate_graph)

# Re-do the layout using the Kamada-Kawaii layout
# Set a seed of 123 to control randomness
# Check whether your neighbor generated an identical plot
set.seed(123)
karate_graph$layout <- igraph::layout_with_kk(karate_graph)
plot(karate_graph)

Exercise 8 - Plotting a network graph (EXTENSION)

# Plot the undirected workfrance network graph without labels and using a 
# Fruchterman-Reingold force directed layout.  Use a seed of 123.
set.seed(123)
workfrance_graph$layout <- igraph::layout_with_fr(workfrance_graph)
V(workfrance_graph)$label <- ""
plot(workfrance_graph)

# Resize the vertices to size 5
V(workfrance_graph)$size <- 5
plot(workfrance_graph)

# Resize the vertices to size 5
V(workfrance_graph)$size <- 5
plot(workfrance_graph)

# Try to color the vertices of the graph by the dept of the vertex
V(workfrance_graph)$color <- factor(V(workfrance_graph)$dept)
plot(workfrance_graph)

Exercise 9 - Plotting a network graph using ggraph (EXTENSION)

# Create a basic Plot of the workfrance undirected network using ggraph
# use a Kamada-Kawaii layout and set a seed of 123
library(ggraph)
## Loading required package: ggplot2
set.seed(123)
ggraph(workfrance_graph, layout = "kk") +
  geom_edge_link(color = "grey") +
  geom_node_point(size = 3) +
  theme_void()

# Redo the plot again using an aesthetic to color the vertices by dept
set.seed(123)
ggraph(workfrance_graph, layout = "kk") +
  geom_edge_link(color = "grey") +
  geom_node_point(size = 3, aes(color = dept)) +
  theme_void()

# (EXTENSION) Try to scale the edge by the mins edge property
set.seed(123)
ggraph(workfrance_graph, layout = "kk") +
  geom_edge_link(aes(color = mins)) +
  geom_node_point(size = 3, aes(color = dept),
                  show.legend = FALSE) +
  theme_void()

Exercise 10 - Interactive network visualization using networkD3 (EXTENSION)

# Create a group in the karate graph containing Mr Hi and John A
V(karate_graph)$group <- ifelse(V(karate_graph)$name %in% c("Mr Hi", "John A"), 1, 0)
# Convert the karate graph for the purposes of using networkD3
# Use you new group in the conversion
library(networkD3)

karate_d3 <- networkD3::igraph_to_networkD3(karate_graph, 
                                            group = V(karate_graph)$group)
# Run a force network visualization of the karate graph in networkD3 
networkD3::forceNetwork(Links = karate_d3$links, 
                        Nodes = karate_d3$nodes, 
                        NodeID = "name",   
                        Source = "source",
                        Target = "target", 
                        Group = "group",
                        opacity = 1)