Reputation: 3395
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)
But is there a way of making the thickness of the edges proportional to how often a particular pairing occurred?
Upvotes: 2
Views: 1781
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)
Upvotes: 1
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
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)
Upvotes: 3
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)
Upvotes: 2