This vignette walks through a simple analysis shown in the paper The spring bounces back (arXiv:2007.09437), using 5 network classes known as Peels quintet (Peel et al 2018 doi.org/10.1073/pnas.1713019115). The purpose of the vignette is to show you how to go from a collection of networks to a plot summarising their final embeddings.
The first block, shown below, loads all the necessary packages. use install.packages()
if any of the packages are not installed on your machine.
library(rsetse)
library(dplyr)
library(tidyr)
library(ggplot2)
library(purrr)
library(ggraph)
library(igraph)
Anscombe’s quartet which showed that figures that were visually very different could have almost identical correlation and other summary statistics. Peels quintet is the graph equivalent of Anscombe’s quartet but for graph/networks. The networks in Peel’s quintet have two groups of nodes which are broken up into two subgroups. All the networks have the same number of node, edges, connections within and between groups. However, the connections between subgroups change producing very different networks even though they appear identical using traditional network metrics (for more information see the paper by Peel et al).
the rSETSe
package has a function that generates each of the 5 types of Peels network. The code chunk below shows 1 example of each class of the quintet starting with type A on the left and ending with type E on the right. It is clear that networks
#This is a bit of a contorted way to get 5 networks into the same plot as
#igraph::union does not also merge attributes
set.seed(1263)
<- 1:5 %>%
peels_networks map(~generate_peels_network(LETTERS[.x]) %>%
#The nodes in all the networks are numbered 1:40, this line ensures
#each class has distinct node names
set.vertex.attribute(., "type", value = paste("type", LETTERS[.x])) %>%
set.vertex.attribute(., "name",
value = as.numeric(get.vertex.attribute(., "name"))+(.x-1)*40) %>%
#The networks are going to be joined into a single network so need to be converted into a
#list of dataframes
::as_data_frame(., what = "both")
igraph%>%
) #the list is now two elements long and made up of a edge and vertex part
transpose() %>%
#join the elements from each part of the list into dataframes
map(~bind_rows(.x)) %>%
graph_from_data_frame(d = .$edges, directed = FALSE, vertices = .$vertices)}
{
ggraph(peels_networks) +
geom_edge_fan()+
geom_node_point(aes(fill = class, shape = grepl("1", sub_class)), size=3) +
scale_shape_manual(values=c(21, 24)) +
guides(fill = "none", shape = "none") +
facet_nodes(~type, scale = "free")
# Creating lots of networks
First we will generate 10 examples of each class of the Peel’s quintet.
set.seed(4563)
<- LETTERS[1:5] %>% map(~{
all_peels
<- .x
peel_type
<- 1:10 %>% map(~{
out
generate_peels_network(peel_type)
})
})
#Embedding lists of networks
Then we will embed all graphs in the list using setse_auto, however before the graph can be embedded they need to be prepared for setse using one of the setse preparation functions prepare_categorical_force
or prepare_continuous_force
. The prime purpose of these functions make ensure that the force variable has a mean of 0, creates a spring constant k if necessary, creates the node distance variable. As the Peel’s quintet is a network of two node classes A and B we will use prepare_categorical_force
.
Once the networks have been prepared they can be embedded. After embedding the graph type and id number is added on to the embeddings data to ensure we catagorise the graph easily.
#The first map cycles though each of the graph types from A to E
<- 1:5 %>% map(~{
all_embeddings
<- all_peels[[.x]]
temp_list
= LETTERS[.x]
node_type #The inner map embeds each of the 10 networks of that type
<- 1:10 %>%
out map(~{
<- .x
id_number <- temp_list[[.x]]
g <-g%>%
embeddings_data #standard edge preparation is fine as k is included in the dataset
prepare_edges() %>%
#k has already been generated by the generate_peels_network function
prepare_categorical_force(., node_names = "name",
force_var = "class") %>%
#The system is considered converged when the static force is 1/10000 of
#absolute sum of the force exerted by all the nodes
setse_auto(force = "class_A", tol = sum(abs(vertex_attr(., "class_A")))/10000)
#create the aggregated node details
#embeddings_data$node_details <- create_node_details(g, embeddings_data)
$node_details <- create_node_edge_df( embeddings_data)
embeddings_data
<- names(embeddings_data)
element_names #add the id data onto each df in the list
<- 1:length(embeddings_data) %>%
embeddings_data map(~embeddings_data[[.x]] %>% mutate(type = node_type,
id = id_number))
names(embeddings_data) <- element_names
return(embeddings_data)
})
return(out)
})
#the list of embedding networks is then transposed and all the dataframes
#representing the networks are made into a list of 5 dataframes using bind_rows
<-all_embeddings %>%
all_embeddings flatten() %>%
transpose() %>%
map(bind_rows)
aggregate the node level details up to whole graph level and plot the results
$node_details %>%
all_embeddingsgroup_by(type, id) %>%
summarise(mean_tension = mean(tension_mean),
elevation = sum(abs(elevation))) %>%
ggplot(aes(x = mean_tension, y = elevation , colour = type)) + geom_point()
We can see that the networks in peels quintet are clearly distinguishable using SETSe.