Search code examples
rdataframeigraphtibble

R, Igraph: convert edges to tibble or data frame


I must be drowning in a cup of tea, but at the same time I have been banging my head against the wall for hours. Please have a look at the reprex below where I generate an igraph graph object g and I collect the edges stemming from some vertices into an object called dd. My goal is to convert to convert dd into a dataframe or a tibble but the most obvious methods (as_data_frame and as_tibble) fail completely. Can anyone help me out?

Many thanks

library(tidyverse)
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:purrr':
#> 
#>     compose, simplify
#> The following object is masked from 'package:tidyr':
#> 
#>     crossing
#> The following object is masked from 'package:tibble':
#> 
#>     as_data_frame
#> The following objects are masked from 'package:stats':
#> 
#>     decompose, spectrum
#> The following object is masked from 'package:base':
#> 
#>     union

g <- make_ring(10)


dd <- E(g)[from(1:4)]

## this does not work

dd%>%as_tibble
#> Error in as.data.frame.default(value, stringsAsFactors = FALSE): cannot coerce class '"igraph.es"' to a data.frame

## neither this

dd%>%as_data_frame
#> Error in as_data_frame(.): Not a graph object

## so what to do?

Created on 2021-07-31 by the reprex package (v2.0.0)


Solution

  • You have extracted edge identifiers from the graph-object. Now you need to understand how the graphs and edges are represented. So use the plot and str commands to examine the details of the g and dd objects:

    > g <- make_ring(10)
    > plot(g)
    > dd <- E(g)[from(1:4)]
    > dd
    + 5/10 edges from 96250aa:
    [1] 1-- 2 2-- 3 3-- 4 4-- 5 1--10
    > str(dd)
     'igraph.es' int [1:5] 1 2 3 4 10   # so it's really just a numeric vector
     - attr(*, "env")=<weakref> 
     - attr(*, "graph")= chr "96250aab-d2ab-43aa-882d-6ef695323b0a"
    > help(pack=igraph)
    > as_edgelist(g)
          [,1] [,2]     # whereas the original graph (list) converts to two columns
     [1,]    1    2
     [2,]    2    3
     [3,]    3    4
     [4,]    4    5
     [5,]    5    6
     [6,]    6    7
     [7,]    7    8
     [8,]    8    9
     [9,]    9   10
    [10,]    1   10
    > as_edgelist(dd)
    Error in as_edgelist(dd) : Not a graph object
    

    After looking at the results I opened the igraph help index and noted a function named as_ids that was described as: "Convert a vertex or edge sequence to an ordinary vector"

    > as_ids(dd)
    [1]  1  2  3  4 10
    > str(g)
    List of 10
     $ :List of 1
      ..$ : 'igraph.vs' int [1:2] 2 10
      .. ..- attr(*, "env")=<weakref> 
      .. ..- attr(*, "graph")= chr "96250aab-d2ab-43aa-882d-6ef695323b0a"
     $ :List of 1
      ..$ : 'igraph.vs' int [1:2] 1 3
      .. ..- attr(*, "env")=<weakref> 
      .. ..- attr(*, "graph")= chr "96250aab-d2ab-43aa-882d-6ef695323b0a"
     $ :List of 1
      ..$ : 'igraph.vs' int [1:2] 2 4
      .. ..- attr(*, "env")=<weakref> 
      .. ..- attr(*, "graph")= chr "96250aab-d2ab-43aa-882d-6ef695323b0a"
     $ :List of 1
      ..$ : 'igraph.vs' int [1:2] 3 5
      .. ..- attr(*, "env")=<weakref> 
      .. ..- attr(*, "graph")= chr "96250aab-d2ab-43aa-882d-6ef695323b0a"
     $ :List of 1
      ..$ : 'igraph.vs' int [1:2] 4 6
      .. ..- attr(*, "env")=<weakref> 
      .. ..- attr(*, "graph")= chr "96250aab-d2ab-43aa-882d-6ef695323b0a"
     $ :List of 1
      ..$ : 'igraph.vs' int [1:2] 5 7
      .. ..- attr(*, "env")=<weakref> 
      .. ..- attr(*, "graph")= chr "96250aab-d2ab-43aa-882d-6ef695323b0a"
     $ :List of 1
      ..$ : 'igraph.vs' int [1:2] 6 8
      .. ..- attr(*, "env")=<weakref> 
      .. ..- attr(*, "graph")= chr "96250aab-d2ab-43aa-882d-6ef695323b0a"
     $ :List of 1
      ..$ : 'igraph.vs' int [1:2] 7 9
      .. ..- attr(*, "env")=<weakref> 
      .. ..- attr(*, "graph")= chr "96250aab-d2ab-43aa-882d-6ef695323b0a"
     $ :List of 1
      ..$ : 'igraph.vs' int [1:2] 8 10
      .. ..- attr(*, "env")=<weakref> 
      .. ..- attr(*, "graph")= chr "96250aab-d2ab-43aa-882d-6ef695323b0a"
     $ :List of 1
      ..$ : 'igraph.vs' int [1:2] 1 9
      .. ..- attr(*, "env")=<weakref> 
      .. ..- attr(*, "graph")= chr "96250aab-d2ab-43aa-882d-6ef695323b0a"
     - attr(*, "class")= chr "igraph"
    

    So if you wanted a data.frame to hold the edge identifiers, you could get a dataframe with a single column, by just doing:

     dd_df <- data.frame( ids <- as_ids(dd) )
    

    But if you wanted a two column result that use as_data_frame method for graph object and then select the first 4 rows of the graph:

    > as_data_frame(g)[1:4, ]
      from to
    1    1  2
    2    2  3
    3    3  4
    4    4  5