Vertex Labels in igraph R - r

I am using igraph to plot a non directed force network.
I have a dataframe of nodes and links as follows:
> links
source target value sourceID targetID
1 3 4 0.6245 1450552 1519842
2 6 8 0.5723 2607133 3051992
3 9 7 0.7150 3101536 3025831
4 0 1 0.7695 401517 425784
5 2 5 0.5535 1045501 2258363
> nodes
name group size
1 401517 1 8
2 425784 1 8
3 1045501 1 8
4 1450552 1 8
5 1519842 1 8
6 2258363 1 8
7 2607133 1 8
8 3025831 1 8
9 3051992 1 8
10 3101536 1 8
I plot these using igraph as follows:
gg <- graph.data.frame(links,directed=FALSE)
plot(gg, vertex.color = 'lightblue', edge.label=links$value, vertex.size=1, edge.color="darkgreen",
vertex.label.font=1, edge.label.font =1, edge.label.cex = 1,
vertex.label.cex = 2 )
On this plot, igraph has used the proxy indexes for source and target as vertex labels.
I want to use the real ID's, in my links table expressed as sourceID and targetID.
So, for:
source target value sourceID targetID
1 3 4 0.6245 1450552 1519842
This would show as:
(1450552) ----- 0.6245 ----- (1519842)
Instead of:
(3) ----- 0.6245 ----- (4)
(Note that the proxy indexes are zero indexed in the links dataframe, and one indexed in the nodes dataframe. This offset by 1 is necessary for igraph plotting).
I know I need to somehow match or map the proxy indexes to their corresponding name within the nodes dataframe. However, I am at a loss as I do no not know the order in which igraph plots labels.
How can I achieve this?
I have consulted the following questions to no avail:
Vertex Labels in igraph with R
how to specify the labels of vertices in R
R igraph rename vertices

You can specify the labels like this:
library(igraph)
gg <- graph.data.frame(
links,directed=FALSE,
vertices = rbind(
setNames(links[,c(1,4)],c("id","label")),
setNames(links[,c(2,5)], c("id","label"))))
plot(gg, vertex.color = 'lightblue', edge.label=links$value,
vertex.size=1, edge.color="darkgreen",
vertex.label.font=1, edge.label.font =1, edge.label.cex = 1,
vertex.label.cex = 2 )
You could also pass
merge(rbind(
setNames(links[,c(1,4)],c("id","label")),
setNames(links[,c(2,5)], c("id","label"))),
nodes,
by.x="label", by.y="name")
to the vertices argument if you needed the other node attributes.
Data:
links <- read.table(header=T, text="
source target value sourceID targetID
1 3 4 0.6245 1450552 1519842
2 6 8 0.5723 2607133 3051992
3 9 7 0.7150 3101536 3025831
4 0 1 0.7695 401517 425784
5 2 5 0.5535 1045501 2258363")
nodes <- read.table(header=T, text="
name group size
1 401517 1 8
2 425784 1 8
3 1045501 1 8
4 1450552 1 8
5 1519842 1 8
6 2258363 1 8
7 2607133 1 8
8 3025831 1 8
9 3051992 1 8
10 3101536 1 8")

It appears I was able to repurpose the answer to this question to achieve this.
r igraph - how to add labels to vertices based on vertex id
The key was to use the vertex.label attribute within plot() and a select a sliced subset of nodes$names.
For our index we can use the ordered default labels returned in igraph automatically. To extract these, you can type V(gg)$names.
Within plot(gg) we can then write:
vertex.label = nodes[c(as.numeric(V(gg)$name)+1),]$name
# 1 Convert to numeric
# 2 Add 1 for offset between proxy links index and nodes index
# 3 Select subset of nodes with above as row index. Return name column
As full code:
gg <- graph.data.frame(links,directed=FALSE)
plot(gg, vertex.color = 'lightblue', edge.label=links$value, vertex.size=1, edge.color="darkgreen",
vertex.label.font=1, edge.label.font =1, edge.label.cex = 1,
vertex.label.cex = 2, vertex.label = nodes[c(as.numeric(V(gg)$name)+1),]$name)
With the data above, this gave:

The easiest solution would be to reorder the columns of links, because according to the documentation:
"If vertices is NULL, then the first two columns of d are used as a symbolic edge list and additional columns as edge attributes."
Hence, your code will give the correct output after running:
links <- links[,c(4,5,3)]

Related

Is there any way that can convert RGB/CIElab value into image in R?

I have a dataframe that contains pixels coordinates and its RGB and CIElab value for each.
These values are abstracted from a certain image. After changing some RGB/CIElab value in this dataframe, I would like to let the 'data' go back to an 'image'.
I include a sample with variable r, g, b, x, and y. r, g, and b contain the RGB value of each pixel.x and y indicate the pixel's coordinate.
So basically, I would like to create a picture with three color channels(rgb) with this dataframe. But I have no idea how to implement the process. Abstracting RGB value from image is easy. However, inversing the process is quite difficult.
r g b x y
1 0.91373 0.72157 0.45098 1 1
2 0.86275 0.59216 0.21961 2 1
3 0.84314 0.56471 0.18039 3 1
4 0.83922 0.56078 0.17647 4 1
5 0.84314 0.56471 0.18039 5 1
6 0.84706 0.56863 0.18431 6 1
7 0.85098 0.57255 0.18824 7 1
8 0.85490 0.57647 0.19216 8 1
9 0.85490 0.57647 0.19216 9 1
10 0.85098 0.57255 0.18824 10 1
Update:
I tried to use as.cimg function
my_cimg <- as.cimg(unlist(rgb_image[1:3]), x=length(unique(rgb_image$x)), y=length(unique(rgb_image$y)),cc = 3)
And it works!!!
Thanks!

Color nodes in directed network in R

I have a directed network with only two type of nodes, A and B.The direction is always from any given A, to any given B. No other direction is possible.
Edge list looks like this:
edges <- read.table(text = "
from to weight
1 6 1.2
3 7 1.4
4 6 1.2
1 7 1.2
2 8 1.2
1 9 1.2
5 10 1.2 ", header=T )
Nodes list looks like this:
nodes
id
1 1
2 1
3 3
4 4
5 5
6 6
7 7
8 B
9 9
10 10
The graph is created using the igraph package.
g <- graph_from_data_frame(d = edges, vertices=nodes, directed = TRUE)
Is it possible to color nodes based on whether they are from or to in the edgeslist, without adding other variables/labels to the nodeslist?
(I tried coloring nodes like so, but realized it does not make much sense)
plot(g, vertex.color=V(g$edges=='from'))
I am not 100% sure, but I think what you are looking for doesn't really exist. vertex.color needs a vector of colors, one color for each of the vertices.
In the meantime, as a workaround, you can use the output of degree to select vertices with in (or out) degree of 0 or higher:
plot(g,
vertex.color=ifelse(degree(g, mode = "out")>0, "red", "black"),
size=15)

Scale-Free graph, access the vertices of the graph

I'm trying to generate a Scale-Free graph, according to the Barabasi-Albert Model. I used the barabasi.game function, gerating 1000 vertices of the graph:
library('igraph')
g <- barabasi.game(1000)
I would like, now, to pick at random a vertex of g and, among its neighbors, to pick at random another vertex. How can I access the vertices of the graph?
Edit. I had problems with the solution kindly suggested by G5W. For this graph:
I obtained, from the first instruction
RV<-sample(V(g), 1)
the result RV=4, but from the second
RVn<-sample(neighbors(g, RV, mode="all"), 1)
I obtained RVn=1. As we can see from the pic this is a mistake; moreover, instruction
neighbors(g, i)
returns
+ 1/10 vertex, named, from 57207c1:
[1] 2
Why?
Thank you.
Modified
You can pick a random vertex and a random neighbor like this:
RV = sample(V(g), 1)
NRV = neighbors(g, RV, mode="all")
RVn = ifelse(length(NRV) == 1, NRV, sample(NRV, 1))
This should work when RV has one neighbor or more.
I would like to mention that most vertices have only one neighbor, so the random selection of a neighbor doesn't do much.
table(sapply(V(g), function(v) length(neighbors(g, v, mode="all"))))
1 2 3 4 5 6 7 8 9 10 11 12 13 14 18 21 37 38 92
657 183 67 35 12 11 3 7 4 6 2 4 1 2 2 1 1 1 1

How to get the edge list of a strongly connected components in a graph?

I have a weighted directed multigraph with a few cycles. With clusters function in igraph package, I can get the nodes belongs to a strongly connected components. But I need the path/order of the nodes that form a cycle.
EDIT after #josilber's response
I have a very dense graph, with 30 nodes and around 2000 edges. So graph.get.subisomorphisms.vf2 takes too long to run in my case.
I'm not familiar with graph algorithm, but I'm thinking maybe do a DFS to the original or reverse graph and use the order or order.out might work, but not sure.
Or any other ideas to make this run faster are welcomed!
Example
library(igraph)
set.seed(123)
graph <-graph(c(1,2,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,8,10,9,10,9,10,10,11,10,5,11,12,12,13,13,14,14,15,14,20,15,16, 16,17,17,18,18,19,19,20,20,21,21,1,22,23,22,23,23,22),directed=T)
E(graph)$weight= runif(ecount(graph),0,10)
> clusters(graph, "strong")
$membership
[1] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1
$csize
[1] 2 21
$no
[1] 2
How do I get the edge list of a cycle with the highest weight here? Thanks!
Assuming that all nodes in each strongly connected component form a cycle and that you're only interested in this large cycle (e.g. in your example you're just interested in the cycle with nodes 1:21 and the cycle with nodes 22:23), then you can extract the node order that forms the cycle, grab the weights on the edges, and compute the total weight of the cycle.
# Compute the node order of the cycle for each component by performing an
# isomorphism with a same-sized directed ring graph
clusts <- clusters(graph, "strong")
(cycles <- lapply(1:clusts$no, function(x) {
sg <- induced.subgraph(graph, clusts$membership == x)
n <- sum(clusts$membership == x)
col <- rep(c(1, 0), c(1, n-1)) # Used to grab isomorphism starting at 1
sg.idx <- graph.get.subisomorphisms.vf2(sg, graph.ring(n, directed=TRUE), col, col)[[1]]
which(clusts$membership == x)[sg.idx]
}))
# [[1]]
# [1] 22 23
#
# [[2]]
# [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
Now you can grab the sum of the edge weights for each cycle:
sapply(cycles, function(x) sum(graph[from=x, to=c(tail(x, -1), x[1])]))
# [1] 8.833018 129.959437
Note that this is in general NP-hard, because finding a Hamiltonian cycle in a general graph is NP-hard. Therefore the graph.get.subisomorphisms.vf2 call could be quite slow for large graphs.

node attribute csv igraph

I have a large number of adjacency matrices, in csv format exported from excel. I also have a large number of csv. files with vertex attribute data.
I have linked them in SNA but igraph goes further functionally, so I am looking to move to it, but I am failing to be able to build the graph+attribute files.
I am looking to set up some code that will be a workhorse for doing a range of plots.
Although there seem many ways to link these two data sets it seemed this was the simplest:
To make the adjacency matrix in the csv a data frame (cut down for missing vertex data) I use:
m <- read.table(header=TRUE, check.names=FALSE, textConnection("
2 3 4 5 6 7
2 0 1 1 0 1 0
3 1 0 0 0 1 0
4 0 0 0 0 0 0
5 1 0 1 0 0 1
6 0 0 0 0 0 0
7 1 1 0 1 0 0
"))
In the case of having both vertex and row names in the original file, the imported attributes file has both vertex names and 'row.names' which correspond to the node names. Hex.ed[1,1] gives the value of the attribute for the first node in the m network, i.e. node 2:
Hex.ed <- read.table(header=TRUE, textConnection("
HH Emo Extra Aggr Consci OTE
2 3.3750 3.0000 3.0000 3.0000 3.0625 3.4375
3 3.5625 2.9375 3.0625 3.0000 3.3125 3.6250
4 3.2500 2.8750 3.7500 3.2500 3.8750 3.5000
5 3.6875 3.1250 3.3750 3.5625 3.6250 3.3125
6 3.3125 3.0000 3.3125 3.8750 3.2500 3.6875
7 3.8125 3.2500 3.5625 2.8750 3.6875 3.4375
"))
g <- graph.data.frame(m, directed=TRUE, vertices=Hex.ed)
However, I get the error: Error in graph.data.frame(m, directed = TRUE, vertices = Hex.ed) : Duplicate vertex names
I get a different error message:
Error in graph.data.frame(m, directed = TRUE, vertices = Hex.ed) :
Some vertex names in edge list are not listed in vertex data frame
but this is because you were not running the example in the question, but used your complete data set, possibly.
Anyway, graph.data.frame does not use adjacency matrices. From the docs at http://igraph.sourceforge.net/doc/R/graph.data.frame.html:
... the first two columns of d are used as a symbolic edge list and
additional columns as edge attributes. The names of the attributes are
taken from the names of the columns.
If you cared about reading the manual you would have seen an example at the bottom.
If you have an adjacency matrix, then you can use graph.adjacency to create the graph, and then add the vertex attribute one by one:
g <- graph.adjacency(as.matrix(m))
for (i in seq_len(ncol(Hex.ed))) {
g <- set.vertex.attribute(g, colnames(Hex.ed)[i], value=Hex.ed[,i])
}
g
# IGRAPH DN-- 6 11 --
# + attr: name (v/c), HH (v/n), Emo (v/n), Extra (v/n), Aggr (v/n),
# Consci (v/n), OTE (v/n)

Resources