### "ENSb1315 Network analysis: social, ecological, and social-ecological approaches" ###
# Lecture: network analysis in R (first steps)
# Author: Harald Waxenecker
# Date: March 1, 2024



##### 1. First steps #####

# numeric vector
1
1+1

i <- 1
i+i

n <- i+i
class(n)

semester <- c(5,6,2,1)


# character vector

k <- "milagro"
class(m)

names <- c("Anna", "Šarka", "Kristína", "Petr")


# data frame

our.data <- data.frame(Names = names,
                       Semester = semester)


View(our.data)


# functions

sum(semester)
mean(semester)

n <- mean(semester)
p <- mean(our.data$Semester)





##### 2. Creating graphs #####


# Let´s start with networks:
# First, we need to install a package. For this lab, we will the package "igraph".
# There are more packages for network analysis, e.g.: sna, networks, etc.

install.packages("igraph")
library(igraph) 

# Manual and insights are available at:
# http://cran.r-project.org/web/packages/igraph/igraph.pdf
# https://igraph.org




# Creating stylized graphs in igraph
### 1. Create a random graph.  

n <- 20 ## number of nodes in your graph 
p <- 0.1 ## the probability of forming a tie 

# Create an Erdős-Rényi random graph 

random_graph <- erdos.renyi.game(n, p, directed = TRUE) 


## I've specified that I want the network to be directed (so asymmetric network data). 
# This will enable us to calculate in and out degrees.

# Let's just look at the random_graph igraph object to see what it looks like.

class(random_graph)
random_graph

# You will see that this is a specific kind of igraph graph - and Erdos-Renyi random graph. 
# Paul Erdos and Alfred Renyi are well known names in graph theory and the field of 
# network analysis. If you are curious about this history, you can read a bit more here: 
# https://en.wikipedia.org/wiki/Erd%C5%91s%E2%80%93R%C3%A9nyi_model

plot(random_graph)

plot(random_graph, 
     edge.arrow.size = 0.25,
     vertex.size = 8, 
     vertex.label.cex = 0.7,
     main = "Random Directed One-Mode Network")


# We give some names to our nodes, by assign letters to nodes
V(random_graph)$name <- LETTERS[1:n]

plot(random_graph, 
     vertex.label = V(random_graph)$name,
     edge.arrow.size = 0.25,
     vertex.size = 8, 
     vertex.label.cex = 0.7,
     main = "Random Directed One-Mode Network")





### 2. Create a small-world graph

# Remember what a small-world graph is? A graph that has a short average path length, 
# yet highly clustered. In our case, it is also symmetric (no directed).

#  Set the number of nodes in the small-world graph  
n <- 20

# Set the initial number of neighbors (k) for each node
k <- 2

# Set the probability (p) of rewiring edges
p <- 0.1

# Generate a small-world graph using the Watts-Strogatz model
small_world_graph <- watts.strogatz.game(dim = 1, n, k, p)

# Plot the small-world graph
plot(small_world_graph,
     vertex.size = 8, 
     vertex.label.cex = 0.7,
     layout = layout_in_circle,  # Circular layout
     main = "Small-World Network")  # Add main title


# Quick overview: https://en.wikipedia.org/wiki/Small-world_network




### 3. Create a scale-free graph

# Generate a scale-free graph using the Barabási-Albert model
scale_free_graph <- barabasi.game(n = 20, directed = FALSE)

# Plot the scale-free graph
plot(scale_free_graph, 
     vertex.size = 8, 
     vertex.label.cex = 0.7,
     layout = layout_with_fr,  # Fruchterman-Reingold layout
     main = "Undirected Scale-Free Network")  # Add main title


# Quick overview: https://en.wikipedia.org/wiki/Barabási–Albert_model



##### 3. Describing our networks #####

# Some 'topological characteristics' of our graphs

# Which graph has the highest density?
graph.density(random_graph)
graph.density(small_world_graph)
graph.density(scale_free_graph)


# Let´s work with our random graph:
vcount(random_graph)
ecount(random_graph)
graph.density(random_graph)
count_components(random_graph)


plot(random_graph, 
     vertex.label = V(random_graph)$name,
     edge.arrow.size = 0.25,
     vertex.size = 8, 
     vertex.label.cex = 0.7,
     main = "Random Directed One-Mode Network")

# Add legend
legend("bottomleft",
       legend = c(paste("Nodes:", vcount(random_graph)),
                  paste("Edges:", ecount(random_graph)),
                  paste("Density:", round(graph.density(random_graph),2)),
                  paste("Components:", count_components(random_graph))),
       bty = "n")



##### 4. Centrality measures #####

# In lecture, we discussed a number of analyses you can conduct to gain information 
# on how an actor in a network is positioned in that network, as well as other 
# characteristics pertaining to that actor's social network 'profile'. 

# Here we will conduct centrality analyses: indegree, outdegree, degree, 
# betweenness and eigenvector

# One thing to keep in mind: in many of these instances, you will notice that 
# calculating a particular network measure (or score) for an individual actor 
# (so assigning a network 'attribute' to an actor) is based on the wider network 
# structure, i.e. its topology. 

# Some of these calculations (e.g. centrality measures) can be plotted in such 
# a way so as to give an indication of the topology (overall network structure).


# Let´s use here our directed random graph:

deg <- degree(random_graph, mode = "all")
indeg <- degree(random_graph, mode = "in")
outdeg <- degree(random_graph, mode = "out")

# Calculate betweenness centrality
bet <- betweenness(random_graph, normalized = TRUE)
round_bet <- round(bet, 2)
# Calculate eigenvector centrality
eig <- eigen_centrality(random_graph, directed = T)
round_eig <- round(eig$vector,2)

# Print the centrality measures
cat("Degree Centrality:", deg, "\n")
cat("Indegree Centrality:", indeg, "\n")
cat("Outdegree Centrality:", outdeg, "\n")
cat("Betweenness Centrality:", round_bet, "\n")
cat("Eigenvector Centrality:", round_eig, "\n")


# If you wish to export these outputs as a table, you can use this kind of code:
centralities <- data.frame(Node = V(random_graph)$name, 
                    Degree = deg,
                    Indegree = indeg,
                    Outdegree = outdeg,
                    Betweenness = round_bet,
                    Eigenvector = round_eig)

View(centralities)

write.csv(centralities, file = "centralities.csv", row.names = FALSE)


# Using betweenness for the node size

plot(random_graph, 
     vertex.label = V(random_graph)$name,
     edge.arrow.size = 0.25,
     vertex.size = round_bet*100+4, 
     vertex.label.cex = 0.7,
     main = "Random Directed One-Mode Network")

# Add legend
legend("bottomleft",
       legend = c(paste("Nodes:", vcount(random_graph)),
                  paste("Edges:", ecount(random_graph)),
                  paste("Density:", round(graph.density(random_graph),2))),
       bty = "n")



# Centrality distributions:
# Let's consider the centrality distributions a bit more by plotting them as histograms:

# Histogram for degree centrality
table(deg)

hist(deg, breaks = seq(min(deg)-0.5, max(deg)+0.5, by = 1),
     col = "#93C64A", border = "black",
     xlab = "Distribution of Degree Centralities",           # Label for x-axis
     ylab = "Frequency",                                     # Label for y-axis
     main = "Degree Distribution")                           # Title of the plot

# Histogram for indegree centrality
table(indeg)

hist(indeg, breaks = seq(min(indeg)-0.5, max(indeg)+0.5, by = 1),
     col = "#93C64A", border = "black",
     xlab = "Distribution of Indegree Centralities",           # Label for x-axis
     ylab = "Frequency",                                     # Label for y-axis
     main = "Indegree Distribution")                           # Title of the plot



# Histogram for outdegree centrality
table(outdeg)

hist(outdeg, breaks = seq(min(outdeg)-0.5, max(outdeg)+0.5, by = 1),
     col = "#93C64A", border = "black",
     xlab = "Distribution of Degree Centralities",           # Label for x-axis
     ylab = "Frequency",                                     # Label for y-axis
     main = "Degree Distribution")                           # Title of the plot





##### 5. Exercising #####

# Exercise 1
# Please, create a sparse and undirected random graph with 150 nodes. Then, 
# create a plot, and describe some topological characteristics of the graph.


# Exercise 2
# Please, create a directed random network with 10 nodes. Give some names 
# to the nodes, by assign letters to nodes. Calculate different 
# node centralities and export these outputs as a table.


# Exercise 3
# Please, can you provide an example of how network analysis could be applied in 
# your field of study?











