How to unite two graphs in R to form a multilayer network?

993 views Asked by At

Could you please help me?

I work with ecological interactions, and some of them are modeled as multilayer networks (multiplex, to be precise).

The best way to input this kind of data into R's package igraph is by using edge and node lists. Unfortunately, my collaborators never have their data organized like that, but rather as incidence matrices (bipartite networks).

I always ask them to at least have those matrices organized precisely with the same dimensions and the same order of row and column labels, so they can be easily combined.

Having those matrices at hand, I then run a long code based on the following steps:

  1. Read two or more incidence matrices into R;

  2. Extract their edge and vertex lists;

  3. Add information on edge type to each edge list;

  4. Add information on vertex class to each vertex list;

  5. Merge those edge lists and vertex lists separately;

  6. Read those merged lists into igraph to create a multilayer graph.

I'm looking for a simpler solution. I've tried using the function union, but it merges the graphs and their edges without keeping information on edge types. See what happens in this example with random matrices:

number <- seq(1:10)

row <- "row"
rowlabels <- paste(row, number, sep = "")
column <- "col"
columnlabels <- paste(column, number, sep = "")

matrix1 <- matrix(data = rbinom(100,size=1,prob=0.5), nrow = 10, ncol = 10,
                  dimnames = list(rowlabels, columnlabels))
matrix2 <- matrix(data = rbinom(100,size=1,prob=0.5), nrow = 10, ncol = 10,
                  dimnames = list(rowlabels, columnlabels))
      
graph1 <- graph_from_incidence_matrix(matrix1, directed = F)
graph2 <- graph_from_incidence_matrix(matrix2, directed = F)
       
E(graph1)$type = "layer1"
E(graph2)$type = "layer2"
    
graph_multi <- union(graph1, graph2)
graph_multi
E(graph_multi)$type

Is there an easier way to combine two or more incidence matrices to make a multilayer graph in igraph?

Thank you very much!

1

There are 1 answers

3
Michał On BEST ANSWER

I would convert the data to data frames, combine to a single edgelist and make the graph in the final step. Something like the following:

set.seed(666)
number <- seq(1:10)
row <- "row"
rowlabels <- paste(row, number, sep = "")
column <- "col"
columnlabels <- paste(column, number, sep = "")
matrix1 <- matrix(data = rbinom(100,size=1,prob=0.5), nrow = 10, ncol = 10,
                  dimnames = list(rowlabels, columnlabels))
matrix2 <- matrix(data = rbinom(100,size=1,prob=0.5), nrow = 10, ncol = 10,
                  dimnames = list(rowlabels, columnlabels))


library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
library(igraph)
#> 
#> Attaching package: 'igraph'
#> The following objects are masked from 'package:dplyr':
#> 
#>     as_data_frame, groups, union
#> The following objects are masked from 'package:stats':
#> 
#>     decompose, spectrum
#> The following object is masked from 'package:base':
#> 
#>     union

edb <- bind_rows(
  as.data.frame(as.table(matrix1)),
  as.data.frame(as.table(matrix2)),
  .id = "layer"
) %>%
  filter(Freq != 0) %>%
  select(
    from = Var1,
    to = Var2,
    layer
  )

# from, to, layer
head(edb)
#>   from   to layer
#> 1 row1 col1     1
#> 2 row3 col1     1
#> 3 row6 col1     1
#> 4 row7 col1     1
#> 5 row1 col2     1
#> 6 row6 col2     1

multig <- graph_from_data_frame(edb, directed=FALSE)
multig
#> IGRAPH c377bd8 UN-- 20 110 -- 
#> + attr: name (v/c), layer (e/c)
#> + edges from c377bd8 (vertex names):
#>  [1] row1 --col1 row3 --col1 row6 --col1 row7 --col1 row1 --col2 row6 --col2
#>  [7] row8 --col2 row1 --col3 row2 --col3 row5 --col3 row8 --col3 row9 --col3
#> [13] row10--col3 row3 --col4 row4 --col4 row5 --col4 row8 --col4 row9 --col4
#> [19] row10--col4 row2 --col5 row4 --col5 row5 --col5 row6 --col5 row8 --col5
#> [25] row9 --col5 row10--col5 row4 --col6 row6 --col6 row8 --col6 row1 --col7
#> [31] row2 --col7 row4 --col7 row5 --col7 row8 --col7 row9 --col7 row10--col7
#> [37] row1 --col8 row3 --col8 row4 --col8 row6 --col8 row7 --col8 row9 --col8
#> [43] row10--col8 row1 --col9 row2 --col9 row4 --col9 row6 --col9 row7 --col9
#> + ... omitted several edges

table(E(multig)$layer)
#> 
#>  1  2 
#> 55 55