4
votes

Using igraph in R, for a certain node x, I would like to list the top three neighboring nodes, based on the property of an edge between x and that neighboring node.

Create directed, weighed sample graph:

set.seed(42)
library(igraph)
n <- 10
adjm <- matrix(sample(0:100, n*10), nc=n)
colnames(adjm) <- rownames(adjm) <- letters[1:n]
g <- graph.adjacency(adjm, weighted=TRUE)

Top three outgoing edges for x based an the edge property (here the weight) on the input adjacency matrix:

x <- 'e'
adjm[x,][order(adjm[x,], decreasing = TRUE)][1:3]

Output:

 i  a  b 
86 62 40 

The current approach is rather cumbersome: select neighbours and edges to neighbours, add to a dataframe, sort the dataframe and and select top three:

x <- 'e'
tab <- data.frame(cbind(
  name=V(g)[neighbors(g,x, mode='out')]$name,
  weight=E(g)[x %->% neighbors(g,x, mode='out')]$weight)) # or %--%, %<-%
tab <- tab[order(tab$weight, decreasing=TRUE),]
head(tab,3)

Output:

  name weight
8    i     86
1    a     62
3    c      6

Is there a more elegant approach?

1

1 Answers

4
votes

I don't know if this is elegant, but certainly shorter:

e_edges <- E(g)[from(x)]
e_top_weights <- order(e_edges$weight, decreasing=TRUE)[1:3]
E(g)[ as.vector(e_edges)[e_top_weights] ]

Edge sequence:

#> [48] e -> i
#> [41] e -> a
#> [42] e -> b

The last step is cumbersome, because e_edges has a strange indexing operator defined for it, and you need to convert it to a vector. This will change in the next version of igraph, and you'll be able to write the natural

e_edges[e_top_weights]

Please tell me if you have questions.