Nova
Nova

Reputation: 618

How to extract edge types for all shortest paths in R with igraph?

igraph has two useful functions, shortest_paths and all_shortest_paths. The former outputs one of the shortest paths, the other outputs all of them. However, the former also is able to output the edge types of the path while the latter doesn't seem to be able to.

How do I use all_shortest_paths to extract the "edge type" for all of the shortest paths? I have provided clarifying code below:

library(igraph)
m <- read.table(row.names=1, header=TRUE, text=
                  " A B C D
                A 0  1  1  0  
                B 0  0 0  1 
                C 0 0  0  1
                D 0  0  0  0")
m <- as.matrix(m)
ig <- graph.adjacency(m, mode="directed")
plot(ig)
E(ig)
for (i in 1:length(E(ig))) {
  
  if (i == 4) {
    
    E(ig)[i]$type <- -1
  } else {

    E(ig)[i]$type <- 1
  }
  
}

###This gets one of the shortest paths
test1 <- shortest_paths(ig, from = V(ig)[1], to = V(ig)[4], mode = "out", output = "epath")

###This outputs the types for the shortest path above
test1$epath[[1]]$type

###This gets all the shortest paths
test2 <- all_shortest_paths(ig, from = V(ig)[1], to = V(ig)[4], mode = "out")

###The code below doesn't work. How do I get the types for ALL the shortest paths?
test2$res[[1]]$type

Upvotes: 3

Views: 456

Answers (3)

thelatemail
thelatemail

Reputation: 93813

Get the selections of edges and extract the type:

lapply(test2$res, \(x) E(ig)[head(x, -1) %->% tail(x, -1)]$type)
#[[1]]
#[1]  1 -1
#
#[[2]]
#[1] 1 1

See https://igraph.org/r/doc/igraph-es-indexing.html or ?"igraph-es-indexing" from inside R for all the details on the options of how this works. E.g.:

E(ig)[c("A","B") %->% c("B","D")]
#+ 2/4 edges from 16165ed (vertex names):
#[1] A->B B->D

Upvotes: 1

Nick
Nick

Reputation: 349

This can be done relatively simply while looping through the test2$res and using igraph's accessor function as_ids():

suppressMessages(library(igraph))
m <- read.table(row.names=1, header=TRUE, text=
                  " A B C D
                A 0  1  1  0  
                B 0  0 0  1 
                C 0 0  0  1
                D 0  0  0  0")
m <- as.matrix(m)
ig <- graph.adjacency(m, mode="directed")
plot(ig)
E(ig)
for (i in 1:length(E(ig))) {
  if (i == 4) {
    E(ig)[i]$type <- "green"
  } else {
    E(ig)[i]$type <- "red"
  }
}

OriginalGraph <- get.data.frame(x = ig)
EdgeTypesPresent <- vector(mode = "list",
                           length = length(test2))

for (m1 in seq_along(test2$res)) {
  p1 <- as_ids(test2$res[[m1]])
  EdgeTypesPresent[[m1]] <- unique(OriginalGraph$type[OriginalGraph$from %in% p1 &
                                                        OriginalGraph$to %in% p1])
  
}

This gives us:

> EdgeTypesPresent
[[1]]
[1] "red"   "green"

[[2]]
[1] "red"

Upvotes: 1

ThomasIsCoding
ThomasIsCoding

Reputation: 101247

Try the code below

df <- get.data.frame(ig)
lapply(
  test2$res,
  function(x) {
    nm <- names(x)
    merge(
      df,
      data.frame(from = head(nm, -1), to = tail(nm, -1))
    )$type
  }
)

and you will get

[[1]]
[1]  1 -1

[[2]]
[1] 1 1

If you want to see more information, you can use

df <- get.data.frame(ig)
lapply(
  test2$res,
  function(x) {
    nm <- names(x)
    merge(
      df,
      data.frame(from = head(nm, -1), to = tail(nm, -1))
    )
  }
)

and you will get

[[1]]
  from to type
1    A  C    1
2    C  D   -1

[[2]]
  from to type
1    A  B    1
2    B  D    1

Upvotes: 2

Related Questions