Making igraph clearer to read - r

I have a directed igraph with 69 vertices, shown below. It was plotted using the igraph package:
library(igraph)
ig <- graph.adjacency(data, mode="directed", weighted=TRUE)
plot(ig)
I'm looking to achieve the following 2 things:
(a) Space the vertices out and maybe lengthen the edges to make it a little easier to read
(b) In reality, my labels are longer. Is it possible to make a vertex bigger and the text smaller to accommodate this.
Any ideas?
Here is my data: https://www.dropbox.com/s/rtedrd1x1duqllj/data.Rdata?dl=0

All of the parameters are definitely highly customizable. I substituted state names for your vertex labels:
# this ensures the starting random position is the same
# for the layouts that use a random starting position
set.seed(1492)
l <- layout.fruchterman.reingold(ig, niter=5000, area=vcount(ig)^4*10)
plot(ig, layout=l,
edge.arrow.size=0.5,
vertex.label.cex=0.75,
vertex.label.family="Helvetica",
vertex.label.font=2,
vertex.shape="circle",
vertex.size=1,
vertex.label.color="black",
edge.width=0.5)
You shld rly take some time to read help("igraph.plotting") & help("layout")

Related

Create Weighted edges in igraph instead of multiple single connections

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

different vertex shapes for each vertex of decomposed graph

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)))

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.

Force-directed graph drawing: Edit the force between specific nodes (R)

I want to analyse a social network using the R packages statnet and/or igraph in reference to force-directed graph drawing (kamada.kawai/fruchterman.reingold). I wounder, if it is possible to adjust the "force" between 2 specific nodes, e.g. to consider a larger or smaller cooperation between 2 stakeholders. However, i do not want to edit the general force between all nodes
(as proposed here:)
How do I lengthen edges in an igraph network plot (layout=fruchterman.reingold)?
The idea on this would be to get a more realistic image of a social network, also for further analysis.
Thanks a lot and nice weekend to everybody!
This layout algorithm supports edge weights, which are basically used as multipliers for the attraction forces along the edges. I.e. edges with high weight will tend to be shorter. Here is a simple example
library(igraph)
g <- graph.ring(10)
# Edge weights, will be recycled
E(g)$weight <- c(1,4)
coords <- layout.fruchterman.reingold(g, weights=E(g)$weight)
# Eliminate the margin
par(mar=c(0,0,0,0))
plot(g, layout=coords, vertex.color="#E495A5", vertex.size=20)

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