I was using the igraph library and I used the neighbors function, but that only gave me a list of all the edges that a particular node had. It doesn't actually plot that graph out.
Is there an easy way to do this? I will post snippets of my code if you need it.
You do not provide any data so I am using a simple example from
Katya Ognyanova. Here is the original data:
library(igraph)
gl <- graph_from_literal(a-b-c-d-e-f, a-g-h-b, h-e:f:i, j)
plot(gl)
The node labeled "b" is node 2. To get its neighbors and plot the sub-graph, you can use:
VList = c(2, neighbors(gl, 2))
Sgl = induced_subgraph(gl, VList)
plot(Sgl)
Related
Could you please help me?
I love plotting networks with igraph for R. One nice feature is drawing polygons around the communities detected by a given algorithm.
When you use one of the community detection algorithms built in igraph, that's pretty straightforward. Like in this example with a random bipartite graph:
library(igraph)
graph <- sample_bipartite(10, 10, p = 0.5)
graph
graph.lou = cluster_louvain(graph)
graph.lou$membership
length(graph.lou$membership)
plot(graph.lou, graph)
But how can I use another kind of input to draw those polygons?
For instance, I usually calculate modularity using the package bipartite for R, because it has other algorithms that are better suited for two-mode networks.
So I'm trying to use the output from bipartite as an input for drawing community polygons in igraph. As in the following example:
library(bipartite)
matrix <- as_incidence_matrix(graph)
matrix
matrix.bec = computeModules(matrix, method = "Beckett")
modules <- module2constraints(matrix.bec)
modules
length(modules)
plot(modules, graph)
From the output of the computeModules function I'm able to extract a vector with community memberships using the module2constraints function. When I try to use it as a plotting input, I get this error message:
Error in xy.coords(x, y, xlabel, ylabel, log) :
'x' and 'y' lengths differ
Is it possible to use this output from bipartite in igraph, so polygons are automatically drawn around the communities?
I've looked into the documentation, searched here on StackOverflow, experimented some tricks, but found no solution.
Thank you very much!
I've found a solution, with help given in another question!
Actually, another way to draw polygons around communities in igraph for R is by using the argument mark.groups of the function plot.
However, this argument accepts only lists of community membership. So, if you want to use an output of the package bipartite in the format of a vector together with an igraph object, you need to convert it to a list first.
The info contained in the vector modules described in the original question needs to be complemented with vertex names and first become a data frame, then a list:
number <- seq(1:10)
row <- "row"
rowlabels <- paste(row, number, sep = "")
column <- "col"
columnlabels <- paste(column, number, sep = "")
matrix <- matrix(data = rbinom(100,size=1,prob=0.5), nrow = 10, ncol = 10,
dimnames = list(rowlabels, columnlabels))
library(bipartite)
matrix.bec <- computeModules(matrix, method = "Beckett")
modules <- module2constraints(matrix.bec)
df <- data.frame(c(rownames(matrix), colnames(matrix)), modules)
colnames(df) <- c("vertices", "modules")
list <- split(df$vertices, df$modules)
Now the object list can be used as a drawing input together with an igraph object:
library(igraph)
graph <- graph_from_incidence_matrix(matrix, directed = F)
plot(graph,
mark.groups = list)
That's one way to make bipartite and igraph talk to one another!
Thank you very much!
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)))
Basically I have tried a few different ways of clustering. I can usually get to a point in iGraph where each node is labeled with a cluster. I can then identify all the nodes within a single cluster. However, this loses their edges.
I'd have to re-iterate back over the original dataset for all the nodes in cluster 1 to get only those where both nodes+the edge are within the cluster. I'd have to do this for every cluster.
This seems like a painfully long process and there is probably a shortcut my google-fu is missing.
So, is there an easy way to, after clustering or performing community detection processes, to maintain an individual cluster/community as its own smaller graph -- that is, retaining all nodes AND edges between them?
You can use delete.vertices() to create a subgraph. Example:
library(igraph)
set.seed(123)
# create random graph
g <- barabasi.game(100, directed = F)
plot(g, layout=layout.fruchterman.reingold)
# do community detection
wc <- multilevel.community(g)
V(g)$community <- membership(wc)
# make community 1 subgraph
g_sub <- delete.vertices(g, V(g)[community != 1])
plot(g_sub, layout=layout.fruchterman.reingold)
An alternative:
#Create random network
d <- sample_gnm(n=50,m=40)
#Identify the communities
dc <- cluster_walktrap(d)
#Induce a subgraph out of the first community
dc_1 <- induced.subgraph(d,dc[[1]])
#plot that specific community
plot(dc_1)
from a data.frame (or any other R object type), with 3 Columns: "Node, Parent and text", I'd like to plot a tree with rows from "Node" to "Parent" and "text" as label.
Can anyone suggest a good library to use and example code, if possible.
I've been looking at the igraph library, but all examples I could find plot trees with sequential numbers or letters as nodes and its not simple to set the tree layout.
Any help would be greatly appreciated
Thanks
EDIT:
Thanks guys for all your help, I really appreciate it.
Some extra comments, if you can help further
#md1630, I tried your suggestion but that's not what I'm looking for. The fist code plots the tree with the root on top and the arrows from root to leaf and the second corrects the arrows but inverts the tree. What I'd like is root on top and arrow from leafs to root (I understand that may not be a tree per say - but that's the requirement
#user20650 your solution looks correct but the image starts to get crowded as the number of nodes increase. Any idea on how to add more space between them?
#math Am I using the function you provided correctly? I called plot(layout.binary(g)) and got the result on the left. The one on the right is the output of plot(g)
upgrade comment
library(igraph)
# some example data
dat <- data.frame(parent=rep(letters[1:3], each=2),
node=letters[2:7],
text=paste0("lab", 1:6))
# create graph
g <- graph.data.frame(dat)
# plot
# layout.reingold.tilford gives a tree structure
# edge and vertx labels can be defined in the plot command or alternatively
# you can add them to the graph via V(g)$name and E(g($label assignments
plot(g, layout = layout.reingold.tilford,
edge.label=E(g)$text, vertex.label=paste0("v_lab",1:7))
EDIT re comment
If you want the direction to go from the leaves towards the root; you can first, get the tree layout coordinates from the more standard tree structure, and then reverse the edges.
# get tree layout coords
g <- graph.data.frame(dat)
lay = layout.reingold.tilford(g)
# redraw graph with edges reversed
g2 <- graph.data.frame(dat[2:1], vertices = get.data.frame(g, what="vertices"))
par(mar=rep(0,4), mfrow=c(1,2))
plot(g, layout=lay)
plot(g2, layout=lay)
You can use rgraphviz. Here's the code to plot the tree from a dataframe df with columns "Node, Parent and text". I didn't run this on my computer so there may be bugs. But roughly this is the idea:
source("http://bioconductor.org/biocLite.R")
biocLite("Rgraphviz")
library("Rgraphviz")
#first set up the graph with just the nodes
nodes<- unique(df['Node'])
gR <- new("graphNEL", nodes = nodes, edgemode = "directed")
#add edges for each row in df
for (j in (1:nrow(df))) {
gR <- addEdge(df[j,2], df[j,1], gR, 1)
}
#add text labels
nAttrs <- list()
z <- df['text']
nAttrs$label <- z
#plot
plot(gR, nodeAttrs = nAttrs) #you can specify more attributes here
You can use igraph to get a network with your data (supposing your dataframe is dd):
g = graph(t(dd[,2:1]))
V(g)$label = as.character(dd$text)
plot(g, layout=layout.binary)
I supposed your root (with no parents) is not in the dataframe, otherwise use dd[-1,2:1] instead.
If you want to have a tree, you can easily produce a layout, it is simply a function that takes a graph and return a matrix. For a binary tree :
layout.binary = function(graph) {
layout = c()
r_vertex = length(V(graph))
depth = ceiling(log2(r_vertex+1))
for (ii in 0:(depth-1)) {
for (jj in 1:min(2^ii, r_vertex)) {
layout = rbind(layout, c(ii, (2*(jj-1)+1)/(2^(ii+1))))
}
r_vertex = r_vertex - 2^ii
}
return(layout)
}
It will plot an horizontal tree, use c((2*(jj-1)+1)/(2^(ii+1)), ii) if you want it to be vertical.
How can I plot a selection of igraph nodes?
I have an existing graph, but it is too complex. I want to be able to 'zoom in' on a subset of the nodes.
I am able to delete a subset of edges, but I can't figure out how to 'turn off' the isolated nodes.
When using the network package, the displayisolates=FALSE parameter does this; it does not display these isolated nodes.
The layout algorithm should also ignore the 'turned off' edges.
For example:
g1 <- graph( c( 0,1, 1,2, 2,2, 2,3 ) )
g2 <- delete.edges(g1, E(g1, c(0,1)))
plot(g2)
When plotting g2, I want to not display node 0.
Thanks
I understand that users should not submit new answers to comment on other answers, but my edit was rejected and I don't have a high enough reputation to leave comments.
I just wanted to point out that in Wine's answer above, the "- 1" index correction in the deletes.isolates function is not necessary from igraph 0.6 onwards. See also Tamas' comment here:
Plot only Edges with a specific weight - igraph
Hey, it looks like you figured it out, but in exploring the question (I usually use the network package myself, but have tried to use igraph as well for some things) I came up with a function that should do that automatically, mirroring the displayisolates = F functinality.
delete.isolates <- function(graph, mode = 'all') {
isolates <- which(degree(graph, mode = mode) == 0) - 1
delete.vertices(graph, isolates)
}
In your case, running this with g1 would remove the first vertex if you used the argument mode = 'in' and the last vertex if you used the argument mode = 'out'.
So in your case, if you entered:
g2 <- delete.isolates(g1, mode = 'in')
plot(g2)
You should get what you want. I don't use igraph much, so it's very possible that this function would run into some issues for other graphs.
P.S. This also gives the kind of weird result that in the new g2, the first vertex is now an isolate based on indegree. This function probably isn't useful in most situations, but might be helpful for making a cleaner plot.
iso <- V(g1)[degree(g1)==0]
g2 <- delete.vertices(g1, iso)