0

I am trying to merge two graphs in R, using igraph. Ideally, I would create a union of vertices from g1 and g2, keeping edges from g1 only. This union should be created based on the label attribute. I guess I could simply remove all the edges from g2 before merging, using something like this:

g2 %>% delete_edges(seq(1, length(E(g2)), by = 1))

Still, when I create a union like this:

g.union <- graph.union(g1, g2, byname=F)

I get a graph with attributes id_1, id_2, label_1, label_2, weight_1, weight_2... Which is not quite what I want. I need to retain all the vertices and edges from g1 adding only those vertices from g2 that are missing in g1. Keeping all properties of those added vertices.

Any help appreciated!

EDIT:

@MrFlick, I can't share those graphs, but a simple example would be something like this:

I have g1

graph
[
  directed 1
  node
  [
    id 1
    label "it2igcryfm862x"
    mydetails "somedetails1"
  ]
  node
  [
    id 2
    label "it0l2xa53eu1w3"
    mydetails "somedetails2"
  ]
  node
  [
    id 3
    label "iszyxcopnao380"
    mydetails "somedetails3"
  ]
 edge
  [
    source 1
    target 2
    weight 1
  ]
  edge
  [
    source 1
    target 3
    weight 2
  ]
  edge
  [
    source 2
    target 3
    weight 1
  ]
]

and g2

graph
[
  directed 1
  node
  [
    id 1
    label "it2igcryfm862x"
    mydetails "somedetails1"
  ]
  node
  [
    id 2
    label "it0l2xa53eu1w3"
    mydetails "somedetails2"
  ]
  node
  [
    id 3
    label "iszyxcopnao380"
    mydetails "somedetails3"
  ]
  node
  [
    id 4
    label "it0lhztmkln4n6"
    mydetails "somedetails4"
  ]
 edge
  [
    source 1
    target 2
    weight 1
  ]
  edge
  [
    source 1
    target 3
    weight 3
  ]
  edge
  [
    source 2
    target 3
    weight 2
  ]
  edge
  [
    source 2
    target 4
    weight 2
  ]
  edge
  [
    source 3
    target 4
    weight 1
  ]
]

and what I need is g3

graph
[
  directed 1
  node
  [
    id 1
    label "it2igcryfm862x"
    mydetails "somedetails1"
  ]
  node
  [
    id 2
    label "it0l2xa53eu1w3"
    mydetails "somedetails2"
  ]
  node
  [
    id 3
    label "iszyxcopnao380"
    mydetails "somedetails3"
  ]
  node
  [
    id 4
    label "it0lhztmkln4n6"
    mydetails "somedetails4"
  ]
 edge
  [
    source 1
    target 2
    weight 1
  ]
  edge
  [
    source 1
    target 3
    weight 2
  ]
  edge
  [
    source 2
    target 3
    weight 1
  ]
]
Srecko
  • 199
  • 4
  • 14
  • It would be easier to help you if you provide a [reproducible example](https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example) with sample input data and the desired output. – MrFlick Sep 08 '17 at 16:07
  • Tried to provide three simple graphs that should give a better idea what the problem is all about. – Srecko Sep 08 '17 at 16:31
  • You need to provide data in a [reproducible format](https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example). How is one supposed to load that data in R? – MrFlick Sep 08 '17 at 16:41

2 Answers2

1

Here's a reproducible example

library(igraph)
set.seed(1)
g1 <- make_(ring(10), with_vertex_(label = LETTERS[1:10]))
V(g1)$color = "red"
g2 <- make_(ring(15), with_vertex_(label = LETTERS[1:15]))
V(g2)$color <- "cyan"

You need to

retain all the vertices and edges from g1 adding only those vertices from g2 that are missing in g1. Keeping all properties of those added vertices.

One way to do it:

v <- V(g2)[!V(g2)%in%V(g1)]
g3 <- add_vertices(g1, length(v), attr = vertex.attributes(g2, v))

Here's how the two original graphs and the result look like:

par(mfrow=c(1,3))
lapply(mget(ls(pattern = "^g\\d")), plot)

enter image description here

lukeA
  • 53,097
  • 5
  • 97
  • 100
  • Side note: one may need `g3 <- add_vertices(g1, length(v), attr = vertex.attributes(g2, v)[intersect(vertex_attr_names(g1), vertex_attr_names(g2))])` if the attributes from g1 and g2 differ, and one wants those of g2 that are also in g1... – lukeA Sep 08 '17 at 16:50
  • Thanks much lukeA and @G5W. There seems to be something I'm missing here, since I'm getting this error: `Error in vertex.attributes(g2, v) : object 'value' not found` – Srecko Sep 08 '17 at 18:43
  • @Srecko I cannot reproduce the error since you still did not provide a reproducible example. Two people pointed you already to the information if needed. Please read it and edit your post accordingly. The goal should be that anyone can run the code by copy-pasting, like in the answer from G5W. – lukeA Sep 08 '17 at 19:04
  • Thanks, @lukeA, but I was using the code you provided. Just copied and tried to run, but got this error. – Srecko Sep 08 '17 at 19:14
  • @Srecko Whats your `packageVersion("igraph")` - maybe `install.packages("igraph")`? – lukeA Sep 08 '17 at 20:37
  • I thought that as well - but, it's 1.1.0. – Srecko Sep 08 '17 at 20:41
  • I use igraph version `1.1.2`. – lukeA Sep 08 '17 at 20:42
  • Well, there seems to be another problem :( can't install with `install.packages("igraph")`, there is an error compiling. So, installed with `install_github("igraph/rigraph")`. Guess should solve that first... – Srecko Sep 08 '17 at 21:11
  • 1
    That's it, @lukeA. The problem was with the igraph library. It worked with the version 1.1.2. Thanks a lot! – Srecko Sep 09 '17 at 17:37
1

Your original code seems to be close to working on the example that you provided.

library(igraph)

###  Recreating your example
par(mfrow = c(2,2), mar=c(0.5,0.5,0.5,0.5))
g1 = graph_from_edgelist(matrix(c(1,2,1,3,2,3), ncol=2, byrow=TRUE))
g1 = set_vertex_attr(g1, "label", 
    value=c("it2igcryfm862x", "it0l2xa53eu1w3", 
        "iszyxcopnao380"))
plot(g1)
box()

g2 = graph_from_edgelist(matrix(c(1,2,1,3,2,3,2,4,3,4), ncol=2, byrow=TRUE))
g2 = set_vertex_attr(g2, "label", 
    value=c("it2igcryfm862x", "it0l2xa53eu1w3", 
        "iszyxcopnao380", "it0lhztmkln4n6"))
plot(g2)
box()

## Create the desired union
g1g2 = union(g1,delete_edges(g2, E(g2)))

## Edit: Preserving labels
NewLabels = c(vertex_attr(g1, "label"), 
    setdiff(vertex_attr(g2, "label"), vertex_attr(g1, "label")))
g1g2 = set_vertex_attr(g1g2, "label", value=NewLabels)

plot(g1g2)
box()

Revised graph

G5W
  • 36,531
  • 10
  • 47
  • 80
  • Thanks, G5W! This one does return all the nodes and edges as expected. But, each property is duplicated. In the example you provided it would be `attr: label_1 (v/c), label_2 (v/c)`, instead of `label` – Srecko Sep 08 '17 at 19:34
  • Yes, I see that I lost the labels in the union. Editing answer. – G5W Sep 08 '17 at 19:48
  • Either I'm doing something wrong, or we are getting the same attribute 3 times :) I don't think it's a big deal, but when you run `vertex_attr(g1g2, index = V(g1g2))`, this is what you'll get: `$label_1 [1] "it2igcryfm862x" "it0l2xa53eu1w3" "iszyxcopnao380" NA $label_2 [1] "it2igcryfm862x" "it0l2xa53eu1w3" "iszyxcopnao380" "it0lhztmkln4n6" $label [1] "it2igcryfm862x" "it0l2xa53eu1w3" "iszyxcopnao380" "it0lhztmkln4n6"` – Srecko Sep 08 '17 at 20:02
  • You are doing nothing wrong. The `union` operation copies the labels from g1 to the new attribute label_1. The labels from g2 go to label_2. I created a new label attribute so that it would correctly label the picture. You can just delete the extra label_1 and label_2. – G5W Sep 08 '17 at 20:07
  • Sure, makes sense. Thanks! – Srecko Sep 08 '17 at 20:11
  • Oh yes... I know there was something that bothered me :) so, when you do a simple thing `g2 = set_vertex_attr(g2, "label", value=c("it2igcryfm862x", "it0lhztmkln4n6", "it0l2xa53eu1w3", "iszyxcopnao380"))` - new node has an id = 2, everything gets messed up: `$label_1 [1] "it2igcryfm862x" "it0l2xa53eu1w3" "iszyxcopnao380" NA $label_2 [1] "it2igcryfm862x" "it0lhztmkln4n6" "it0l2xa53eu1w3" "iszyxcopnao380" $label [1] "it2igcryfm862x" "it0l2xa53eu1w3" "iszyxcopnao380" "it0lhztmkln4n6"`. That's why I need union by `label`. Any ideas? – Srecko Sep 08 '17 at 20:24