Overview

The main goals of the igraph library is to provide a set of data types and functions for

  1. pain-free implementation of graph algorithms,
  2. fast handling of large graphs, with millions of vertices and edges,
  3. allowing rapid prototyping via high level languages like R and Python

Overview

## Load package
library(igraph)
  • igraph is a collection of network analysis tools with the emphasis on efficiency, portability and ease of use
  • igraph is open source and free
  • igraph can be programmed in R, Python, Mathematica and C/C++
  • the igraph manual page is a good place to start
  • the igraph documentation is a good place to end

Basic, notable and popular graphs

Read a graph from data frames

You can read a graph from a data frame representation. It consists of two data frames:

  1. one data frame contains nodes and related attributes
  2. one data frame contains edges (paris of nodes) and related attributes
# read graph from data frame
actors <- data.frame(
  name = c("Alice", "Bob", "Cecil", "David", "Esmeralda"),
  age = c(48, 33, 45, 34, 21),
  gender = c("F", "M", "F", "M", "F")
)

relations <- data.frame(
  from = c("Bob", "Cecil", "Cecil", "David", "David", "Esmeralda"),
  to = c("Alice", "Bob", "Alice", "Alice", "Bob", "Alice"),
  sameDept = c(FALSE, FALSE, TRUE, FALSE, FALSE, TRUE),
  friendship = c(4, 5, 5, 2, 1, 1),
  advice = c(4, 5, 5, 4, 2, 3)
)

g = graph_from_data_frame(relations, directed = TRUE, vertices = actors)

Explore a graph

# print graph
g
## IGRAPH c7ecafd DN-- 5 6 -- 
## + attr: name (v/c), age (v/n), gender (v/c), sameDept (e/l), friendship
## | (e/n), advice (e/n)
## + edges from c7ecafd (vertex names):
## [1] Bob      ->Alice Cecil    ->Bob   Cecil    ->Alice David    ->Alice
## [5] David    ->Bob   Esmeralda->Alice

‘IGRAPH’ denotes that this is an igraph graph. Then come four bits that denote the kind of the graph:

  • the first is ‘U’ for undirected and ‘D’ for directed graphs
  • The second is ‘N’ for named graph (i.e. if the graph has the ‘name’ vertex attribute set)
  • The third is ‘W’ for weighted graphs (i.e. if the ‘weight’ edge attribute is set)
  • The fourth is ‘B’ for bipartite graphs (i.e. if the ‘type’ vertex attribute is set)

You can print nodes and edges as follows:

# nodes and node count
V(g)
## + 5/5 vertices, named, from c7ecafd:
## [1] Alice     Bob       Cecil     David     Esmeralda
vcount(g)
## [1] 5
# edges and edge count
E(g)
## + 6/6 edges from c7ecafd (vertex names):
## [1] Bob      ->Alice Cecil    ->Bob   Cecil    ->Alice David    ->Alice
## [5] David    ->Bob   Esmeralda->Alice
ecount(g)
## [1] 6

Attributes

A graph can have attributes for the entire graph, for nodes and for edges.

# add graph attribute 
g$name = "Alice & friends"
graph_attr(g)
## $name
## [1] "Alice & friends"
# add node attribute
V(g)$height = c(122, 155, 178, 167, 198)
vertex_attr(g)
## $name
## [1] "Alice"     "Bob"       "Cecil"     "David"     "Esmeralda"
## 
## $age
## [1] 48 33 45 34 21
## 
## $gender
## [1] "F" "M" "F" "M" "F"
## 
## $height
## [1] 122 155 178 167 198
# add edge attribute
E(g)$weight = c(1, 2, 2, 5, 5, 4)
edge_attr(g)
## $sameDept
## [1] FALSE FALSE  TRUE FALSE FALSE  TRUE
## 
## $friendship
## [1] 4 5 5 2 1 1
## 
## $advice
## [1] 4 5 5 4 2 3
## 
## $weight
## [1] 1 2 2 5 5 4
# print the new graph 
g
## IGRAPH c7ecafd DNW- 5 6 -- Alice & friends
## + attr: name (g/c), name (v/c), age (v/n), gender (v/c), height (v/n),
## | sameDept (e/l), friendship (e/n), advice (e/n), weight (e/n)
## + edges from c7ecafd (vertex names):
## [1] Bob      ->Alice Cecil    ->Bob   Cecil    ->Alice David    ->Alice
## [5] David    ->Bob   Esmeralda->Alice
# delete attribute
g <- delete_graph_attr(g, "name")
g <- delete_vertex_attr(g, "height")
g <- delete_edge_attr(g, "weight")

Iterators

Iterators allow to access groups of nodes and edges in a smart way.

# access nodes 
V(g)[1]
## + 1/5 vertex, named, from c7ecafd:
## [1] Alice
V(g)["Alice"]
## + 1/5 vertex, named, from c7ecafd:
## [1] Alice
V(g)[1:3]
## + 3/5 vertices, named, from c7ecafd:
## [1] Alice Bob   Cecil
V(g)[age <= 30]
## + 1/5 vertex, named, from c7ecafd:
## [1] Esmeralda
V(g)[gender == "M"]
## + 2/5 vertices, named, from c7ecafd:
## [1] Bob   David
# access edges 
E(g)[1]
## + 1/6 edge from c7ecafd (vertex names):
## [1] Bob->Alice
E(g)["Bob|Alice"]
## + 1/6 edge from c7ecafd (vertex names):
## [1] Bob->Alice
E(g)[1:3]
## + 3/6 edges from c7ecafd (vertex names):
## [1] Bob  ->Alice Cecil->Bob   Cecil->Alice
E(g)[sameDept == TRUE]
## + 2/6 edges from c7ecafd (vertex names):
## [1] Cecil    ->Alice Esmeralda->Alice

Switch between graph representations

We have 3 main graph representations:

  1. the igraph internal representation
  2. the adjcency matrix representation
  3. the data frame representation

Use each representation for the right task, for instance:

  1. compute a node centrality measure: use igraph representation
  2. find the dominant eigenvector using the power method: use adjcency matrix representation
  3. filter nodes or edges according to some condition: use data frame representation

From data frame to igraph and back

# read graph from data frame
actors <- data.frame(
  name = c("Alice", "Bob", "Cecil", "David", "Esmeralda"),
  age = c(48, 33, 45, 34, 21),
  gender = c("F", "M", "F", "M", "F")
)

relations <- data.frame(
  from = c("Bob", "Cecil", "Cecil", "David", "David", "Esmeralda"),
  to = c("Alice", "Bob", "Alice", "Alice", "Bob", "Alice"),
  sameDept = c(FALSE, FALSE, TRUE, FALSE, FALSE, TRUE),
  friendship = c(4, 5, 5, 2, 1, 1),
  advice = c(4, 5, 5, 4, 2, 3)
)

g = graph_from_data_frame(vertices = actors, d = relations, directed = TRUE)

as_data_frame(g, what="vertices")
##                name age gender
## Alice         Alice  48      F
## Bob             Bob  33      M
## Cecil         Cecil  45      F
## David         David  34      M
## Esmeralda Esmeralda  21      F
as_data_frame(g, what="edges")
##        from    to sameDept friendship advice
## 1       Bob Alice    FALSE          4      4
## 2     Cecil   Bob    FALSE          5      5
## 3     Cecil Alice     TRUE          5      5
## 4     David Alice    FALSE          2      4
## 5     David   Bob    FALSE          1      2
## 6 Esmeralda Alice     TRUE          1      3
as_data_frame(g, what="both")
## $vertices
##                name age gender
## Alice         Alice  48      F
## Bob             Bob  33      M
## Cecil         Cecil  45      F
## David         David  34      M
## Esmeralda Esmeralda  21      F
## 
## $edges
##        from    to sameDept friendship advice
## 1       Bob Alice    FALSE          4      4
## 2     Cecil   Bob    FALSE          5      5
## 3     Cecil Alice     TRUE          5      5
## 4     David Alice    FALSE          2      4
## 5     David   Bob    FALSE          1      2
## 6 Esmeralda Alice     TRUE          1      3

From igraph to adjacency matrix and back

# from igraph to adjacency matrix
# sparse matrix
as_adjacency_matrix(g)
## 5 x 5 sparse Matrix of class "dgCMatrix"
##           Alice Bob Cecil David Esmeralda
## Alice         .   .     .     .         .
## Bob           1   .     .     .         .
## Cecil         1   1     .     .         .
## David         1   1     .     .         .
## Esmeralda     1   .     .     .         .
# non-sparse matrix
as_adjacency_matrix(g, sparse = FALSE)
##           Alice Bob Cecil David Esmeralda
## Alice         0   0     0     0         0
## Bob           1   0     0     0         0
## Cecil         1   1     0     0         0
## David         1   1     0     0         0
## Esmeralda     1   0     0     0         0
# weighted matrix
as_adjacency_matrix(g, attr = "friendship")
## 5 x 5 sparse Matrix of class "dgCMatrix"
##           Alice Bob Cecil David Esmeralda
## Alice         .   .     .     .         .
## Bob           4   .     .     .         .
## Cecil         5   5     .     .         .
## David         2   1     .     .         .
## Esmeralda     1   .     .     .         .
# from adjacency matrix to igraph
# non-weighted graph
(A = as_adjacency_matrix(g))
## 5 x 5 sparse Matrix of class "dgCMatrix"
##           Alice Bob Cecil David Esmeralda
## Alice         .   .     .     .         .
## Bob           1   .     .     .         .
## Cecil         1   1     .     .         .
## David         1   1     .     .         .
## Esmeralda     1   .     .     .         .
graph_from_adjacency_matrix(A)
## IGRAPH 1b1c4f0 DN-- 5 6 -- 
## + attr: name (v/c)
## + edges from 1b1c4f0 (vertex names):
## [1] Bob      ->Alice Cecil    ->Alice David    ->Alice Esmeralda->Alice
## [5] Cecil    ->Bob   David    ->Bob
# undirected graph
graph_from_adjacency_matrix(A, mode = "undirected")
## IGRAPH 1c2f755 UN-- 5 6 -- 
## + attr: name (v/c)
## + edges from 1c2f755 (vertex names):
## [1] Alice--Bob       Alice--Cecil     Alice--David     Alice--Esmeralda
## [5] Bob  --Cecil     Bob  --David
(A = as_adjacency_matrix(g, attr = "friendship"))
## 5 x 5 sparse Matrix of class "dgCMatrix"
##           Alice Bob Cecil David Esmeralda
## Alice         .   .     .     .         .
## Bob           4   .     .     .         .
## Cecil         5   5     .     .         .
## David         2   1     .     .         .
## Esmeralda     1   .     .     .         .
# multi-graph
graph_from_adjacency_matrix(A)
## IGRAPH 6540ab8 DN-- 5 18 -- 
## + attr: name (v/c)
## + edges from 6540ab8 (vertex names):
##  [1] Bob      ->Alice Bob      ->Alice Bob      ->Alice Bob      ->Alice
##  [5] Cecil    ->Alice Cecil    ->Alice Cecil    ->Alice Cecil    ->Alice
##  [9] Cecil    ->Alice David    ->Alice David    ->Alice Esmeralda->Alice
## [13] Cecil    ->Bob   Cecil    ->Bob   Cecil    ->Bob   Cecil    ->Bob  
## [17] Cecil    ->Bob   David    ->Bob
# weighted graph on weight attribute
graph_from_adjacency_matrix(A, weighted = TRUE)
## IGRAPH d8d0a35 DNW- 5 6 -- 
## + attr: name (v/c), weight (e/n)
## + edges from d8d0a35 (vertex names):
## [1] Bob      ->Alice Cecil    ->Alice David    ->Alice Esmeralda->Alice
## [5] Cecil    ->Bob   David    ->Bob
# weighted graph on friendship attribute
graph_from_adjacency_matrix(A, weighted = "friendship")
## IGRAPH 06b864c DN-- 5 6 -- 
## + attr: name (v/c), friendship (e/n)
## + edges from 06b864c (vertex names):
## [1] Bob      ->Alice Cecil    ->Alice David    ->Alice Esmeralda->Alice
## [5] Cecil    ->Bob   David    ->Bob

Read and write graph on disk

# write to graphml format
write_graph(g, file="Alice.xml", format="graphml")

# read from graphml format (notice the new id vertex attribute)
read_graph(file="Alice.xml", format="graphml")
## IGRAPH 9d7ba65 DN-- 5 6 -- 
## + attr: name (v/c), age (v/n), gender (v/c), id (v/c), sameDept (e/l),
## | friendship (e/n), advice (e/n)
## + edges from 9d7ba65 (vertex names):
## [1] Bob      ->Alice Cecil    ->Bob   Cecil    ->Alice David    ->Alice
## [5] David    ->Bob   Esmeralda->Alice

Visualize a graph

igraph have some basic visualization skills. Read the igraph plot manual for more.

# plot graph
plot(g, vertex.shape = "none")

# visualization parameters for graph, nodes and edges
plot(g, 
     vertex.size = 20, 
     vertex.color = "white", 
     vertex.shape = "square", 
     vertex.label = letters[1:vcount(g)],
     edge.width = 2, 
     edge.color = "black", 
     edge.lty = 3, 
     edge.label = LETTERS[1:ecount(g)], 
     edge.curved = TRUE)

Layouts

You can visualize the same graph with different layouts.

z = make_graph("Zachary")


# Fruchterman and Reingold (force-based)
plot(z, layout = layout_with_fr(z), vertex.shape = "none")

# Kamada-Kawai (force-based)
plot(z, layout = layout_with_kk(z), vertex.shape = "none")

# In circle
plot(z, layout = layout_in_circle(z), vertex.shape = "none")

# On grid
plot(z, layout = layout_on_grid(z), vertex.shape = "none")

# Random
plot(z, layout = layout_randomly(z), vertex.shape = "none")

# tries to choose an appropriate layout algorithm for the graph
plot(z, layout = layout_nicely(z), vertex.shape = "none")

# 3D
#g = make_lattice(c(4, 4, 4))
#coords = layout_with_fr(g, dim=3)
#rglplot(g, layout=coords, vertex.shape = "none")


# save the layout of the graph in a variable
coords = layout_nicely(z)
coords[1:5, ]
##              [,1]      [,2]
## [1,]  1.987202531 1.7269579
## [2,]  1.274151716 0.9356515
## [3,] -0.005908832 0.3641919
## [4,]  0.645811936 2.2827358
## [5,]  3.148955309 3.4071657
plot(z, layout = coords, vertex.shape = "none")