igraph nonreciprocal edges after converting to undirected graph using mutual - r

I'm working on a directed graph in igraph for R. I'm trying to convert it to an undirected graph where just reciprocal edges of the former persist. Should be easy but I'm getting strange results.
first I did it like that
library(igraph)
load("dmNet.Rdata")
#http://www.unet.univie.ac.at/~a0406222/dmNet.Rdata
recNet <- as.undirected(net, mode = "mutual",edge.attr.comb="sum")
when I check E(recNet)$weight there are a lot of edges with a weight of 1, which should not be possible since the sum of two reciprocal edges has to be at least 2. Then I did it like that
recNet <- as.undirected(net, mode = "mutual",edge.attr.comb="c")
now I can see that there are actually some edges containing just one value. My new graph recNet seems to contain nonreciprocal edges of net. What am I doing wrong, or am I missunderstandig the "mutual option"?

This happens because some edges are self-loops in your graph. All the edges that end up with a weight of 1 are self-loops:
all(which(E(recNet)$weight == 1) %in% which(is.loop(recNet)))
# [1] TRUE
Apparently, a self-loop is considered as a mutual edge in a directed graph. If you want to consider self-loops as non-mutual, then you can just remove them from the graph. Be careful, though, because some vertices have multiple self-loops, and you might not want to remove these.

Related

Automatically curving an arc when it is overlapping with another one

I am automatically generating graphs whose nodes need to be in fixed positions. For example:
There is actually an arc from node V4 to node V16, but we annot see it because there are also arcs from V4 to V10 and from V10 to V16.
Note that both the nodes and the arcs are generated automatically, and that the positions may vary, so I would need an automated way to curve arcs that are hidden behind other arcs.
Also note that none of these solutions are valid: igraph: Resolving tight overlapping nodes ; Using igraph, how to force curvature when arrows point in opposite directions. The first one simply places de nodes in a certain way, but my nodes need to be fixed. The second one simply deals with pairs of nodes that have two arcs connecting them going in the opposite direction.
UPDATE: The construction of the graph is the result of the learning process of the graph that forms a Bayesian Network using bnlearn library, so I am not very sure how could I produce a reproducible example. The positions of the nodes are fixed because they represent positions. I actually need some magic, some kind of detection of overlapping arcs: If two arcs overlap, curve one of them slightly so that it can be seen. I know from the linked questions that curving an arc is an option, so I thought maybe this kind of magic could be achieved
One solution would be to use the qgraph package. In the example below it automatically curves the bidirectional edges:
library(igraph)
library(qgraph)
# the raster layout
layout <- cbind(1:3, rep(1:3, each = 3))
# fully connected network
adj <- matrix(1, 9, 9)
# plot directed and undirected network
layout(matrix(1:2, 1, 2))
qgraph(adj, layout = layout, directed = FALSE, title = "undirected")
qgraph(adj, layout = layout, directed = TRUE, title = "directed") # automatically curves the bidirectional arrows
To convert an igraph object to something qgraph can use, all you need is an edgelist or adjacency matrix:
g <- make_ring(9)
edgeList <- do.call(rbind, igraph::get.adjedgelist(g))
qgraph(edgeList)
If you also want to include the axes, you can do so using axis() since qgraph uses base graphics. However, you probably have to tinker with par() as well to make it look nice.

Number of vertices in Igraph in R

I'm fairly new to IGraph in R.
I'm doing community detection using IGraph and have already built my communities /clusters using the walktrap technique.
Next, within each cluster, I want to count the number of vertices between each two certain vertices. The reason I want to do this is, for each vertex XX, I want to list vertices that are connected to XX via say max 3 vertices, meaning no further than 3 vertices away from XX.
Can anyone help how this can be done in R please?
making a random graph (for demonstration):
g <- erdos.renyi.game(100, 1/25)
plot(g,vertex.size=3)
get walktrap communities and save as vertex attribute:
V(g)$community<-walktrap.community(g, modularity = TRUE, membership = TRUE)$membership
V(g)$community
now make a subgraph containing only edges and vertices of one community, e.g. community 2:
sub<-induced.subgraph(g,v=V(g)$community==2)
plot(sub)
make a matrix containing all shortest paths:
shortestPs<-shortest.paths(sub)
now count the number of shortest paths smaller or equal to 3.
I also exclude shortest paths from each node to itself (shortestPaths!=0).
also divide by two because every node pair appears twice in the matrix for undirected graphs.
Number_of_shortest_paths_smaller_3 <- length(which(shortestPs<=3 & shortestPs!=0))/2
Number_of_shortest_paths_smaller_3
Hope that's close to what you need, good luck!

How to study the interaction between a set of nodes when the network is quite dense, using igraph?

I have 4 undirected graph with 1000 vertices and 176672, 150994, 193477, 236060 edges. I am trying to see interaction between a specific set of nodes (16 in number) for each graph. This visualization in tkplot is not feasible as 1000 vertices is already way too much for it. I was thinking of if there is some way to extract the interaction of these 16 nodes from the parent graph and view separately, which will be then more easy to handle and work with in tkplot. I don't want the loss of information as in what is the node(s) in he path of interaction if it comes from other than 16 pre-specified nodes. Is there a way to achieve it?
In such a dense graph, if you only take the shortest paths connecting each pair of these 16 vertices, you will still get a graph too large for tkplot, or even to see any meaningful on a cairo pdf plot.
However, if you aim to do it, this is one possible way:
require(igraph)
g <- erdos.renyi.game(n = 1000, p = 0.1)
set <- sample(1:vcount(g), 16)
in.shortest.paths <- NULL
for(v in set){
in.shortest.paths <- c(in.shortest.paths,
unlist(get.all.shortest.paths(g, from = v, to = set)$res))
}
subgraph <- induced.subgraph(g, unique(in.shortest.paths))
In this example, subgraph will include approx. half of all the vertices.
After this, I think you should consider to find some other way than visualization to investigate the relationships between your vertices of interest. It can be some topological metric, but it really depends on the aims of your analysis.

Choosing vertices by edge weight

I have a network with two types of edges, one with edge$weight=1 and the other edge$weight=2 (to define different relationships e.g. marriage vs. kinship). I want to choose the neighbors of nodes that are linked by edge$weight=2. Then, after getting the vertex names of the neighbors, I will calculate their degree only for edge$weight=1.
It seems simple, but the following code does not give the correct neighbor names:
V(net)[E(net)[E(net)$weight==2]]
Is there another way to get vertex names with respect to the edge type?
I think you are looking for the adj function which will return the vertices adjacent to a given edge set. In your case you can choose all the relevant vertices by using V(net)[ adj(E(net)$weight==2) ]
For example:
# make a sample graph with edge weights 1 or 2
net <- graph.full(20)
E(net)$weight <- sample(1:2,ecount(net),replace=T)
# now select only those vertices connected by an edge with weight == 2
V(net)[ adj(E(net)$weight==2) ]

DFS on undirected graph complexity

Let's say I have an undirected graph with V nodes and E edges.If I represent the graph with adjacency lists,if I have a representation of an edge between x and y,I must also have a representation of the edge between y and x in the adjacency list.
I know that DFS for directed graphs has V+E complexity.For undirected graphs doesn't it have v+2*e complexity ,because you visit each edge 2 times ?Sorry if it's a noobish question..I really want to understand this think.Thank you,
The complexity is normally expressed O(|V| + |E|) and this isn't affected by the factor of 2.
But the factor of 2 is actually there. One undirected edge behaves just line 2 directed edges. E.g. the algorithm (for a connected undirected graph) is
visit(v) {
mark(v)
for each unmarked w adjacent to v, visit(w)
}
The for loop will consider each edge incident to each vertex once. Since each undirected edge is incident to 2 vertices, it will clearly be considered twice!
Note the undirected DFS doesn't have to worry about restarting from all the sources. You can pick any vertex.

Resources