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)
Related
I have loaded a 2D dataset and I wanted to try some graph-based clustering algorithms, however the relative neighborhood graph I get seems to be missing a lot of edges. Here is the result I get, and you can tell visually that vertices that should be connected with an edge are not. Is the cccd library working correctly or am I doing something wrong?
Here's the code I used:
g <- rng(x = dataset1)
plot.igraph(g, vertex.size = 2, vertex.label = NA)
I'm also having this issue. Setting the "open" option to FALSE seems to help but I still have 1 less edge than expected on the iris UCI dataset (195 vs 196).
I'm trying to visualize the connections between the institutions in a medical faculty and just can't get the edges to be weighted and displayed thicker or thinner depending on the number of connections.
I've tried to combine the answers I found here playing around with edge.width = E(g)$weight and trying graph.strength(g). But honestly I have no idea what I'm doing. This is the first time I have to use R and I have no experience in programming whatsoever.
library(igraph)
D3 <- read.csv(file.choose(),header=TRUE,row.names = 1)
g <- graph.data.frame(D3, directed=FALSE)
plot(g,
vertex.size=20,
vertex.label.dist=1,
vertex.label.degree=-pi/2,
layout=layout_with_kk)
Igraph plots a network where every single connection is shown. Some institutions have multiple connections between each other which make the graph quite unattractive to look at. Only a Part of the table was used for this picture
My data looks like this and has about 1500 rows:
"1","NEUROLOGIE","MEDINF"
my data
Any help is much appreciated!
Using edge.width = E(g)$weight is the right idea, but you need to get the right weight. graph.strength(g) is a property of the vertices, but you need a weight for the edges. I don't know of a function that directly calculates how many edges there are between two vertices, but it is not hard to write one.
First, get a version of the graph with just one edge between each pair of connected vertices.
g2 = simplify(g)
Now we need to get the right weight for the edges of g2. If an edge connects two vertices, all shortest paths connecting those two vertices will be single edges, so for each edge of the simplified g2, we need to find the number of shortest paths (edges) between those vertices in the original g. Then we can plot.
E(g2)$weight = sapply(E(g2), function(e) {
length(all_shortest_paths(g, from=ends(g2, e)[1], to=ends(g2, e)[2])$res) } )
plot(g2,
vertex.size=15,
vertex.label.dist=0.5,
vertex.label.cex=0.8,
vertex.label.degree=-pi/2,
edge.width=E(g2)$weight,
layout=layout_with_kk,
margin=-0.2)
(I have slightly modified your plot statement to improve readability.)
Thank you so much for your help!! I was nowhere close to that.. To make it more readble I reduced the thickness of the edges and replaced the names with number, this is the code:
library(igraph)
D3 <- read.csv(file.choose(),header=TRUE,row.names = 1)
g <- graph.data.frame(D3, directed=FALSE)
g2 = simplify(g)
E(g2)$weight = sapply(E(g2), function(e) {
length(all_shortest_paths(g, from=ends(g2, e)[1], to=ends(g2, e)[2])$res) } )
tkplot(g2,
vertex.color= "gold",
vertex.label.color="red",
vertex.size=10,
vertex.label.cex=1,
edge.width=E(g2)$weight*0.15,
edge.color="grey",
layout=layout.reingold.tilford,
asp = .5,
margin=-0.95)
Creating:
Reingold.tilford
I find this visualization quite fine because the graph is interactive. Are there other ways to make it even more readable?
Thanks again for the help!
All the best,
Jay
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)
I have a large transition matrix that I want to plot a graph of in r. I have chosen the markovchain package to do this, which allows me to turn this matrix into a markovchain object and then plot it as follows:
library(markovchain)
tMat = matrix(c(0,.2,.7,.1,.3,.4,.3,.1,.4,.5),3,3)
mc = new("markovchain",transitionMatrix = tMat)
plot(mc)
which produces the following output:
of course, this is just an example, and as I mentioned before the real transition matrix is much hairier.
My question is: how can I plot only edges that have values greater than some minimum threshold? If I try to "zero out" all values below a certain threshold, markovchain complains that the rows do not sum to one (because it is then no longer a singularly sochastic matrix). But for a very complicated graph, it is less important that the edges connected to a vertex sum to 1, and more important that the graph remains readable. Is there any way to do this?
I know that the plot function is built on top of igraph.plot, so I am hoping that there is some option there that might help?
Any suggestions would be much appreciated!
-Paul
woops: i answered my own question. Just wanted to leave this here in case other people encounter the same problem: you can simply create the markovchain object, and then go into its transitionMatrix attribute and edit the values directly:
mc#transitionMatrix[mc#transitionMatrix<.2] = 0
which produces:
Now a god follow-up question which actually gets at the original problem and would be a better solution is: how to only suppress the numbers in teh graph output rather than deleting the lines altogether? It leads to ugly situations where previously connected nodes/vertices become islands. I think this would involve going into the part of the igraph.plot object that stores these values, which I don't know how to do even after reseraching quite a bit.
how to only suppress the numbers in teh graph output rather than
deleting the lines altogether?
Coerce the markovchain object to an igraph object; now you got all flexibility you need:
library(markovchain)
statesNames=c("a","b","c")
mc<-new("markovchain", states=statesNames, transitionMatrix=
matrix(c(0.2,0.5,0.3,
0,1,0,
0.1,0.8,0.1),nrow=3, byrow=TRUE, dimnames=list(statesNames,statesNames)
))
g <- as(mc, "igraph")
min <- 0.5
plot(g, edge.label=ifelse(E(g)$prob>=min, E(g)$prob, NA))
I need to draw a network with 5 nodes and 20 directed edges (an edge connecting each 2 nodes) using R, but I need two features to exist:
To be able to control the thickness of each edge.
The edges not to be overlapping (i.e.,the edge form A to B is not drawn over the edge from B to A)
I've spent hours looking for a solution, and tried many packages, but there's always a problem.
Can anybody suggest a solution please and provide a complete example as possible?
Many Thanks in advance.
If it is ok for the lines to be curved then I know two ways. First I create an edgelist:
Edges <- data.frame(
from = rep(1:5,each=5),
to = rep(1:5,times=5),
thickness = abs(rnorm(25)))
Edges <- subset(Edges,from!=to)
This contains the node of origin at the first column, node of destination at the second and weight at the third. You can use my pacake qgraph to plot a weighted graph using this. By default the edges are curved if there are multiple edges between two nodes:
library("qgraph")
qgraph(Edges,esize=5,gray=TRUE)
However this package is not really intended for this purpose and you can't change the edge colors (yet, working on it:) ). You can only make all edges black with a small trick:
qgraph(Edges,esize=5,gray=TRUE,minimum=0,cut=.Machine$double.xmin)
For more control you can use the igraph package. First we make the graph:
library("igraph")
g <- graph.edgelist(as.matrix(Edges[,-3]))
Note the conversion to matrix and subtracting one because the first node is 0. Next we define the layout:
l <- layout.fruchterman.reingold(g)
Now we can change some of the edge parameters with the E()function:
# Define edge widths:
E(g)$width <- Edges$thickness * 5
# Define arrow widths:
E(g)$arrow.width <- Edges$thickness * 5
# Make edges curved:
E(g)$curved <- 0.2
And finally plot the graph:
plot(g,layout=l)
While not an R answer specifically, I would recommend using Cytoscape to generate the network.
You can automate it using a RCytoscape.
http://bioconductor.org/packages/release/bioc/html/RCytoscape.html
The package informatively named 'network' can draw directed networks fairly well, and handle your issues.
ex.net <- rbind(c(0, 1, 1, 1), c(1, 0, 0, 1), c(0, 0, 0, 1), c(1, 0, 1, 0))
plot(network(ex.net), usecurve = T, edge.curve = 0.00001,
edge.lwd = c(4, rep(1, 7)))
The edge.curve argument, if set very low and combined with usecurve=T, separates the edges, although there might be a more direct way of doing this, and edge.lwd can take a vector as its argument for different sizes.
It's not always the prettiest result, I admit. But it's fairly easy to get decent looking network plots that can be customized in a number of different ways (see ?network.plot).
The 'non overlapping' constraint on edges is the big problem here. First, your network has to be 'planar' otherwise it's impossible in 2-dimensions (you cant connect three houses to gas, electric, phone company buildings without crossovers).
I think an algorithm for planar graph layout essentially solves the 4-colour problem. Have fun with that. Heuristics exist, search for planar graph layout, and force-directed, and read Planar Graph Layouts