How to fit text inside vertex and avoid overlapping? - r

I'm trying to plot a graph with characters as labels. The issue it that the text is a bit long and the vertices overlap between them. Is there a way to minimize the area of the circular vertex by fitting the text inside? and also, how to avoid overlapping between them? This is the edge list and the data frame of attributes that I'm using(The second column of the df has the labels that I'm trying to fit. Here is my code:
## READ THE EDGE LIST AS A GRAPH OBJECT ##
library('igraph')
cn <- as.matrix(cn, header= FALSE)
g <- graph.edgelist(cn,directed= TRUE)
plot(g, layout = layout.reingold.tilford(g, root=1))
## GET ATTRIBUTES ##
V(g)$name=as.character(att$Name)
V(g)$desc=as.character(att$Description)
## GET LABELS ##
V(g)$label <- V(g)$name
Here I tried to use the method proposed in this post.
## FIT THE LABELS INSIDE THE VERTEX ##
ly <- layout.reingold.tilford(g, root=1) ly <- layout.auto(g)
plot(0, type="n", ann=FALSE, axes=FALSE, xlim=extendrange(ly[,1]), ylim=extendrange(ly[,2])) plot(g, layout=ly, rescale=FALSE, add=TRUE,
vertex.size=(strwidth(V(g)$label) + strwidth("oo")) * 100)
It is working for fitting the text inside the vertexes, but it is not minimizing the area of the circle. For instance, the string of characters "Random Process" would fit better in two lines instead of one and so on.. Also, it has problems with vertex overlapping. I would like to keep the structure of a tree diagram. Here is my outcome so far:

Try with this:
plot(G, vertex.size=8, vertex.color = rainbow(10, .8, .8, alpha= .8),
vertex.label.color = "black", vertex.label.cex = 0.4, vertex.label.degree = -pi/2,
edge.arrow.size = 0.3, edge.arrow.width = 0.4, edge.color = "black")
With vertex.label.degree and vertex.label.cex you fit the text on the node. Best!

Related

how to set position of vertex names in igraph network

I need to set the position of vertex labels inside or right next to them. Which parameter should i change in plot to change that?
i've tried to change vertex.label.cex and vertex.label.dist parameters but labels still located in the corner of the plot and look messy.
plot(g,
vertex.color= "yellow",
vertex.size = degree(g)*0.3,
vertex.label=names,
vertex.label.cex = degree(g)/1000,
edge.width= 0.5,
vertex.label.dist=0.1)
You had the right idea with vertex.label.dist. You just used too small a value.
Since you did not provide your graph, I will illustrate with a random graph (and some modifications to your plot statement to match this graph).
library(igraph)
set.seed(1234)
g = erdos.renyi.game(15, 0.2)
plot(g)
par(mfrow=c(1,2))
set.seed(4321)
plot(g,
vertex.color= "yellow",
vertex.size = degree(g),
edge.width= 0.5,
vertex.label.dist=0.1,
margin=-0.2,
main="vertex.label.dist=0.1")
set.seed(4321)
plot(g,
vertex.color= "yellow",
vertex.size = degree(g),
edge.width= 0.5,
vertex.label.dist=1,
margin=-0.2,
main="vertex.label.dist=1")
Notice that with the larger value of vertex.label.dist the labels are visibly offset.

Progressive point to point walk plotting in R

How can I to plot a progressive walk from point to point?
Lets have p1 =[1,0], p2=[0,1], p3=[1,1]. Plot should first draw a line from p1 to p2 showing the direction, wait for a second, then draw another line from p2 to p3 and it goes on if you have more data.
The plot size should be first fixed to (0,1)^2. Correct output should look similar to this image:
Example plot
My code is this for now:
plot(x,y,xlim=range(x), ylim=range(y), xlab="x", ylab="y", main="Filled Plane",pch=16)
#lines(x,y,xlim=range(x),ylim=(y),pch=16)
for(i in 1:20){
arrows(x[i],y[i],x[i+1],y[i+1],length = 0.25, angle = 30, col = 1:3)
}
One option is to use arrows. Fist you need to create a plot giving the data you want. Then you can draw lines to connect your points.
Let say you have random uniform arrays of x,y. Set the limit to decide how many points you want to plot.
Although I placed the points immediately ( I could not place the grid properly otherwise) Hope it helps.
limit<- 50
x <- runif(limit)
y <- runif(limit)
plot(x,y, xlim=range(0,1), ylim=range(0,1),
xlab="x", ylab="y", main = "Random Walk")
grid(nx = 10, ny = 10, col = "lightgray", lty = "dotted",
lwd = par("lwd"), equilogs = TRUE)
for(i in 1:limit){
arrows(x[i],y[i],x[i+1],y[i+1], length = 0.1, angle = 20)
Sys.sleep(0.5)
}

Add grid over 3D surface using persp3D (plot3D package)

I'm trying to add a grid on top of a 3D surface created with persp3D (package plot3D), however I can't sort a way of doing it without causing a deformation on the grid.
library(plot3D)
data("volcano")
volcano is a 3D matrix that can be used to create a 3D plot by simply calling:
persp3D(z=volcano)
What I intend to do is create a new grid using the dimensions of the 3D matrix and than add it to the 3D plot.
# new grid
x.seq <- seq(1, dim(volcano)[1], length = 20)
y.seq <- seq(1, dim(volcano)[2], length = 20)
# Visualize grid
plot(x=c(0,length(volcano[,1])), y=c(0,length(volcano[1,])), type='n')
abline(v=x.seq, h=y.seq)
I got close to it by subsetting the matrix volcano by the new sequences created and then plot the new 3D matrix over the original 3D surface.
# New matrix using sequences created
mtx.sub <- volcano[time.seq, freq.seq]
# Plot new matrix on top of original surface
persp3D(z=volcano)
persp3D(z=amp.sub, border="black", facets=NA, add=T, colkey=list(plot=F))
Even though the result is close to what I expected, a closer look will show that the grid is not really on top of the existing surface, it is a whole new surface that do not match the original one (which is quite obvious, given that it is a different matrix).
What I'm looking for is a way to add a 2D grid that will go over the original surface, something similar to abline, but for a 3D plot.
I had a look at plot3D documentation and searched on the web, but none of the solutions apply to persp3D().
Any thoughts on a way around this?
You can add the grid directly within the call to persp3D:
persp3D(z=volcano, border="black", lwd=0.3)
In response to your comment, you could plot at lower resolution to get wider borders, however, the surface will also be at lower resolution (see below). It would be nice to be able to plot the surface at full resolution and then have a sparser net of border lines that still matches the high-resolution surface, for example, by plotting the border lines only on every other facet, but I'm not sure how to do that without hacking persp3D (or one of the functions called by persp3D).
persp3D(z=volcano[seq(1,nrow(volcano),2), seq(1,ncol(volcano),2)],
border="black", lwd=0.4)
A work around is to use ribbon3D. It requires some more lines of code and messing around with parameters, but it does work reasonable.
require(plot3D)
### create data from 3D plotting
###
### x1, x2 a grid
### x the value of a normal distribution
x1 <- seq(-4,4,0.025)
x2 <- seq(-4,4,0.025)
mu = 0
z <- matrix(rep(0,length(x1)*length(x2)),length(x1))
for (i in 1:length(x1)) {
for(j in 1:length(x2)) {
z[i,j] <- dnorm(x1[i],mu,1)*dnorm(x2[j],mu,1)
}
}
### plot 3D
sel = 1+c(1:32)*10 ### selection of the grid lines to plot
persp3D(x1,x2,z,
border = NA, facets = TRUE, col = rgb(1,1,1,0.5),
theta = 30, phi = 30,
zlim = c(0,0.26))
ribbon3D(x1[sel],x2,z[sel,],
border = NA, facets = NA, col = 1, width = 0.02,
along = "y", space = 0.9, add = TRUE)
ribbon3D(x1[],x2[sel],z[,sel],
border = NA, facets = NA, col = 1, width = 0.02,
along = "x", space = 0.9, add = TRUE)
Example with the volcano data
require(plot3D)
### create data from 3D plotting
x <- 1:length(volcano[,1])
y <- 1:length(volcano[1,])
z <- volcano
### plot 3D
selx = seq(1,max(x),4)
sely = seq(1,max(y),4)
persp3D(x,y,z,
border = NA, facets = TRUE, lwd = 0.03,
theta = 30, phi = 30)
ribbon3D(x[selx],y,z[selx,],
border = 1, facets = 1, col = 1, width = 0.1,
along = "y", space = 0.9, add = TRUE)
ribbon3D(x[],y[sely],z[,sely],
border = 1, facets = 1, col = 1, width = 0.1,
along = "x", space = 0.9, add = TRUE)

Plotting titles and legends on interactive igraph plot? (R)

I'm having trouble adding a title and legend to the inside of my graph. Is it not possible with tkplot OR plot?
dff <- data.frame(a = c(0,1,2,3,4),b = c(3,4,5,6,7))
nod <- data.frame(node = c(0:7),wt = c(1:8))
pg <- graph_from_data_frame(d = dff, vertices = nod,directed = F)
# plot function with edge.label added
tkplot(pg, edge.label = nod$wt, main = "this is my graph")
legend('topleft',legend= degree(pg)*5,pt.cex=20,col='white',
pch=21, pt.bg='white')
It doesn't seem to want to work the way I want it to. I just want the legend to show the vertices adjusted to be bigger for a higher degree.
I was also wondering if there is a way to plot only certain vertices from the graph? For example, you choose one vertex and plot only the vertices that form a path back to it?
Based on the help for tkplot, here's an example of how to add a title to an interactive plot:
library(tcltk)
id = tkplot(pg, edge.label = nod$wt, main = "this is my graph")
canvas = tk_canvas(id)
width = as.numeric(tkcget(canvas, "-width"))
height = as.numeric(tkcget(canvas, "-height"))
tkcreate(canvas, "text", width/2, 25, text="My title",
justify="center",
font=tkfont.create(family="helvetica", size=20, weight="bold"))
For the standard base R plot, your code works as is:
plot(pg, edge.label = nod$wt, main = "this is my graph")
legend('topleft',legend= degree(pg)*5,pt.cex=20,col='white',
pch=21, pt.bg='white')

increase margins between venn.diagramm plots within grid.layout

I'm trying to display 4 venn.diagramm plots in a grid. I need to increase the space between diagrams in order that my legends don't overlap with other diagrams (or be outside of the plots).
I tried to do so by playing with margin in the function venn.diagram but this lead to increase the distance between the diagrams and their respective subtitles (what is not good).
I have seen some questions related to mine (e.g. controlling the inner figure margin within grid.layout) but they didn't work in my case.
Here is my code:
library(VennDiagram)
library(grid)
library(gridBase)
library(lattice)
# data
l1 <- list(Deletion=1:1420, Insertion=967:2042)
l2 <- list(Deletion=1:502, Insertion=324:660)
l3 <- list(Deletion=1:142, Insertion=85:184)
l4 <- list(Deletion=1:161, Insertion=22:217)
venns <- list(Subtargets=l1, Targets=l2, Genes=l3, Promoters=l4)
# set up grid layout
gl <- grid.layout(nrow=2, ncol=2)
# setup viewports
vp.1 <- viewport(layout.pos.col=1, layout.pos.row=1)
vp.2 <- viewport(layout.pos.col=2, layout.pos.row=1)
vp.3 <- viewport(layout.pos.col=1, layout.pos.row=2)
vp.4 <- viewport(layout.pos.col=2, layout.pos.row=2)
# init layout
pushViewport(viewport(layout=gl))
for (i in 1:4){
# access the relevant viewport
vp <- paste("vp.", i, sep="")
pushViewport(get(vp))
# draw the venn diagram
temp <- venn.diagram(venns[[i]], fill = c("red", "green"), alpha = c(0.5, 0.5),
cex = 1,cat.fontface = 2, lty =2, filename = NULL, sub=names(venns)[i],
margin = 0.5, sub.pos = c(0.5, 0.78), sub.col="blue")
# plot the venn diagram on the viewport
grid.draw(temp)
# done with this viewport
popViewport()
}
Any idea? Maybe by increasing the margins between viewports without changing the parameters within wiewport?
I met this problem before and my solution is to create more grids.
gl <- grid.layout(nrow=3, ncol=3, widths = c(1, 0.2, 1), heights = c(1, 0.2, 1))
grid.show.layout(gl)
Then you can plot your venn diagram on the corner grids.

Resources