1

I have an igraph network with edge attributes.

I would like to generate a vertex attribute combining edge attributes. Specifically, I would like for each vertex to assign an attribute based on the mode of its own edge attributes (or any other operation, for the matter).

In my example an edge represent a collaboration between people on a subject.

library(igraph)
library(RColorBrewer)
g <- graph("Zachary") # the Zachary carate club
V(g)$names <- c(1:gorder(g))
set.seed(1); E(g)$relation <- sample(c("A","B","C"), gsize(g), replace = TRUE)
set.seed(1); E(g)$relation_col <- sample(brewer.pal(3, "Set1"), gsize(g), replace = TRUE)
    
plot(g, vertex.size=10, vertex.label=NA, 
         vertex.color="grey",
         edge.color=E(g)$relation_col)

I cannot generate a vertex-specific attribute. When I calculate the mode, it is done for the whole network, not for the specific edge

getmode <- function(v) {
      uniqv <- unique(v)
      uniqv[which.max(tabulate(match(v, uniqv)))]
    }
g <- set_vertex_attr(g, "relation", value=getmode(E(g)$relation))

vertex_attr(g)
$names
 [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34

$relation
 [1] "B" "B" "B" "B" "B" "B" "B" "B" "B" "B" "B" "B" "B" "B" "B" "B" "B" "B" "B" "B" "B" "B" "B" "B" "B" "B" "B" "B" "B" "B" "B" "B" "B" "B"

Manual reference: https://igraph.org/r/doc/igraph-attribute-combination.html

MCS
  • 1,071
  • 9
  • 23

1 Answers1

0

Maybe the following function solves the problem of assigning edge attributes to vertices attributes.

The code below uses function Modes from this SO post. If there is more than one mode, it selects one at random with sample. Therefore, call set.seed in order to make the results reproducible.

library(igraph)
library(RColorBrewer)

Modes <- function(x) {
  ux <- unique(x)
  tab <- tabulate(match(x, ux))
  ux[tab == max(tab)]
}

attr_from_edge_to_vertex <- function(x, e_attr, v_attr){
  f <- function(v, edges_mat){
    i1 <- which(edges_mat[,1] == v)
    i2 <- which(edges_mat[,2] == v)
    i <- union(i1, i2)
    ea <- edge_attr(x, v_attr, index = E(x)[i])
    ea <- Modes(ea)
    if(length(ea) > 1) sample(ea, 1) else ea
  }
  if(missing(e_attr)){
    msg <- paste("Edge attribute", sQuote(e_attr), "doesn't exist.")
    msg <- paste(msg, "Returning the graph unchanged.")
    warning(msg)
  } else {
    es <- ends(x, es = E(x))
    if(missing(v_attr)) v_attr <- e_attr
    for(v in as_ids(V(x))){
      va <- f(v, es)
      vertex_attr(x, v_attr, index = v) <- va
    }
  }
  x
}

g <- graph("Zachary") # the Zachary carate club
V(g)$names <- c(1:gorder(g))
set.seed(1); E(g)$relation <- sample(c("A","B","C"), gsize(g), replace = TRUE)
set.seed(1); E(g)$relation_col <- sample(brewer.pal(3, "Set1"), gsize(g), replace = TRUE)

h <- attr_from_edge_to_vertex(g, "relation_col")
vertex_attr(h, "relation_col")
# [1] "#E41A1C" "#E41A1C" "#377EB8" "#E41A1C" "#377EB8" "#377EB8" "#377EB8" "#4DAF4A" "#377EB8"
#[10] "#E41A1C" "#377EB8" "#4DAF4A" "#4DAF4A" "#E41A1C" "#4DAF4A" "#377EB8" "#4DAF4A" "#4DAF4A"
#[19] "#377EB8" "#E41A1C" "#377EB8" "#E41A1C" "#377EB8" "#377EB8" "#4DAF4A" "#4DAF4A" "#377EB8"
#[28] "#377EB8" "#E41A1C" "#E41A1C" "#E41A1C" "#4DAF4A" "#4DAF4A" "#E41A1C"


plot(g, vertex.size=10, vertex.label=NA,
     vertex.color=vertex_attr(h, "relation_col"),
     edge.color=E(g)$relation_col)
MCS
  • 1,071
  • 9
  • 23
Rui Barradas
  • 70,273
  • 8
  • 34
  • 66
  • I change my toy example to provide a better insight. – MCS Sep 23 '20 at 09:20
  • If I use your Rui Barradas' solution with my new toy example I get an error (In vattrs[[name]][index] <- value: number of items to replace is not a multiple of replacement length). Besides, visual check shows me that the transformation did not do what it was supposed to do h <- attr_from_edge_to_vertex(g, "relation") h <- attr_from_edge_to_vertex(g, "relation_col") #vertex_attr(h) #edge_attr(h) plot(h,vertex.size=10, vertex.label=NA, vertex.color=V(h)$relation_col, edge.color=E(h)$relation_col) – MCS Sep 23 '20 at 09:28
  • @MCS When I run your new example I get `Error in "igraph" %in% class(graph) : object 'zach' not found` right after the first `set.seed(1); E(g)$relation <- sample(etc)`. – Rui Barradas Sep 23 '20 at 12:04
  • @MCS The problem is that you now have 78 edges but only 34 vertices. What is the rule to select which of those 78 values to assign to the 34 vertex attributes? (In the original example there were as many edges as vertices). – Rui Barradas Sep 23 '20 at 12:44
  • For each vertex, I want to consider all the edges of interest (those edges that have that vertex as a starting/arrival point, as my network in not directed). I would like to calculate the mode of edges attributes (e.g. relation) and assign it to the vertex as vertex attribute. In this way I would have as many vertices as attributes. – MCS Sep 23 '20 at 12:51
  • @MCS So if, say, `degree(g, v = 1)` is 16, you want vertex 1 to have 16 values for attribute `"relation"` and another 16 values for attribute `"relation_col"`? – Rui Barradas Sep 23 '20 at 14:48
  • So, I would like to take the 16, make a list of the 16 ```relation``` attributes, calculate the value that appears most often (either "A","B",or "C") and than attribute that one only to the vertex as its attribute – MCS Sep 23 '20 at 15:03
  • in testing the function outside the toy model the function does not work and produces a vector of NA. What would produce that? – MCS Sep 24 '20 at 15:32