In this document we will practice creating and examining graph objects in R, and visualizing those graphs using common visualization packages.
# 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
# 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
# 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:
# 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
# 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"
# 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
# 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)
# 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)
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()
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)