The goal is to familiarize with the R
package
igraph
.
Official website: http://igraph.org/r/
Be careful: igraph
has also been developed in C and
Python. If you do a search on the web you might arrive on http://igraph.org/c/ or http://igraph.org/python/ rather than http://igraph.org/r/
If you want to go further with igraph
you can also have
a look at that tutorial: http://kateto.net/networks-r-igraph
igraph
packageInstall the package igraph
and load the library
install.packages("igraph")
library(igraph)
##
## Attaching package: 'igraph'
## The following objects are masked from 'package:stats':
##
## decompose, spectrum
## The following object is masked from 'package:base':
##
## union
There are 2 possible formats: either a vector that concatenates the indexes of linked nodes or a matrix with 2 rows.
EdgeList1 <- c(1,2, 1,3, 2,3, 3,5, 2,4, 4,5, 5,6, 4,6, 4,7, 6,7, 3,4)
EdgeList2 <- matrix(EdgeList1,nrow=2)
g1 <- graph(edges=EdgeList1, directed=FALSE)
g2 <- graph(edges=EdgeList2, directed=FALSE)
par(mfrow=c(1,2))
plot(g1)
plot(g2)
You obtain an object with class igraph
:
class(g1)
## [1] "igraph"
You can specify the number of nodes \(n\) (in particular when there are isolated nodes):
g3 <- graph(edges=EdgeList1, n=9, directed=FALSE)
plot(g3)
Nodes are not necessarily of the numeric type:
EdgeListNames <- c("Eric", "Erwan", "Erwan","Ana")
g4 <- graph(edges=EdgeListNames)
plot(g4)
# Note that by default, the graph is directed
With isolated nodes:
g5 <- graph(edges=EdgeListNames, isolates="Paul")
plot(g5)
It could be useful to start with a particular graph, specifying the number of node
g0 <- make_empty_graph(20)
gf <- make_full_graph(20)
gr <- make_ring(20)
gl <- make_lattice(c(4,6)) # here you input dimension
gs <- make_star(10)
par(mfrow=c(2,3))
plot(g0)
plot(gf)
plot(gr)
plot(gl)
plot(gs)
data.frame
structure containing the
list of edges:Dataset (csv format) gathers friendship relationships among high-school students. It’s in the repo but you may also download it from: http://www.sociopatterns.org/datasets/high-school-contact-and-friendship-networks/
friends <- read.table(file='../Data/Toy_Data/Friendship-network_data_2013.csv')
head(friends)
gfriends <- graph_from_data_frame(friends, directed=TRUE)
gfriends
## IGRAPH f848483 DN-- 134 668 --
## + attr: name (v/c)
## + edges from f848483 (vertex names):
## [1] 1 ->55 1 ->205 1 ->272 1 ->494 1 ->779 1 ->894 3 ->1 3 ->28 3 ->147
## [10] 3 ->272 3 ->407 3 ->674 3 ->884 27->63 27->173 28->202 28->327 28->353
## [19] 28->407 28->429 28->441 28->492 28->545 32->440 32->624 32->797 32->920
## [28] 34->151 34->277 34->502 34->866 45->48 45->79 45->335 45->496 45->601
## [37] 45->674 45->765 46->117 46->196 46->257 46->268 48->45 48->79 48->496
## [46] 55->1 55->170 55->205 55->252 55->272 55->779 55->883 55->894 61->797
## [55] 63->27 63->125 63->173 70->101 70->132 70->240 70->425 70->447 72->407
## [64] 72->674 72->857 79->45 79->48 79->335 79->496 79->601 79->674 79->765
## + ... omitted several edges
class(gfriends)
## [1] "igraph"
plot(gfriends)
You can also import other data.frame
; try with a dataset
containing information about media: the first file
Dataset1-Media-Example-NODES.csv
contains information about
the nodes and the second one
Dataset1-Media-Example-EDGES.csv
contains the list of
interactions (these are valued and of several different types):
nodes <- read.csv("../Data/Toy_Data/Dataset1-Media-Example-NODES.csv", header=TRUE, as.is=TRUE)
head(nodes)
links <- read.csv("../Data/Toy_Data/Dataset1-Media-Example-EDGES.csv", header=TRUE, as.is=TRUE)
head(links)
net <- graph_from_data_frame(d=links, vertices=nodes, directed=TRUE)
class(net)
## [1] "igraph"
plot(net)
igraph
:Function read_graph
is adapted to certain graph
formats:
# usage:
# This is not a command to be run !!!!
read_graph(file, format = c("edgelist", "pajek", "ncol", "lgl", "graphml", "dimacs", "graphdb", "gml", "dl"), ...)
The file lesmis.gml contains the weighted network of co-appearances of characters in Victor Hugo’s novel Les Miserables. Nodes represent characters as indicated by the labels and edges connect any pair of characters that appear in the same chapter of the book. The values on the edges are the number of such co-appearances. The file is in the repo or may be doawloaded from http://www-personal.umich.edu/~mejn/netdata/
miserab <- read_graph(file='../Data/Toy_Data/lesmis.gml', format="gml")
class(miserab)
## [1] "igraph"
plot(miserab)
A <- matrix(c(0,0,0,0,0,0,1,1,0,1,0,1,0,1,1,0), 4, 4)
A
## [,1] [,2] [,3] [,4]
## [1,] 0 0 0 0
## [2,] 0 0 1 1
## [3,] 0 1 0 1
## [4,] 0 1 1 0
plot(graph_from_adjacency_matrix(A, mode='undirected'))
If you want to create toy graphs to play with, you can use the
funtion sample_gnm
specifying the number of nodes
n
and the number of edges m
(the Erdös-Rényi
model will be described soon).
set.seed(237)
toyG <- sample_gnm(n=50,m=12)
plot(toyG)
Note that you don’t visualize the 12 edges because they connect nodes that are close together.
You can convert a graph into its adjacency matrix:
Afriends <- as_adj(gfriends)
dim(Afriends)
## [1] 134 134
Beware: by default as_adj
creates a matrix with
sparse format and certain classical operations are. not
possible :
is.matrix(Afriends)
## [1] FALSE
class(Afriends)
## [1] "dgCMatrix"
## attr(,"package")
## [1] "Matrix"
t(Afriends)
## Error in t.default(Afriends): argument is not a matrix
To correct for that, just use option sparse=FALSE
:
Afriends <- as_adj(gfriends, sparse=FALSE)
is.matrix(Afriends)
## [1] TRUE
Get familiar with the following functions by applying them to the
graphs created above. Also use the package documentation (with
help()
) and READ it!
vcount()
ecount()
V()
E()
is.directed()
You can do the fusion of 2 graphs by a simple +
operation
E4 <- c(3,7, 2,5, 4,1, 6,5, 2,4)
g4 <- graph(edges=E4, directed=FALSE)
fused_G <- g1+g4
plot(fused_G)
Note that this produces (at least) 2 disconnected components and the nodes of the second graph have been renamed to be distinguished from the nodes of the first one. To connect these 2 graphs one needs to add edges
V(fused_G)
## + 14/14 vertices, from bcd950e:
## [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14
G_more <- add.edges(fused_G,c(14,3, 11,5))
plot(G_more)
Another possibility is to use union
, in which case the
nodes that have the same names/numbers are considered the same:
fused_G2 <- union(g1,g4)
plot(fused_G2)
When the graph is bipartite, a vertex attribute
is added
to the vertices
Gb1 <- sample_bipartite(n1=5, n2=8, type="gnm", m=11)
vertex_attr(Gb1)
## $type
## [1] FALSE FALSE FALSE FALSE FALSE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## [13] TRUE
plot(Gb1,layout=layout_as_bipartite)
Gb2 <- sample_bipartite(n1=3, n2=4, type="gnm", m=7)
plot(Gb2,layout=layout_as_bipartite)
plot(Gb1+Gb2, layout=layout_as_bipartite)
# plot(union(Gb1,Gb2), layout=layout_as_bipartite) # This does'nt work !
It is not possible to simply do a union
of 2 bipartites
graphs. Indeed, the union
function preserves vertices
attributes. You could use the following code to correct for that:
union_bipartite<-function(list_nets){
x<-do.call(igraph::union, list_nets)
l<-length(list_nets)
type_vec<-sapply(1:l,function(y) paste0("type_",y))
or_types<-apply(sapply(1:l, function(k) vertex_attr(x, type_vec[k])),1,any)
V(x)$type<-!(is.na(or_types)|!(or_types))
x
}
net1<-sample_bipartite(15,10,"gnp",0.1)
V(net1)$name<-c(sapply(1:15,function(x) paste0("A_",x)),sapply(1:10,function(x) paste0("B_",x)))
net2<-sample_bipartite(15,10,"gnp",0.2)
V(net2)$name<-c(sapply(6:20,function(x) paste0("A_",x)),sapply(3:12,function(x) paste0("B_",x)))
net3<-sample_bipartite(20,12,"gnp",0.25)
V(net3)$name<-c(sapply(1:20,function(x) paste0("A_",x)),sapply(1:12,function(x) paste0("B_",x)))
nets<-union_bipartite(list(net1,net2,net3))
plot(net1,layout=layout_as_bipartite)
plot(net2,layout=layout_as_bipartite)
plot(nets,layout=layout_as_bipartite)
V(nets)[which(V(nets)$type)]$name
## [1] "B_1" "B_2" "B_3" "B_4" "B_5" "B_6" "B_7" "B_8" "B_9" "B_10"
## [11] "B_11" "B_12"
V(nets)[which(!V(nets)$type)]$name
## [1] "A_1" "A_2" "A_3" "A_4" "A_5" "A_6" "A_7" "A_8" "A_9" "A_10"
## [11] "A_11" "A_12" "A_13" "A_14" "A_15" "A_16" "A_17" "A_18" "A_19" "A_20"
To know more about that: https://igraph.org/r/doc/layout_.html
plot(gfriends)
To choose a specific layout, use the following option (use autocompletion to see the possible layouts):
plot(gfriends, layout=layout_as_star)
plot(gfriends, layout=layout_in_circle)
plot(gfriends, layout=layout_randomly)
Two popular visualization algorithms for having visualizations deemed “aesthetic”. If you want more information: https://halshs.archives-ouvertes.fr/halshs-00839905/document
plot(gfriends, layout=layout.fruchterman.reingold)
plot(gfriends, layout=layout.kamada.kawai)
igraph
To see all options of plot()
just type
?igraph.plotting
The most common ones are:
vertex.color
, vertex.shape
,
vertex.size
, vertex.label
color, shape, size
and labels of the nodesedge.color
, edge.label
edge color and
labelsplot(net)
plot(net, edge.arrow.size=.4)
plot(net, vertex.color="orange", edge.color="blue", vertex.label.color="black", edge.arrow.size=.4)
If we want to use additional information to color the nodes according to the covariates (here the type of media, the size of the nodes according to the audience, the thickness of the edges according to their weight…) or on the edges (here valued and of different types). You can find this information here:
vertex_attr(net)
## $name
## [1] "s01" "s02" "s03" "s04" "s05" "s06" "s07" "s08" "s09" "s10" "s11" "s12"
## [13] "s13" "s14" "s15" "s16" "s17"
##
## $media
## [1] "NY Times" "Washington Post" "Wall Street Journal"
## [4] "USA Today" "LA Times" "New York Post"
## [7] "CNN" "MSNBC" "FOX News"
## [10] "ABC" "BBC" "Yahoo News"
## [13] "Google News" "Reuters.com" "NYTimes.com"
## [16] "WashingtonPost.com" "AOL.com"
##
## $media.type
## [1] 1 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3 3
##
## $type.label
## [1] "Newspaper" "Newspaper" "Newspaper" "Newspaper" "Newspaper" "Newspaper"
## [7] "TV" "TV" "TV" "TV" "TV" "Online"
## [13] "Online" "Online" "Online" "Online" "Online"
##
## $audience.size
## [1] 20 25 30 32 20 50 56 34 60 23 34 33 23 12 24 28 33
V(net)$media
## [1] "NY Times" "Washington Post" "Wall Street Journal"
## [4] "USA Today" "LA Times" "New York Post"
## [7] "CNN" "MSNBC" "FOX News"
## [10] "ABC" "BBC" "Yahoo News"
## [13] "Google News" "Reuters.com" "NYTimes.com"
## [16] "WashingtonPost.com" "AOL.com"
edge_attr(net)
## $weight
## [1] 10 12 22 21 22 21 21 11 12 22 23 20 11 11 21 23 21 21 21 22 21 21 21 23 21
## [26] 22 22 21 21 2 5 1 1 2 2 3 1 1 1 1 2 2 4 2 4 4 4 1 1 1
## [51] 1 1
##
## $type
## [1] "hyperlink" "hyperlink" "hyperlink" "hyperlink" "mention" "mention"
## [7] "mention" "mention" "mention" "hyperlink" "hyperlink" "mention"
## [13] "hyperlink" "hyperlink" "mention" "hyperlink" "hyperlink" "mention"
## [19] "mention" "mention" "hyperlink" "hyperlink" "hyperlink" "hyperlink"
## [25] "hyperlink" "hyperlink" "mention" "mention" "hyperlink" "hyperlink"
## [31] "hyperlink" "hyperlink" "mention" "hyperlink" "mention" "hyperlink"
## [37] "mention" "hyperlink" "mention" "hyperlink" "mention" "mention"
## [43] "hyperlink" "hyperlink" "hyperlink" "mention" "hyperlink" "hyperlink"
## [49] "mention" "hyperlink" "hyperlink" "mention"
E(net)$weight
## [1] 10 12 22 21 22 21 21 11 12 22 23 20 11 11 21 23 21 21 21 22 21 21 21 23 21
## [26] 22 22 21 21 2 5 1 1 2 2 3 1 1 1 1 2 2 4 2 4 4 4 1 1 1
## [51] 1 1
plot(net, vertex.label=V(net)$media, edge.arrow.size=.4)
plot(net, vertex.label=V(net)$media, edge.arrow.size=.4, vertex.color=V(net)$media.type)
plot(net, vertex.label=V(net)$media, edge.arrow.size=.4, vertex.color=V(net)$media.type, vertex.size=V(net)$audience.size)
plot(net, vertex.label=V(net)$media, vertex.color=V(net)$media.type, vertex.size=V(net)$audience.size, edge.width=E(net)$weight)
To change the color of the link based on its type
E(net)$color[E(net)$type=="hyperlink"]<-"blue"
E(net)$color[E(net)$type=="mention"]<-"red"
plot(net, edge.arrow.size=.4)
Search the web for graphs and import them onto your machine (you will keep the data recovery address as a comment in your file). Vary the original formats if you can, and the type of graph (directed or not). Determine the order (number of nodes) and size (number of edges) of the graphs and visualize them.
Here is a list of servers offering real graph data: