1 Importing and visualizing network data

  • Import network data from external edge list.
  • Import node attributes from external dataset.
  • Plot networks with igraph and with ggraph.
  • Plot with different network layouts.
# Packages
library(tidyverse)
library(igraph)
library(skimr)
library(janitor)
library(ggraph)

# Read the edgelist data into R
(elist <- read_csv("./Data/class_edgelist_clean.csv"))
## # A tibble: 44 × 3
##    from  to    tie_weight
##    <chr> <chr>      <dbl>
##  1 David Sofia          2
##  2 David Maria          2
##  3 David Lem            1
##  4 David Beth           3
##  5 David Mark           1
##  6 David Amber          2
##  7 Sofia David          1
##  8 Sofia Maria          5
##  9 Sofia Beth           1
## 10 Sofia Amber          2
## # … with 34 more rows
# Using a function from igraph, convert the data frame above into a network.
graph <- graph_from_data_frame(elist)

# In igraph, networks are objects of class "igraph"
class(graph)
## [1] "igraph"
# Summary information about this network
graph
## IGRAPH 47248d4 DN-- 11 44 -- 
## + attr: name (v/c), tie_weight (e/n)
## + edges from 47248d4 (vertex names):
##  [1] David->Sofia  David->Maria  David->Lem    David->Beth   David->Mark  
##  [6] David->Amber  Sofia->David  Sofia->Maria  Sofia->Beth   Sofia->Amber 
## [11] Maria->David  Maria->Sofia  Maria->Lem    Maria->Beth   Maria->Amber 
## [16] Jose ->Sofia  Jose ->Maria  Lem  ->David  Lem  ->Maria  Lem  ->Jim   
## [21] Lem  ->Beth   Lem  ->Amber  Jim  ->Maria  Jim  ->Lem    Jim  ->Beth  
## [26] Jim  ->Amber  Beth ->David  Beth ->Sofia  Beth ->Maria  Beth ->Lem   
## [31] Beth ->Jim    Beth ->Amber  Mark ->David  Mark ->Jose   Mark ->Amber 
## [36] Kent ->Thomas Amber->David  Amber->Sofia  Amber->Maria  Amber->Lem   
## + ... omitted several edges
# The graph is Directed, Named, NOT Weighted, NOT Bipartite.
# The graph has 12 nodes and 144 edges. 
# It has a vertex attribute called "name" and an edge attribute called
# "tie_weight".

# Plot the network
# Set the seed for reproducibility (more on this below)
set.seed(221)
# plot
plot(graph)

# The plot() function is extremely flexible. We can set vertex 
# parameters (size, color etc.), edge parameters (width, color, line type etc.), 
# label parameters (font, color, size), vertex layout, and more. See 
# http://igraph.org/r/doc/plot.common.html for details.

# For example, let's plot with smaller arrows and labels for more clarity.
# Set the seed for reproducibility (more on this below).
set.seed(221)
# Plot
plot(graph, edge.arrow.size=0.5, vertex.label.cex=0.5)

# Let's now also import vertex attributes
(vert.attr <- read_csv("./Data/class_attributes.csv"))
## # A tibble: 12 × 4
##    name     age grade sex  
##    <chr>  <dbl> <dbl> <chr>
##  1 Amber     23    70 F    
##  2 Beth      35    85 F    
##  3 David     22   100 M    
##  4 Jim       26    95 M    
##  5 Jose      30    90 M    
##  6 Kent      23    75 M    
##  7 Lem       32    95 M    
##  8 Maria     25    80 F    
##  9 Mark      24    80 M    
## 10 Randy     26   100 M    
## 11 Sofia     26    97 F    
## 12 Thomas    23    92 M
# The same function we used above can import vertex attributes together with edge data.
graph <- graph_from_data_frame(d= elist, vertices= vert.attr)

# The igraph object now includes vertex attributes
graph
## IGRAPH 4ae9416 DN-- 12 44 -- 
## + attr: name (v/c), age (v/n), grade (v/n), sex (v/c), tie_weight (e/n)
## + edges from 4ae9416 (vertex names):
##  [1] David->Sofia  David->Maria  David->Lem    David->Beth   David->Mark  
##  [6] David->Amber  Sofia->David  Sofia->Maria  Sofia->Beth   Sofia->Amber 
## [11] Maria->David  Maria->Sofia  Maria->Lem    Maria->Beth   Maria->Amber 
## [16] Jose ->Sofia  Jose ->Maria  Lem  ->David  Lem  ->Maria  Lem  ->Jim   
## [21] Lem  ->Beth   Lem  ->Amber  Jim  ->Maria  Jim  ->Lem    Jim  ->Beth  
## [26] Jim  ->Amber  Beth ->David  Beth ->Sofia  Beth ->Maria  Beth ->Lem   
## [31] Beth ->Jim    Beth ->Amber  Mark ->David  Mark ->Jose   Mark ->Amber 
## [36] Kent ->Thomas Amber->David  Amber->Sofia  Amber->Maria  Amber->Lem   
## + ... omitted several edges
# Two ways to fix the network layout for visualization.

# 1) Set the same seed before each plot
set.seed(215)
plot(graph, edge.arrow.size=0.5)

# Plot again
set.seed(215)
plot(graph, edge.arrow.size=0.5)

# 2) Calculate network layout matrix separately, and always use that matrix for plot
set.seed(215)
layout.mat.fr <- layout_(graph=graph, layout=with_fr())

# Plot using that layout matrix
plot(graph, layout=layout.mat.fr, edge.arrow.size=0.5)

# Plot again
plot(graph, layout=layout.mat.fr, edge.arrow.size=0.5)

# Plot using different layout algorithms
# As star
set.seed(215)
layout.mat.st <- layout_(graph=graph, layout=as_star())
plot(graph, layout=layout.mat.st, edge.arrow.size=0.5)

# Kamada-kawai
set.seed(215)
layout.mat.kk <- layout_(graph=graph, layout=with_kk())
plot(graph, layout=layout.mat.kk, edge.arrow.size=0.5)

# You can use any matrix (with 2 columns and N rows, N being the number of
# vertices) for the graph layout, e.g. a matrix with spatial coordinates.

# More information on layout functions: http://igraph.org/r/doc/layout_.html

# A layout matrix can be set as the "default" layout matrix for a 
# graph, by setting it as a graph attribute called "layout". If we do that, 
# plot() will always (silently) use that matrix as graph's layout.
graph$layout <- layout.mat.kk 

# Now we don't need to set the "layout" argument any more.
plot(graph, edge.arrow.size=0.5)

# To export the plot to an external file, use png() or pdf()
pdf("graph_kk.pdf")
plot(graph)
dev.off()
## quartz_off_screen 
##                 2
# Plot with ggraph and ggplot2 grammar
ggraph(graph) + 
  # Draw edges
  geom_edge_link(
    # Specify arrow size
    arrow = arrow(length = unit(2, 'mm')),
    # Distance between edge end and node
    end_cap = circle(3, 'mm'),
    # Distance between edge start and node
    start_cap = circle(3, 'mm')) + 
  # Draw nodes
  geom_node_point(color= "blue", fill = "lightblue", shape = 21, size=5) + 
  # Draw node labels (names)
  geom_node_text(aes(label = name), color= "black", size=3) + 
  # Theme details
  theme_graph(base_family = 'Helvetica')

2 Network objects and attributes

  • Vertex and edge attributes.
  • Use vertex and edge attributes to analyze network composition.
  • Use vertex and edge attributes to analyze network structure.
  • Visualize characteristics of network composition and structure.
# Vertex sequence of the graph
V(graph)
## + 12/12 vertices, named, from 4ae9416:
##  [1] Amber  Beth   David  Jim    Jose   Kent   Lem    Maria  Mark   Randy 
## [11] Sofia  Thomas
# Edge sequence of the graph
E(graph)
## + 44/44 edges from 4ae9416 (vertex names):
##  [1] David ->Sofia  David ->Maria  David ->Lem    David ->Beth   David ->Mark  
##  [6] David ->Amber  Sofia ->David  Sofia ->Maria  Sofia ->Beth   Sofia ->Amber 
## [11] Maria ->David  Maria ->Sofia  Maria ->Lem    Maria ->Beth   Maria ->Amber 
## [16] Jose  ->Sofia  Jose  ->Maria  Lem   ->David  Lem   ->Maria  Lem   ->Jim   
## [21] Lem   ->Beth   Lem   ->Amber  Jim   ->Maria  Jim   ->Lem    Jim   ->Beth  
## [26] Jim   ->Amber  Beth  ->David  Beth  ->Sofia  Beth  ->Maria  Beth  ->Lem   
## [31] Beth  ->Jim    Beth  ->Amber  Mark  ->David  Mark  ->Jose   Mark  ->Amber 
## [36] Kent  ->Thomas Amber ->David  Amber ->Sofia  Amber ->Maria  Amber ->Lem   
## [41] Amber ->Jim    Amber ->Beth   Amber ->Mark   Thomas->Kent
# Indexing based on vertex and edge attributes
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

# Extract vertex attribute
V(graph)$age
##  [1] 23 35 22 26 30 23 32 25 24 26 26 23
# A vertex attribute is just a vector that we can re-use for any operation. For
# example: What's the average age in the network?
V(graph)$age %>% 
  mean
## [1] 26.25
# What's its standard deviation?
V(graph)$age %>% 
  sd
## [1] 4.048007
# Battery of descriptive stats using skimr functions
V(graph)$age %>% 
  skimr::skim()
Data summary
Name Piped data
Number of rows 12
Number of columns 1
_______________________
Column type frequency:
numeric 1
________________________
Group variables None

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
data 0 1 26.25 4.05 22 23 25.5 27 35 ▇▆▁▃▂
# What's the distribution of gender in the network?
V(graph)$sex %>% 
  tabyl
##  . n   percent
##  F 4 0.3333333
##  M 8 0.6666667
# Vertex names are a vertex attribute created by default by graph_from_data_frame()
V(graph)$name
##  [1] "Amber"  "Beth"   "David"  "Jim"    "Jose"   "Kent"   "Lem"    "Maria" 
##  [9] "Mark"   "Randy"  "Sofia"  "Thomas"
# Extract edge attribute
E(graph)$tie_weight
##  [1] 2 2 1 3 1 2 1 5 1 2 2 5 1 2 4 1 1 2 2 5 2 2 1 5 5 2 4 3 1 1 5 3 1 1 1 3 2 3
## [39] 3 1 2 2 1 3
# Average tie weight (i.e., strength) in the network
E(graph)$tie_weight %>% 
  mean
## [1] 2.318182
# View female actors
V(graph)[sex=="F"]
## + 4/12 vertices, named, from 4ae9416:
## [1] Amber Beth  Maria Sofia
# View strong ties
E(graph)[tie_weight > 2]
## + 15/44 edges from 4ae9416 (vertex names):
##  [1] David ->Beth   Sofia ->Maria  Maria ->Sofia  Maria ->Amber  Lem   ->Jim   
##  [6] Jim   ->Lem    Jim   ->Beth   Beth  ->David  Beth  ->Sofia  Beth  ->Jim   
## [11] Beth  ->Amber  Kent  ->Thomas Amber ->Sofia  Amber ->Maria  Thomas->Kent
# View age of female actors
V(graph)[sex=="F"]$age
## [1] 23 35 25 26
# Mean age of female actors in the network
V(graph)[sex=="F"]$age %>% 
  mean
## [1] 27.25
# Display actor gender in graph visualization via ggraph
ggraph(graph) + 
  # Draw edges
  geom_edge_link(arrow = arrow(length = unit(2, 'mm')),
    end_cap = circle(3, 'mm'),
    start_cap = circle(3, 'mm')) + 
  # Draw nodes
  geom_node_point(aes(fill= sex), color = "blue", shape = 21, size=5) + 
  # Draw node labels (names)
  geom_node_text(aes(label = name), color= "darkblue", size=3) + 
  # Theme details
  theme_graph(base_family = 'Helvetica')
## Using `stress` as default layout

# Alternative code to plot via igraph

# First plot with uniform blue color
plot(graph, vertex.color= "blue", edge.arrow.size=0.5, 
     vertex.label.cex=0.5, vertex.label.color= "white")

# The color can also be set as a vertex attribute in the graph itself, and the
# plot function will recognize it.
V(graph)$color <- "blue"

# Now the plot function recognizes the vertex attribute "color".
plot(graph, edge.arrow.size=0.5, vertex.label.cex=0.5, vertex.label.color= "white")

# Using indexing, set a different color for female actors
V(graph)[sex=="F"]$color
## [1] "blue" "blue" "blue" "blue"
V(graph)[sex=="F"]$color <- "red"

# Plot again
plot(graph, edge.arrow.size=0.5, vertex.label.cex=0.5, vertex.label.color= "white")

# Indexing based on network structure
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

# View all actors who know Mark
V(graph)[nei("Mark")]
## + 3/12 vertices, named, from 4ae9416:
## [1] Amber David Jose
# View the age of all actors who know Mark.
V(graph)[nei("Mark")]$age
## [1] 23 22 30
# Average age in Mark's first-order neighborhood.
V(graph)[nei("Mark")]$age %>% 
  mean
## [1] 25
# View all edges that are incident on David
E(graph)[inc("David")]
## + 12/44 edges from 4ae9416 (vertex names):
##  [1] David->Sofia David->Maria David->Lem   David->Beth  David->Mark 
##  [6] David->Amber Sofia->David Maria->David Lem  ->David Beth ->David
## [11] Mark ->David Amber->David
# All edges "to" David
E(graph)[to("David")]
## + 6/44 edges from 4ae9416 (vertex names):
## [1] Sofia->David Maria->David Lem  ->David Beth ->David Mark ->David
## [6] Amber->David
# View the strength of these edges
E(graph)[to("David")]$tie_weight
## [1] 1 2 2 4 1 2
# Average strength of all incoming edges to David
E(graph)[to("David")]$tie_weight %>% 
  mean
## [1] 2
# View all edges to David whose tie_weight is ==2
E(graph)[to("David") & tie_weight==2]
## + 3/44 edges from 4ae9416 (vertex names):
## [1] Maria->David Lem  ->David Amber->David
# View all edges between women in the network.
# First get the vertex sequence of all women
women <- V(graph)[sex=="F"]
women
## + 4/12 vertices, named, from 4ae9416:
## [1] Amber Beth  Maria Sofia
# Then get the edges among them.
E(graph)[women %--% women]
## + 12/44 edges from 4ae9416 (vertex names):
##  [1] Sofia->Maria Sofia->Beth  Sofia->Amber Maria->Sofia Maria->Beth 
##  [6] Maria->Amber Beth ->Sofia Beth ->Maria Beth ->Amber Amber->Sofia
## [11] Amber->Maria Amber->Beth
# Are there more edges among women or among men?
# Number of edges among women
E(graph)[women %--% women] %>% length
## [1] 12
# Number of edges among men
men <- V(graph)[sex=="M"]
E(graph)[men %--% men] %>% length
## [1] 9
# What is the strength of ties among women?
E(graph)[women %--% women]$tie_weight
##  [1] 5 1 2 5 2 4 3 1 3 3 3 2
# Compare the distribution of tie strength among women vs among men
E(graph)[women %--% women]$tie_weight %>% 
  tabyl
##  . n    percent
##  1 2 0.16666667
##  2 3 0.25000000
##  3 4 0.33333333
##  4 1 0.08333333
##  5 2 0.16666667
E(graph)[men %--% men]$tie_weight %>% 
  tabyl
##  . n   percent
##  1 4 0.4444444
##  2 1 0.1111111
##  3 2 0.2222222
##  5 2 0.2222222
# Example of plot combining igraph and ggraph to highlight structural features
# of the network

# Create vertex attribute to flag nodes that are adjacent to Mark
V(graph)$nei.mark <- "No"
V(graph)[nei("Mark")]$nei.mark <- "Yes"

# Create edge attribute to flag edges that are incident on Mark
E(graph)$inc.mark <- "No"
E(graph)[inc("Mark")]$inc.mark <- "Yes"

# Create vertex attribute with vertex degree
V(graph)$degree <- degree(graph)

# Plot
ggraph(graph) + 
  # Draw edges
  geom_edge_link(end_cap = circle(3, 'mm'),
                 start_cap = circle(3, 'mm'),
                 # For edge transparency
                 alpha = 0.7,
                 # Edge width as tie weight
                 aes(width = tie_weight, 
                     # Edge color indicates if edge is incident on Mark
                     color = inc.mark)) + 
  # Draw nodes
  geom_node_point(
    # Node fill indicates whether node is adjacent to Mark
    aes(fill= nei.mark, 
        # Node size is degree
        size = degree), 
                  shape= 21, 
                  color = "blue") + 
  # Draw node labels (names)
  geom_node_text(aes(label = name), color= "darkblue", size=3) + 
  # Theme details
  theme_graph(base_family = 'Helvetica')
## Using `stress` as default layout

3 Example of network measures: centrality

  • Import network data from external adjacency matrix.
  • Calculate and analyze centrality measures.
  • Visualize centrality in network plots.
# Read in the campnet network adjacency matrix
campnet.adj <- read_csv(file="./Data/campnet_adj.csv") %>%
        # Remove first column (node names, they're already stored as column names)
        dplyr::select(-1) %>%
        # Convert to matrix
        as.matrix
## New names:
## * `` -> ...1
## Rows: 18 Columns: 19
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr  (1): ...1
## dbl (18): ANN, BERT, BILL, BRAZEY, CAROL, DON, GERY, HARRY, HOLLY, JENNIE, J...
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Import into directed graph 
camp <- graph_from_adjacency_matrix(campnet.adj, 
                                    mode="directed",
                                    # To use matrix column names as "name" vertex attribute in igraph
                                    add.colnames = NULL)

# Read in the vertex attributes
(campnet.attr <- read_csv(file="./Data/campattr.csv"))
## Rows: 18 Columns: 3
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (3): id, Gender, Role
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
## # A tibble: 18 × 3
##    id      Gender Role   
##    <chr>   <chr>  <chr>  
##  1 ANN     female student
##  2 BERT    male   prof   
##  3 BILL    male   student
##  4 BRAZEY  female student
##  5 CAROL   female student
##  6 DON     male   student
##  7 GERY    male   prof   
##  8 HARRY   male   student
##  9 HOLLY   female student
## 10 JENNIE  female student
## 11 JOHN    male   student
## 12 LEE     male   student
## 13 MICHAEL male   student
## 14 PAM     female student
## 15 PAT     female student
## 16 PAULINE female student
## 17 RUSS    male   prof   
## 18 STEVE   male   prof
# Note that actors in the graph are in the same order as actors in the attribute
# data frame.
V(camp)
## + 18/18 vertices, named, from 5a7c297:
##  [1] ANN     BERT    BILL    BRAZEY  CAROL   DON     GERY    HARRY   HOLLY  
## [10] JENNIE  JOHN    LEE     MICHAEL PAM     PAT     PAULINE RUSS    STEVE
campnet.attr$id
##  [1] "ANN"     "BERT"    "BILL"    "BRAZEY"  "CAROL"   "DON"     "GERY"   
##  [8] "HARRY"   "HOLLY"   "JENNIE"  "JOHN"    "LEE"     "MICHAEL" "PAM"    
## [15] "PAT"     "PAULINE" "RUSS"    "STEVE"
# So we can simply set the columns from the attribute data frame as vertex 
# attributes (because the order is the same, no merge is needed)
V(camp)$Gender <- campnet.attr$Gender
V(camp)$Role <- campnet.attr$Role

# Let's print the graph
camp
## IGRAPH 5a7c297 DN-- 18 54 -- 
## + attr: name (v/c), Gender (v/c), Role (v/c)
## + edges from 5a7c297 (vertex names):
##  [1] ANN   ->JENNIE  ANN   ->PAM     ANN   ->PAULINE BERT  ->LEE    
##  [5] BERT  ->RUSS    BERT  ->STEVE   BILL  ->DON     BILL  ->HARRY  
##  [9] BILL  ->MICHAEL BRAZEY->BERT    BRAZEY->LEE     BRAZEY->STEVE  
## [13] CAROL ->PAM     CAROL ->PAT     CAROL ->PAULINE DON   ->HARRY  
## [17] DON   ->HOLLY   DON   ->MICHAEL GERY  ->MICHAEL GERY  ->RUSS   
## [21] GERY  ->STEVE   HARRY ->DON     HARRY ->HOLLY   HARRY ->MICHAEL
## [25] HOLLY ->DON     HOLLY ->PAM     HOLLY ->PAT     JENNIE->ANN    
## [29] JENNIE->PAM     JENNIE->PAT     JOHN  ->GERY    JOHN  ->PAULINE
## + ... omitted several edges
# Plot it.
# Calculate layout and set as layout attribute of graph.
set.seed(219)
camp$layout <- layout_(graph=camp, layout=with_kk())
# Plot the graph.
plot(camp, edge.arrow.size=0.1, vertex.label.cex=0.5)

# Calculate indegree
(camp.deg <- degree(camp, mode= "in"))
##     ANN    BERT    BILL  BRAZEY   CAROL     DON    GERY   HARRY   HOLLY  JENNIE 
##       2       4       0       1       2       4       2       3       4       3 
##    JOHN     LEE MICHAEL     PAM     PAT PAULINE    RUSS   STEVE 
##       0       3       4       5       4       4       4       5
# Note that the result is simply a numeric vector
# It's a *named* numeric vector, where igraph vertex names are stored as 
# vector names
names(camp.deg)
##  [1] "ANN"     "BERT"    "BILL"    "BRAZEY"  "CAROL"   "DON"     "GERY"   
##  [8] "HARRY"   "HOLLY"   "JENNIE"  "JOHN"    "LEE"     "MICHAEL" "PAM"    
## [15] "PAT"     "PAULINE" "RUSS"    "STEVE"
# With tidyverse (enframe), we can convert this indegree vector to data frame
# and set the indegree variable name
camp.deg <- degree(camp, mode= "in") %>%
        enframe(value = "indegree")

# View result
camp.deg
## # A tibble: 18 × 2
##    name    indegree
##    <chr>      <dbl>
##  1 ANN            2
##  2 BERT           4
##  3 BILL           0
##  4 BRAZEY         1
##  5 CAROL          2
##  6 DON            4
##  7 GERY           2
##  8 HARRY          3
##  9 HOLLY          4
## 10 JENNIE         3
## 11 JOHN           0
## 12 LEE            3
## 13 MICHAEL        4
## 14 PAM            5
## 15 PAT            4
## 16 PAULINE        4
## 17 RUSS           4
## 18 STEVE          5
# Betweenness, directed
camp.bet.dir <- betweenness(camp, directed = TRUE) %>%
        enframe(value = "betw.dir")

# Betweenness, undirected
camp.bet.undir <- betweenness(camp, directed = FALSE) %>%
        enframe(value = "betw.undir")

# Closeness, undirected
camp.clos.undir <- closeness(camp, mode="all") %>%
        enframe(value = "clos.undir")

# Let's create a data frame with all centrality values.
# Start with degree data frame
camp.centr <- camp.deg %>%
  # Join with directed betweenness data frame
  left_join(camp.bet.dir, by = "name") %>%
  # Join with undirected betweenness data frame
  left_join(camp.bet.undir, by = "name") %>%
  # Join with closeness data frame
  left_join(camp.clos.undir, by = "name") 

camp.centr
## # A tibble: 18 × 5
##    name    indegree betw.dir betw.undir clos.undir
##    <chr>      <dbl>    <dbl>      <dbl>      <dbl>
##  1 ANN            2     0.5        1.78     0.0208
##  2 BERT           4    13.7        6.19     0.0196
##  3 BILL           0     0          0        0.02  
##  4 BRAZEY         1     0          0        0.0169
##  5 CAROL          2     1.33       0.2      0.0208
##  6 DON            4    16.3        3.47     0.0233
##  7 GERY           2    54.7       35.9      0.0278
##  8 HARRY          3     2.33       1.74     0.0233
##  9 HOLLY          4    78.3       27.1      0.0263
## 10 JENNIE         3     6.33       1.2      0.0182
## 11 JOHN           0     0         33.1      0.0263
## 12 LEE            3     5          0        0.0169
## 13 MICHAEL        4    58.8       32.2      0.0278
## 14 PAM            5    32.5       15.1      0.0238
## 15 PAT            4    39.5       13.1      0.0233
## 16 PAULINE        4    12.5       33.5      0.025 
## 17 RUSS           4    47.3       25.6      0.025 
## 18 STEVE          5    16.8       23.8      0.0222
# Create histogram of degree centrality using ggplot2
ggplot(data= camp.centr, aes(x=indegree)) + 
        geom_histogram(binwidth = 1, color= "black")

# Plot network with nodes sized by centrality

# Create indegree attribute
V(camp)$indegree <- degree(camp, mode= "in")
  
# Plot
ggraph(camp) + 
  # Draw edges
  geom_edge_link(end_cap = circle(3, 'mm'),
                 start_cap = circle(3, 'mm')) + 
  # Draw nodes
  geom_node_point(
    # Node fill indicates whether node is adjacent to Mark
    aes(size = indegree), 
    shape= 21, 
    fill = "lightblue",
    color = "blue") + 
  # Draw node labels (names)
  geom_node_text(aes(label = name), color= "darkblue", size=3) + 
  # Theme details
  theme_graph(base_family = 'Helvetica')
## Using `stress` as default layout

# Same for betweenness: but now use both node size and color to visualize 
# centrality
V(camp)$betw <- betweenness(camp, directed = FALSE)

# Plot
ggraph(camp) + 
  # Draw edges
  geom_edge_link(end_cap = circle(3, 'mm'),
                 start_cap = circle(3, 'mm')) + 
  # Draw nodes
  geom_node_point(
    aes(size = betw, color = betw)) + 
  # Draw node labels (names)
  geom_node_text(aes(label = name), color= "darkblue", size=3) + 
  # Theme details
  theme_graph(base_family = 'Helvetica')
## Using `stress` as default layout

# Plot with size = betweenness, color = role, shape = gender
ggraph(camp) + 
  # Draw edges
  geom_edge_link(end_cap = circle(3, 'mm'),
                 start_cap = circle(3, 'mm')) + 
  # Draw nodes
  geom_node_point(
    # Node size, color, shape
    aes(size = betw, color = Role, shape = Gender)) + 
  # Draw node labels (names)
  geom_node_text(aes(label = name), color= "darkblue", size=3) + 
  # Theme details
  theme_graph(base_family = 'Helvetica')
## Using `stress` as default layout