17
votes

I'm trying to use the igraph package to draw a (sparse) weighted graph. I currently have an adjacency matrix, but cannot get the graph.adjacency function to recognise the edge weights.

Consider the following random symmetric matrix:

m <- read.table(row.names=1, header=TRUE, text=
"           A          B          C          D           E         F
A 0.00000000  0.0000000  0.0000000  0.0000000  0.05119703 1.3431599
B 0.00000000  0.0000000 -0.6088082  0.4016954  0.00000000 0.6132168
C 0.00000000 -0.6088082  0.0000000  0.0000000 -0.63295415 0.0000000
D 0.00000000  0.4016954  0.0000000  0.0000000 -0.29831267 0.0000000
E 0.05119703  0.0000000 -0.6329541 -0.2983127  0.00000000 0.1562458
F 1.34315990  0.6132168  0.0000000  0.0000000  0.15624584 0.0000000")
m <- as.matrix(m)

To plot, first I must get this adjacency matrix into the proper igraph format. This should be relatively simple with graph.adjacency. According to my reading of the documentation for graph.adjacency, I should do the following:

library(igraph)
ig <- graph.adjacency(m, mode="undirected", weighted=TRUE)

However, it doesn't recognise the edge weights:

str(ig)
# IGRAPH UNW- 6 8 -- 
# + attr: name (v/c), weight (e/n)
# + edges (vertex names):
# [1] A--E A--F B--C B--D B--F C--E D--E E--F
plot(ig)

enter image description here

How do I get igraph to recognise the edge weights?

4
It doesn't appear to be the problem, but do note that the matrix you've printed above is not symmetric. (Try isSymmetric(m), and then compare, e.g., the values of m[5,3] and m[3,5].) - Josh O'Brien
@JoshO'Brien, it appears it's a simple copy&paste bug, numbers in columns A and E have 8 decimal places, while the rest has 7. Aside of that it's symmetric: isSymmetric(round(m,6)) == TRUE. Interestingly, igraph retained the version with the most decimal places, and in case of discrepancy added 0 at the end of the number with 7 decimal places. - TWL
The weights are there, weight (e/n) means that there is an edge attribute called weight, and it is numeric. See ?print.igraph. But they are not plotted by default, you need to add them as edge.label. - Gabor Csardi

4 Answers

29
votes

The weights are there, weight (e/n) means that there is an edge attribute called weight, and it is numeric. See ?print.igraph. But they are not plotted by default, you need to add them as edge.label.

plot(ig, edge.label=round(E(ig)$weight, 3))

graph plot screenshot

For plotting, make sure you read ?igraph.plotting.

12
votes

@TWL's solution can be easily generalized to represent edges' width as a function of the weights, including negative weights. The trick is to translate all weights by summing the value of the smallest weight (plus optionally an offset that represents the width of the minimum weight). For example:

# reproducible example:
set.seed(12345)
a <- matrix(runif(5*5, min=-10, max=10), ncol=5)
diag(a) <- 0 # remove loops.
>a
           [,1]       [,2]      [,3]       [,4]       [,5]
[1,]  0.0000000 -6.6725643 -9.309291 -0.7501069 -0.9254385
[2,]  7.5154639  0.0000000 -6.952530 -2.2371204 -3.4649518
[3,]  5.2196466  0.1844867  0.000000 -1.9502972  9.3083065
[4,]  7.7224913  4.5541051 -9.977268  0.0000000  4.1496375
[5,] -0.8703808  9.7947388 -2.175933  9.0331751  0.0000000

# create igraph object.
g <- graph.adjacency(a, mode="undirected", weighted=TRUE)
plot(g)

# assign edge's width as a function of weights.
E(g)$width <- E(g)$weight + min(E(g)$weight) + 1 # offset=1
plot(g)

enter image description here

9
votes

As much as I love igraph, I've found the qgraph package easier to plot weighted networks.

With the adjacency matrix you can also just use qgraph() from the qgraph library to plot it. It will automatically color negative edges a shade of red and positive edges a shade of green.

install.packages('qgraph')
require(qgraph)
qgraph(m)
qgraph(m,edge.labels=TRUE)  #if you want the weights on the edges as well

qgraph is built on igraph, but just does everything for you.

4
votes

You can extract the edge weights with E(ig)$weight, and assign them to the edge.width argument in the plotting function:

plot(ig, edge.width=E(ig)$weight)

See the ?igraph.plotting [link] for reference.

Also, please note that in this example, the weights will correspond to the width of the edges, hence they should be >= 0.