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)
Related
I have a very large bipartite network model that I created from 5 million lines of a dataset. I decompose my network model because I can not draw a graph of this size. Now all I need is to plot the decompose graphics one by one. There is no problem with that. But I want to draw the graph with a shape according to the attributes of each node. For example, I want a square for the "A" attributes on my graph G, and a triangle for the "B" attributes. In addition to this I want to add vertex labels by attributes. Here is my codes to plot first component of graph after creating bipartite G and its work:
components <- decompose(G)
plot(components[[1]])
I tried something like this to adding labels and changing vertex shapes according to graph attributes but it didn't work:
plot(components[[1]], vertex.label= V(G)$attributes,
vertex.shape=c("square", "triangle"))
Does anyone can help me, I'm stuck. Thank you so much!
the components function returns a list of vertices which make up a component. So you need to traverse the list, create a subgraph and plot. As for plotting attributes you need to provide a reproducible example for us to help.
library(igraph)
set.seed(8675309)
g <- sample_gnp(200, p = 0.01)
V(g)$name <- paste0("Node", 1:vcount(g))
V(g)$shape <- sample(c("circle","square"), vcount(g), replace = T)
clu <- components(g)
grps <- groups(clu)
lapply(grps, function(x) plot(induced_subgraph(g, x)))
I'm using igraph community-detection and the community sizes are either too small or too large. Is there any way to specify the size of the detected communities? If not, is there any way for me to manually split or merge communities detected from igraph? Thanks!
Whilst I don't think it's possible to set/specify the size of a community detected by igraph, some of the community detection algorithms allow you to specify how many communities you want (an alternative to splitting/merging).
You can use either the cluster_spinglass() function and set spins to be the number of communities desired. Or use one of the hierarchical methods and then use cut_at() to get the desired number of communities, using the no argument to specify how many communities you want.
Example code:
# Set up your graph object
g <-[an igraph object] # set up your graph
# Use spinglass to create a set number of communities
sg <- g %>% cluster_spinglass(spins = 10) # produces 10 communities using spinglass algorithm
# Use hierarchical methods and cut_at to create a set number of communities
walk <- g %>% cluster_walktrap() %>% cut_at(no = 10)
eb <- g %>% cluster_edge_betweenness() %>% cut_at(no = 10)
Note that the spinglass method will give you back a communities object, whereas the cut_at method simply gives you back the community indices for all nodes in the graph (i.e. a simple numeric vector).
You can find more details on the communities help page.
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).
Trying to find communities in tweet data. The cosine similarity between different words forms the adjacency matrix. Then, I created graph out of that adjacency matrix. Visualization of the graph is the task here:
# Document Term Matrix
dtm = DocumentTermMatrix(tweets)
### adjust threshold here
dtms = removeSparseTerms(dtm, 0.998)
dim(dtms)
# cosine similarity matrix
t = as.matrix(dtms)
# comparing two word feature vectors
#cosine(t[,"yesterday"], t[,"yet"])
numWords = dim(t)[2]
# cosine measure between all column vectors of a matrix.
adjMat = cosine(t)
r = 3
for(i in 1:numWords)
{
highElement = sort(adjMat[i,], partial=numWords-r)[numWords-r]
adjMat[i,][adjMat[i,] < highElement] = 0
}
# build graph from the adjacency matrix
g = graph.adjacency(adjMat, weighted=TRUE, mode="undirected", diag=FALSE)
V(g)$name
# remove loop and multiple edges
g = simplify(g)
wt = walktrap.community(g, steps=5) # default steps=2
table(membership(wt))
# set vertex color & size
nodecolor = rainbow(length(table(membership(wt))))[as.vector(membership(wt))]
nodesize = as.matrix(round((log2(10*membership(wt)))))
nodelayout = layout.fruchterman.reingold(g,niter=1000,area=vcount(g)^1.1,repulserad=vcount(g)^10.0, weights=NULL)
par(mai=c(0,0,1,0))
plot(g,
layout=nodelayout,
vertex.size = nodesize,
vertex.label=NA,
vertex.color = nodecolor,
edge.arrow.size=0.2,
edge.color="grey",
edge.width=1)
I just want to have some more gap between separate clusters/communities.
To the best of my knowledge, you can't layout vertices of the same community close to each other, using igraph only. I have implemented this function in my package NetPathMiner. It seems it is a bit hard to install the package just for the visualization function. I will write the a simple version of it here and explain what it does.
layout.by.attr <- function(graph, wc, cluster.strength=1,layout=layout.auto) {
g <- graph.edgelist(get.edgelist(graph)) # create a lightweight copy of graph w/o the attributes.
E(g)$weight <- 1
attr <- cbind(id=1:vcount(g), val=wc)
g <- g + vertices(unique(attr[,2])) + igraph::edges(unlist(t(attr)), weight=cluster.strength)
l <- layout(g, weights=E(g)$weight)[1:vcount(graph),]
return(l)
}
Basically, the function adds an extra vertex that is connected to all vertices belonging to the same community. The layout is calculated based on the new graph. Since each community is now connected by a common vertex, they tend to cluster together.
As Gabor said in the comment, increasing edge weights will also have similar effect. The function leverages this information, by increasing a cluster.strength, edges between created vertices and their communities are given higher weights.
If this is still not enough, you extend this principle (calculating the layout on a more connected graph) by adding edges between all vertices of the same communities (forming a clique). From my experience, this is a bit of an overkill.
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).