This should be straightforward, but I want to obtain the number of mutual edges associated with all the vertices in my graph:
library(igraph)
ed <- data.frame(from = c(1,1,2,3,3), to = c(2,3,1,1,2))
ver <- data.frame(id = 1:3)
gr <- graph_from_data_frame(d = ed,vertices = ver, directed = T)
plot(gr)
I know I can use which_mutual for edges, but is there an equivalent command for getting something like this:
# vertex edges no_mutual
# 1 2 2
# 2 1 1
# 3 2 1
UDPATE: Corrected inconsistencies in output table as pointed out by emilliman5
Here's a one-liner solution:
> table(unlist(strsplit(attr(E(gr)[which_mutual(gr)],"vnames"),"\\|")))/2
1 2 3
2 1 1
It relies on getting the vertex names for each edge in an edgelist as the "vnames" attribute being a "|"-separated string. It then splits on that, then that gives you a table of all vertexes in mutual edges, and each one appears twice per edge so divide by two.
If there's a less hacky way of getting vertex names from an edgelist, I'm sure Gabor knows it.
Here's that trick in more detail:
For your graph gr:
> E(gr)
+ 5/5 edges (vertex names):
[1] 1->2 1->3 2->1 3->1 3->2
You can get vertexes for edges thus:
> attr(E(gr),"vnames")
[1] "1|2" "1|3" "2|1" "3|1" "3|2"
So my one-liner subsets that edge list my the mutuality criterion, then manipulates the strings.
I am not sure how well this will scale, but it gets the job done. Your expected table has some inconsistencies so I did the best I could, i.e. vertex 2 only has one originating edge not 2.
mutual_edges <- lapply(V(gr), function(x) which_mutual(gr, es = E(gr)[from(x) | to(x)]))
df <- data.frame(Vertex=names(mutual_edges),
Edges=unlist(lapply(V(gr), function(x) length(E(gr)[from(x)]) )),
no_mutual=unlist(lapply(mutual_edges, function(x) sum(x)/2)))
df
# Vertex Edges no_mutual
#1 1 2 2
#2 2 1 1
#3 3 2 1
Related
I am working on a graph, where each node has an attribute "group" of the following: "Baby Product", "Book" "CE" "DVD" "Music" "Software" "Toy" "Video" "Video Games".
I would like to know how to plot a graph reppresenting those communities: there shall be 9 verticies, one for each group, and a link (possibly weighted) each time two nodes of two categories are connected.
I have tried using the igraph contract function, but this is the result:
> contract(fullnet, mapping=as.factor(products$group), vertex.attr.comb = products$group)
Error in FUN(X[[i]], ...) :
Unknown/unambigous attribute combination specification
Inoltre: Warning message:
In igraph.i.attribute.combination(vertex.attr.comb) :
Some attributes are duplicated
I guess I have misunderstood what this function is used for.
Now I am thinking about creating a new edgelist, made like the one before but instead of the Id of each vertex the name of the group. Sadly, I do not know how to do this in a fast way on an edgelist of over 1200000 elements.
Thank you very much in advance.
I think using contract() should be correct. In the example code below, I added an anonymous function to vertex.attr.comb to combine the vertices by group. Then, simplify() removes loop edges and calculate the sum of edge weight.
# Create example graph
set.seed(1)
g <- random.graph.game(10, 0.2)
V(g)$group <- rep(letters[1:3], times = c(3, 3, 4))
E(g)$weight <- 1:length(E(g))
E(g)
# + 9/9 edges from 7017c6a:
# [1] 2-- 3 3-- 4 4-- 7 5-- 7 5-- 8 7-- 8 3-- 9 2--10 9--10
E(g)$weight
# [1] 1 2 3 4 5 6 7 8 9
# Contract graph by `group` attribute of vertices
g1 <- contract(g, factor(V(g)$group),
vertex.attr.comb = function(x) levels(factor(x)))
# Remove loop edges and compute the sum of edge weight by group
g1 <- simplify(g1, edge.attr.comb = "sum")
E(g1)
# + 3/3 edges from a852397:
# [1] 1--2 1--3 2--3
E(g1)$weight
# [1] 2 15 12
I use igraph cluster_spinglass to detect compartments (communities) in a directed network but that only works for connected components
g <- graph_from_literal( 1 -+ 4 -+ 7,2 -+ 5 -+ 9, 4+-5,
3 -+ 6,5 -+8, 8-+ 9, simplify = FALSE)
m<-cluster_spinglass(g)
Gives an error, the solution is to extract the connected component
dg <- components(g)
g1 <- induced_subgraph(g, which(dg$membership == which.max(dg$csize)))
m<-cluster_spinglass(g1)
I get the memberships of the nodes (vertices) with
m$membership
But here I don't have all the nodes of the original network g, I would like to add another group with these nodes so I have all the original nodes clasified in different groups.
You can just transfer this into your original graph g.
In your example, I think that you just want the vertices in the
other connected component to be another community, it suffices to assign all nodes in the second component to group 3.
V(g)$membership = 3
V(g)[V(g1)$name]$membership = m$membership
V(g)$membership
[1] 1 1 1 2 2 2 3 3 2
But in a more general example, there might be multiple components and those components might break up into multiple communities.
To cover that, you can loop through all components, compute the communities and then transfer those back to the original graph.
V(g)$membership = 0
for(comp in unique(dg$membership)) {
g1 <- induced_subgraph(g, which(dg$membership == comp))
m<-cluster_spinglass(g1)
V(g)[V(g1)$name]$membership = m$membership + max(V(g)$membership)
}
V(g)$membership
[1] 1 1 1 2 2 2 3 3 2
I have following sample for a graph in R igraph:
# Erdos
g <- erdos.renyi.game(100, 1/100)
V(g)$size<-seq(0.05,1,0.05)
# Draw nodes and save positions
locs <- layout.fruchterman.reingold(g)
plot(g, layout=locs, vertex.label=NA, main="Original")
# Show igraph data
g
Generally, I like to know how
The current node names can be replaced with new ones and
How this can be combined with adding new node information.
This is how the dataframe with the new information looks like:
node_old node_new Type More_Data
1 5 1 AA 122.5
2 2 2 BB 80.4
3 12 3 CC 104.3
"Type" and "More_Data" are the information that I like to assign to the nodes.
Thanks!
if '5' is node name, then
V(g)$label[V(g)$label=='5'] <- '1'
V(g)$Type[V(g)$label=='5'] <- 'AA'
V(g)$More_Data[V(g)$label=='5'] <- 122.5
if '5' is 5th node,
V(g)$Type[5] <- 'AA'
V(g)$More_Data[5] <- 122.5
I'm very new to R and trying to calculate the adjacent vertices of a graph, which is obtained from deleting certain nodes from an original graph.
However, the output of the result doesn't match with the plot of the graph.
For example:
library(igraph)
g <- make_ring(8)
g <- add_edges(g, c(1,2, 2,7, 3,6, 4,5, 8,2, 6,2))
V(g)$label <- 1:8
plot(g)
h <- delete.vertices(g, c(1,2))
plot(h)
If I compute:
adjacent_vertices(h,6)= 5
However, I want the output to be 3,5,7 as the plot shows. The problem lies in the fact that it doesn't know I'm trying to find the adjacent vertices of node labelled 6.
Could someone please help. Thanks.
The issue here is that when you delete the vertices, the indices for the remaining vertices are shifted down to [0,6]:
> V(h)
+ 6/6 vertices:
[1] 1 2 3 4 5 6
To find the neighbors, using the original vertex names, you could then simply offset the values by the number of vertices removed, e.g.:
> neighbors(h, 6 - offset) + offset
+ 3/6 vertices:
[1] 3 5 7
A better approach, however, would be to refer to the vertex labels instead of using the indices:
> V(g)$label
[1] 1 2 3 4 5 6 7 8
> V(h)$label
[1] 3 4 5 6 7 8
> V(h)[V(h)$label == 6]
+ 1/6 vertex:
[1] 4
To get the neighbors of your vertex of interest, you can modify your code to look like:
> vertex_of_interest <- V(h)[V(h)$label == 6]
> neighbors(h, vertex_of_interest)$label
[1] 3 5 7
I have an igraph graph and want to simply get each edge's from_id and to_id. For example:
g <- erdos.renyi.game(4, 1, type="gnm", directed=FALSE)
E(g)[1] # will return some edge, possibly not the same one
# Edge sequence:
# e
# e [1] 3 -- 1
What I want is to get two variables v1, v2 where v1 = 3 and v2 = 1 (equivalent to v1 = 1 and v2 = 3). I want to do this for all edges in the graph E(g)[x], where x is the loop variable. Is there any way to do this?
Thanks
get.edges() returns all edges, get.edge() returns one edge. If you need to iterate over all edges, then call get.edges() and go over all lines of the two-column matrix, with apply(), or a for loop.
get.edgelist(g) is the one you want, which spits out a matrix like:
# [,1] [,2]
#[1,] 3 1
If g is you igraph then try ends(g,es = E(g))