17

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?

Gabor Csardi
  • 10,076
  • 1
  • 31
  • 49
Scott Ritchie
  • 9,228
  • 2
  • 24
  • 61
  • 2
    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 Jan 23 '14 at 06:41
  • @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 Jan 23 '14 at 08:02
  • 2
    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 Jan 23 '14 at 14:34

4 Answers4

29

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.

Gabor Csardi
  • 10,076
  • 1
  • 31
  • 49
12

@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

ddiez
  • 1,059
  • 11
  • 25
8

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.

James Tobin
  • 2,950
  • 17
  • 34
  • 1
    FYI: you **can** have negative edges in igraph. Also, `qgraph` just calls `igraph` AFAIK. – Gabor Csardi Jan 23 '14 at 15:07
  • I realize that qgraph calls igraph. Its just easier to plot weighted networks with it because it does everything for you in the background. – James Tobin Jan 23 '14 at 15:09
  • Sure, I agree that's useful. The -1 was because you implied that igraph cannot handle negative edges, which is misinformation. – Gabor Csardi Jan 23 '14 at 15:29
4

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.

TWL
  • 2,210
  • 1
  • 15
  • 20
  • Edge weights can be negative, there is nothing wrong with that AFAIK. – Gabor Csardi Jan 23 '14 at 14:33
  • @GaborCsardi, I did not imply that the edge weights cannot be negative. In the context of my answer, they should be positive to be visualised as the **edge width**. Hence, I found -1 vote a bit hasty. Nonetheless, I edited the answer to avoid confusion. – TWL Jan 23 '14 at 23:55
  • I see, sorry, misunderstood. – Gabor Csardi Jan 24 '14 at 02:56