Wolfgang
Wolfgang

Reputation: 3395

Create Weighted Graph from Group Membership Data

Suppose I have a dataset in R indicating the individuals within groups. Here is an example:

grp <- c(1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5)
ind <- c("A", "C", "D", "B", "C", "D", "E", "A", "D", "E", "B", "F", "E", "A", "F")
data.frame(grp, ind)

So, the data look like this:

   grp ind
1    1   A
2    1   C
3    1   D
4    2   B
5    2   C
6    2   D
7    2   E
8    3   A
9    3   D
10   3   E
11   4   B
12   4   F
13   4   E
14   5   A
15   5   F

So, group 1 is composed of individuals (A, C, D), group 2 is composed of individuals (B, C, D, E), and so on. I would like to create a network graph that shows how individuals are connected with each other. Within a group, all individuals are connected by edges. The thickness of the edges should reflect how often two individuals are connected to each other.

With:

pairs <- do.call(rbind, sapply(split(ind, grp), function(x) t(combn(x,2))))

I can obtain a matrix with all pairwise edges, which I can plot with the igraph package:

library(igraph)
plot(graph.edgelist(pairs, directed=FALSE), edge.curved=FALSE)

network

But is there a way of making the thickness of the edges proportional to how often a particular pairing occurred?

Upvotes: 2

Views: 1781

Answers (4)

Gabor Csardi
Gabor Csardi

Reputation: 10825

Here is a solution that creates the bipartite graph, and then projects it to the individuals.

g <- graph.edgelist(cbind(grp, ind), directed=FALSE)
V(g)$type <- V(g)$name %in% grp 
ind_g <- bipartite.projection(g)[[1]]
E(ind_g)$width <- E(ind_g)$weight * 3
plot(ind_g)

graph plot

Upvotes: 1

Areza
Areza

Reputation: 6080

library(igraph)
grp <- c(1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5)
ind <- c("A", "C", "D", "B", "C", "D", "E", "A", "D", "E", "B", "F", "E", "A", "F")
data.frame(grp, ind)

pairs <- do.call(rbind, sapply(split(ind, grp), function(x) t(combn(x,2))))
g = graph.data.frame(pairs, directed=FALSE)

E(g)$weight = c(1, grp)
plot.igraph(g, edge.width=E(g)$weight)

I am not sure if I am putting the weight correctly but I hope you find my code helpful. You can find more helpful sample codes here on weight-edge or and here on weight-node

Upvotes: 1

josliber
josliber

Reputation: 44340

@hrbrmstr's solution builds a second graph to get the edge weights. You could also do this beforehand by operating on pairs:

# Count unique edge pairs
library(plyr)
weighted <- ddply(data.frame(pairs), .(X1, X2), count)

# Plot
library(igraph)
g <- graph.edgelist(as.matrix(weighted[,1:2]), directed=FALSE)
plot(g, edge.curved=FALSE, edge.width=weighted$freq*3)

enter image description here

Upvotes: 3

hrbrmstr
hrbrmstr

Reputation: 78832

Could probably tighten this up a bit, but…

library(igraph)

grp <- c(1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5)
ind <- c("A", "C", "D", "B", "C", "D", "E", "A", "D", "E", "B", "F", "E", "A", "F")

pairs <- do.call(rbind, sapply(split(ind, grp), function(x) t(combn(x,2))))

g <- graph.edgelist(pairs, directed=FALSE)

m <- get.adjacency(g) # get the adjacency matrix

net <- graph.adjacency(m,
                       mode="undirected",
                       weighted=TRUE,
                       diag=FALSE)

print(E(net)$weight) # just for kicks
## [1] 1 2 1 1 2 1 1 1 2 2 1 1

set.seed(1492) # ensures consistent layout every run

plot.igraph(net, 
            vertex.label=V(net)$name,
            layout=layout.fruchterman.reingold,
            edge.color="black",
            edge.width=E(net)$weight*3)

plot

Upvotes: 2

Related Questions