R bnlearn undirected arcs - r

I built a graph using bnlearn:hc using the following steps:
bootstrap 500 bns using hc algorithm
calculated the best threshold
extract the best arcs with threshold > "best threshold calculated" and direction > 0.5
So if I try to bootstrap with 1 bn, to be more fast in small tests, sometimes I have some undirected arcs.
In bnlearn how I can know what are the undirected arcs from a bn object (a learned structure) and remove it? This would be the best solution ?
Tks

When there are many nodes it can be hard to pick out the undirected arcs in a graph. In this case you can use undirected.arcs() to find them.
Usage is as follows:
boot = boot.strength(data = df, R=500, algorithm = 'hc',
algorithm.args = list(score = 'bde'))
boot.avg = averaged.network(boot)
undirected.arcs(boot.avg)
You can check the scores of each arc direction to make sure one isn't greater than the other:
score(set.arc(boot.avg, from="A", to="B", df)
score(set.arc(boot.avg, from="B", to="A", df)
And then finally you will want to set a direction like so:
boot.avg = set.arc(boot.avg, from="A", to="B")
If you want to remove the arc entirely you can do so with:
boot.avg = drop.arc(boot.avg, from="A", to="B")

To see which arcs are undirected you can plot the network. Use plot(network) or, if you have the package Rgraphviz, you can use graphviz.plot(network).

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.

R iGraph: degree in the case of bidirectional edges

I have noticed that the function degree in iGraph doesn't straighforwardly allow to calculate the degree of the undirected skeleton graph of a directed graph, whenever bidirectional edges are involved.
For example,
g <-graph_from_literal( a-+b,a++c,d-+a,a-+e,a-+f )
d1 <- degree(g,v='a',mode="all")
# 6
nn <- unique(neighbors(g,'a',mode='all'))
d2 <- length(nn)
# 5
As I wanted d2, instead of d1, I have used a different route based on finding the neighbors of the considered vertex.
My question is: is there a better/faster way to do this, maybe using some other iGraph function that I'm not aware of?
Create an undirected copy of the graph, collapse the multiple edges in the undirected graph into a single edge, and then calculate the degree on that:
> g2 <- as.undirected(g, mode="collapse")
> degree(g2)

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.

Interpreting arguments in watts.strogatz.game() in igraph using R

I am having trouble interpreting the arguments in the watts strogatz model in igraph and the documentation doesn't really help.
If I generate a network:
watts.strogatz.game(dim=1,size=2000,nei=10, p=0.01)
Here the size argument should indicate the number of nodes and the p argument the probability of rewiring.
I do not undertand the dim and nei arguments. Does dim mean the size of the network when it starts adding edges? Can someone help?
Edges are not added, but rewired.
The initial graph is a lattice, i.e., a very regular graph.
The dim and nei parameters describe this initial lattice (before any rewiring happens).
There are size^dim vertices.
Here are lattices of dimensions 1 and 2.
library(igraph)
g <- graph.lattice(5)
plot(g, layout=layout.grid(g,width=5))
plot(graph.lattice(c(5,5)))
In those examples, each vertex is connected to 1 neighbour in each direction:
you can change nei to increase this number.
g <- graph.lattice(10, nei=2)
plot(g, layout=layout.circle)
The lattices used are actually circular (I set p=0 to remove the rewiring -- you can change it to see how the model works):
g <- watts.strogatz.game(dim=1,size=10,nei=2, p=0)
plot(g)

R reciprocal edges in igraph in R

I am working with graphs in R. I am currently using igraph and I would like to be able to plot bidirectional edges "reciprocal edges" of a graph. So far I've seen it is possible to plot "bidirectional" graphs but not reciprocal edges, for example: E(1,3) and E(3,1) could potentially be represented as a bidirectional edge <-->, but instead I would like to plot two parallel edges one pointing to the opposite direction of the other || .
There exist in Rgraphviz an option when plotting "plot(rEG, recipEdges = "distinct")" that makes this, but I like more how plots look like on igraph. Thanks in advance.
In igraph, you can use the edge attribute curved to curve the edges you want.
For example, here is a graph based small adjacency matrix:
library("igraph")
adj <- matrix(c(
0,1,1,
1,0,1,
0,0,0),3,3,byrow=TRUE)
library("igraph")
G <- graph.adjacency(adj)
The edge between node 0 and 1 is bidirected (Actually, it isn't, it are two edges and they just look like a bidirected edge because they are straight).:
plot(G)
To change this, we can use the edgelist:
E <- t(apply(get.edgelist(G),1,sort))
E(G)$curved <- 0
E(G)[duplicated(E) | duplicated(E,fromLast =TRUE)]$curved <- 0.2
plot(G)
Another option is my package, where this is the default behavior:
library("qgraph")
qgraph(adj)
which can be suppressed with the bidirectional argument.
Try plot(graph, edge.curved=TRUE). It definitely works in igraph 0.6, and it may also work in igraph 0.5.4 (not sure when it was added).

Resources