Search code examples
rigraph

Recursively looping through neighbors with an igraph object


Appreciate any pointers to the below output that want. I know I need to do some form of recursion but sure how to do that exactly.

I have the following code

>> start of code
# BOM data
library("dplyr")
library(igraph)

text1 <- ("
          matnr,comp
          FG1,SA1
          FG1,SA2
          SA1,SA3
          SA1,SA4
          SA1,SA5
          SA5,SA6
          FG2,SA1
          FG2,SA8
          SA8,SA9
          SA9,SA10
          SA9,SA11")

df1 <- read.table(textConnection(text1),  header = TRUE, stringsAsFactors=FALSE, strip.white = TRUE, sep=",")
head(df1)
net <- graph_from_data_frame(df1)
net
neighbors_FG1 <- neighbors(net, v=c("FG1"), mode=c("out"))
neighbors_FG1

neighbors_FG2 <- neighbors(net, v=c("FG2"), mode=c("out"))
neighbors_FG2            

neighbors_SA1 <- neighbors(net, v=c("SA1"), mode=c("out"))
neighbors_SA1

>> end of code

I want to be able to produce a data frame like below. I would think that this will need some sort of recursion and I would like to get help with this. If you can even help me with how I can get to the output below, that will be great.

FG,level,material,Comp  
FG1,1,FG1,SA1  
FG1,1,FG1,SA2  
FG1,2,SA1,SA3  
FG1,2,SA1,SA4  
FG1,2,SA1,SA5  
FG1,3,SA5,SA6  
FG2,1,FG2,SA1  
FG2,1,FG2,SA8  
FG2,2,SA8,SA9  

Solution

  • Here is an igraph option

    lst <- lapply(
      names(V(net))[degree(net, mode = "in") == 0],
      function(x) {
        d <- Filter(
          is.finite,
          setNames(
            c(distances(net, x, mode = "out") + 1),
            names(V(net))
          )
        )
        cbind(
          FG = x,
          merge(
            setNames(get.data.frame(
              induced_subgraph(
                net,
                names(d)
              )
            ), c("matnr", "comp")),
            setNames(
              rev(stack(d)),
              c("matnr", "lvl")
            )
          )
        )
      }
    )
    
    res <- `row.names<-`(
      subset(
        do.call(rbind, lst),
        ave(seq_along(matnr), matnr, comp, lvl, FUN = seq_along) == 1
      ), NULL
    )
    

    which gives

    > res
        FG matnr comp lvl
    1  FG1   FG1  SA1   1
    2  FG1   FG1  SA2   1
    3  FG1   SA1  SA3   2
    4  FG1   SA1  SA4   2
    5  FG1   SA1  SA5   2
    6  FG1   SA5  SA6   3
    7  FG2   FG2  SA1   1
    8  FG2   FG2  SA8   1
    9  FG2   SA8  SA9   2
    10 FG2   SA9 SA10   3
    11 FG2   SA9 SA11   3