spacing vertices evenly in igraph in r - r

I have the following graph graph
set.seed(1410)
df<-data.frame(
"site.x"=c(rep("a",3),rep("b",3),rep("c",3),rep("d",3)),
"site.y"=c(rep(c("e","f","g"),4)),
"bond.strength"=sample(1:100,12, replace=TRUE))
library(igraph)
df<-graph.data.frame(df)
V(df)$names <- c("a","b","c","d","e","f","g")
layOUT<-data.frame(x=c(rep(1,4),rep(2,3)),y=c(4:1,3:1))
E(df)[ bond.strength < 101 ]$color <- "red"
E(df)[ bond.strength < 67 ]$color <- "yellow"
E(df)[ bond.strength < 34 ]$color <- "green"
V(df)$color <- "white"
l<-as.matrix(layOUT)
plot(df,layout=l,vertex.size=10,vertex.label=V(df)$names,
edge.arrow.size=0.01,vertex.label.color = "black")
I would like to space the vertices "g-e" evenly along the vertical distance between vertex a and d to make my current graph (see below) prettier. As you can see it is pretty crowded.
Also I would like to move the two column of vertices closer together on the x-axis but I have noticed that adjusting the x coordinates in the layout is not responding. For example the two following layouts produce graph that look exactly the same despite the drastic adjustment in the x-coordinates.
layOUT<-data.frame(x=c(rep(1,4),rep(2,3)),y=c(4:1,3:1))
layOUT<-data.frame(x=c(rep(1,4),rep(100,3)),y=c(4:1,3:1))
Thanks for any advice you may have.

Your second question is easier to answer: igraph rescales the layout into the rectangle spanned by (-1, -1) and (1,1) in the coordinate system. If you want to avoid this, pass rescale=FALSE to the plot function -- but in this case, it is up to you to ensure that the coordinates actually make sense and are not outside the plot area.
Regarding your first question: since you are constructing the layout manually in the layOUT variable, nothing prevents you from adjusting the Y coordinates manually. First, get the minimum and maximum Y coordinates for the vertices with X=1 from layOUT:
min.y <- min(layOUT$y[layOUT$x == 1])
max.y <- max(layOUT$y[layOUT$x == 1])
Then just space the Y coordinates of the vertices with an X coordinate of 2 evenly between min.y and max.y:
vs.on.right <- which(layOUT$x == 2)
n <- length(vs.on.right)
layOUT$y[vs.on.right] <- (0:n)*(max.y-min.y)/n + min.y

Related

how to make concentric circles layout in igraph (R)

I'm trying to create a special graph layout where 2 different types of nodes (based on their attribute) are placed on 2 different circles with different radius (concentric circles layout).
Here's a toy example where a graph with 10 nodes have an attribute (size). The goal is to place the nodes with size less than 5 on an inner circle, and the nodes with size greater than 5 on an outer circle:
g <- make_full_graph(10)
V(g)$size = V(g)
I couldn't find any such layout supported by igraph library. Does anyone know how to achieve this?
There is the layout_in_circle option if you only wanted one circle. You could apply that separately to each of your groups with something like this
layout_in_circles <- function(g, group=1) {
layout <- lapply(split(V(g), group), function(x) {
layout_in_circle(induced_subgraph(g,x))
})
layout <- Map(`*`, layout, seq_along(layout))
x <- matrix(0, nrow=vcount(g), ncol=2)
split(x, group) <- layout
x
}
Then you could plot with
plot(g, layout=layout_in_circles(g, group=V(g)>5))
It doesn't do anything special to try to make the edges pretty. But I guess the point is you can define whatever function you want to control the layout by returning a matrix of coordinates.

Plot unconnected graph in igraph

I have an unconnected graph that I plot with fruchterman-reingold layout in igraph
require(igraph)
er_graph <- erdos.renyi.game(100, 5/20)+erdos.renyi.game(100, 5/20)
coords<-layout.fruchterman.reingold(er_graph)
plot(er_graph,layout=coords, vertex.label=NA)
Plot Example :
The result was two distant clusters.
I wish to decrease the white area in my plot.
Is there a way to scale the coordinate in order to decrease the space between the clusters?
There may be an easy way to do this in one of the layout functions, but you can also directly change the node coordinates after creating the layout. If you look at coords, you can see it's just a matrix of node coordinates. You can use the cluster labels to move the two node clusters closer together programmatically:
require(igraph)
require(dplyr)
er_graph <- erdos.renyi.game(100, 5/20)+erdos.renyi.game(100, 5/20)
# Make layout reproducible
set.seed(40)
coords <- layout.fruchterman.reingold(er_graph)
# Original graph
plot(er_graph,layout=coords, vertex.label=NA)
Move clusters closer together: First, we add the cluster labels to the coordinates and set a parameter f for what fraction of the distance between clusters we want eliminate. Then we subtract from each node f times the difference between the mean coordinates for that cluster and the mean coordinates over both clusters.
# Add cluster labels to coords
coords = data.frame(coords, clust=clusters(er_graph)$membership)
# Move closer by a fraction "f" of mean distance between clusters
f = 0.6
# Shift each node closer to the overall center of mass of the node
coords = coords %>%
mutate(X1 = ifelse(clust==1, X1 - f*(mean(X1[clust==1]) - mean(X1)), X1 - f*(mean(X1[clust==2]) - mean(X1))),
X2 = ifelse(clust==1, X2 - f*(mean(X2[clust==1]) - mean(X2)), X2 - f*(mean(X2[clust==2]) - mean(X2))))
# Convert coords back to original matrix form
coords = as.matrix(coords[,1:2])
# Re-plot graph
plot(er_graph,layout=coords, vertex.label=NA)

Create bubble chart with biggest bubble at the center

I'm trying to create a bubble chart using a set of data as follows:
X --> 10
Y --> 20
Z --> 5
Q --> 10
I simply need to have the biggest bubble (based on its number) to be at the centre (give or take) and the rest of the bubbles be around it without overlapping.
All of the R examples I have seen require a two dimensional dataset, and since the data I have are only one dimensional, I like to know if it's at all possible to create such graphs in R.
It would be great if someone could suggest me some useful hints or so. By the way for this task I need to use a SA tools so something like d3js is out of options. However, I am open to using a tool other than R.
I wasn't quite sure if this question should be asked in On Stack Overflow or Cross Validated, so if moderators believe it doesn't belong here, I'll remove it.
This should do, the main idea being that you sort by the value of the radius, so the first is the biggest, then shift the values around it (odd on one side, even on the other) so that the values are decreasing both ways.
Further explanations in the code.
library(plotrix)
library(RColorBrewer)
# Set the random seed, to get reproducible results
set.seed(54321)
# Generate some random values for the radius
num.circles <- 11
rd <- runif(num.circles, 1, 20)
df <- data.frame(labels=paste("Lbl", 1:num.circles), radius=rd)
# Sort by descending radius. The biggest circle is always row 1
df <- df[rev(order(df$radius)),]
# Now we want to put the biggest circle in the middle and the others on either side
# To do so we reorder the data frame taking the even values first reversed, then the odd values.
# This ensure the biggest circle is in the middle
df <- df[c(rev(seq(2, num.circles, 2)), seq(1, num.circles, 2)),]
# Space between the circles. 0.2 * average radius seems OK
space.between <- 0.2 * mean(df$radius)
# Creat an empty plot
plot(0, 0, "n", axes=FALSE, bty="n", xlab="", ylab="",
xlim=c(0, sum(df$radius)*2+space.between*num.circles),
ylim=c(0, 2.5 * max(df$radius)))
# Draw the circle at half the height of the biggest circle (plus some padding)
xx <- 0
mid.y <- max(df$radius) * 1.25
# Some nice degrading tones of blue
colors <- colorRampPalette(brewer.pal(8,"Blues"))(num.circles/2)
for (i in 1:nrow(df))
{
row <- df[i,]
x <- xx + row$radius + i*space.between
y <- mid.y
# Draw the circle
draw.circle(x, y, row$radius,
col=colors[abs(num.circles/2-i)])
# Add the label
text(x, y, row$labels, cex=0.6)
# Update current x position
xx <- xx + row$radius * 2
}
The result:
Live version on RFiddle.

R: Counting points on a grid of rectangles:

I have a grid of rectangles, whose coordinates are stored in the variable say, 'gridPoints' as shown below:
gridData.Grid=GridTopology(c(min(data$LATITUDE),min(data$LONGITUDE)),c(0.005,0.005),c(32,32));
gridPoints = as.data.frame(coordinates(gridData.Grid))[1:1000,];
names(gridPoints) = c("LATITUDE","LONGITUDE");
plot(gridPoints,col=4);
points(data,col=2);
When plotted, these are the black points in the image,
Now, I have another data set of points called say , 'data', which when plotted are the blue points above.
I would want a count of how many blue points fall within each rectangle in the grid. Each rectangle can be represented by the center of the rectangle, along with the corresponding count of blue points within it in the output. Also, if the blue point lies on any of the sides of the rectangle, it can be considered as lying within the rectangle while making the count. The plot has the blue and black points looking like circles, but they are just standard points/coordinates and hence, much smaller than the circles. In a special case, the rectangle can also be a square.
Try this,
x <- seq(0,10,by=2)
y <- seq(0, 30, by=10)
grid <- expand.grid(x, y)
N <- 100
points <- cbind(runif(N, 0, 10), runif(N, 0, 30))
plot(grid, t="n", xaxs="i", yaxs="i")
points(points, col="blue", pch="+")
abline(v=x, h=y)
binxy <- data.frame(x=findInterval(points[,1], x),
y=findInterval(points[,2], y))
(results <- table(binxy))
d <- as.data.frame.table(results)
xx <- x[-length(x)] + 0.5*diff(x)
d$x <- xx[d$x]
yy <- y[-length(y)] + 0.5*diff(y)
d$y <- yy[d$y]
with(d, text(x, y, label=Freq))
A more general approach (may be overkill for this case, but if you generalize to arbitrary polygons it will still work) is to use the over function in the sp package. This will find which polygon each point is contained in (then you can count them up).
You will need to do some conversions up front (to spatial objects) but this method will work with more complicated polygons than rectangles.
If all the rectangles are exactly the same size, then you could use k nearest neighbor techniques using the centers of the rectangles, see the knn and knn1 functions in the class package.

How to plot directed acyclic lattice graph in R

I need to plot directed acyclic lattice graph of size m x n, similar as in this picture, but without edges on the contour and without vertexes on the corners:
Is this possible to do with graph.lattice function? If yes, how to set such vertexes' labels (i.e. (x,y) format, not just an integer number) and remove mentioned edges and vertexes? Moreover, is it possible to plot graph in such position (as in a picture) without using tkplot function and rotating it then?
I am not exactly sure what you mean by 'without edges on the contour', but here are some points:
Read ?igraph.plotting for the complete list of plotting parameters.
If you don't want the frame on the vertices, set vertex.frame.color to the same value as vertex.color.
Use layout.grid, see ?layout.grid.
Use vertex.label to set the labels.
If you want to omit some edges, then delete them, or set their width to zero or their color to background color.
If you want to omit some vertices, then attach the coordinates calculated by layout.grid as vertex attributes, and then remove the vertices from the graph.
Something like this could work:
g <- graph.lattice( c(5,5) )
lay <- layout.grid(g)
V(g)$x <- lay[,1]
V(g)$y <- lay[,2]
V(g)$color <- V(g)$frame.color <- "darkolivegreen"
V(g)$label.color <- "lightgrey"
V(g)$label <- paste(V(g)$x+1, V(g)$y+1, sep=",")
To remove the edges, you can select them based on the coordinates of the vertices:
torem <- c(E(g)[ V(g)[x==0] %--% V(g)[x==0] ],
E(g)[ V(g)[y==0] %--% V(g)[y==0] ],
E(g)[ V(g)[x==4] %--% V(g)[x==4] ],
E(g)[ V(g)[y==4] %--% V(g)[y==4] ])
g2 <- delete.edges(g, torem)
And then remove the vertices and plot:
g3 <- delete.vertices(g2, V(g2)[ x %in% c(0,4) & y %in% c(0,4) ])
plot(g3, layout=cbind(V(g3)$x, V(g3)$y))

Resources