I'm using igraph to plot networks and can't seem to get nodes (vertices) not drawn over top of each other.
My code:
g<-graph.empty(n=0, directed=FALSE)
nodes<-my_verts
edge<-my_intra_edges
freq<-nodes[,2]
max_freq<-sum(freq)
frequency<-freq*50/max_freq
colour1<-heat.colors(max_freq/2+2)
colour<-rev(colour1)
g<-igraph::add.vertices(g, length(nodes[,2]), name=as.character(nodes[,1]), color=colour[freq/2+2])
names<-V(g)$name
ids<-1:length(names)
names(ids)<-names
from<-as.character(edge[,1])
to<-as.character(edge[,2])
edges<-matrix(c(ids[from], ids[to]), nc=2)
my_weight<-edge[,3]
g<-add.edges(g, t(edges), weight=my_weight)
V(g)$label<-V(g)$name
my_radius<-sqrt(my_verts[,2]/pi)
V(g)$size<-my_radius
V(g)$label.cex<-0.0001
del_ids<-intersect(which(degree(g)==0), which(freq==1))
g1<-delete.vertices(g, ids[del_ids])
length(del_ids)
jpeg(file="BC9.jpeg", height=7016, width=7016, res=600)
par(mfrow=c(1,1), mar=c(5,5,5,5))
title=c("BC9")
layout<-layout_with_graphopt(g1, niter=800)
plot(g1, layout=layout, edge.color="darkblue", main=title, edge.width=0.2)
dev.off()
This currently will plot most nodes as independent points but some nodes get plotted on top of each other. Is there a way to get the nodes to have better spacing?
Thanks.
I have the same problem with igraph, the layouts these algorithms provide don't seem to prevent overlap of nodes.
Someone will probably come up with a good igraph-only solution but my very tedious current workaround for this is: I open the network on Gephi, then I use Force Atlas 2 algorithm with the "prevent overlap" option checked, I save the .gexf file, then later I extract the x,y,z coordinates from the file, then I use it as the layout in igraph.
From what I understand, the coordinates for the plots are rescaled, but you can stop that with the rescale argument and do things manually. You can also use the norm_coords() to normalize the plot with the boundaries you have. I don't understand all the detail in this, but it works for me.
library(igraph)
g <- barabasi.game(100) # create a graph
lo <- layout_with_kk(g) # create a layout
lo <- norm_coords(lo, ymin=-1, ymax=1, xmin=-1, xmax=1)
# I think this tells igraph to normalize the coordinates of the
# layout relative to the space you're working with
# see how it works
par(mfrow=c(1,2), mar=c(0,0,0,0))
plot(g, edge.arrow.width = .25,
edge.arrow.size = .25,
vertex.label = NA,
vertex.size = 5,
rescale=FALSE,
layout=lo*0.25)
plot(g, edge.arrow.width = .25,
edge.arrow.size = .25,
vertex.label = NA,
vertex.size = 5,
rescale=FALSE,
layout=lo*1)
Created on 2020-09-10 by the reprex package (v0.3.0)
Related
I have a really wordy network plot. I am basically trying to have it function as a sort of flow chart. I am trying to make its aesthetics both functional and pleasing, but I am having a difficult time. The legend's text is way too large and there is not enough space in the network for everything to be spaced out properly. Also, I want to make the background a different color.
The only solutions I have been able to find, however, require the ggnet2 package, but when I try to install the ggnet2 package, it says I cannot install that on this version of rStudio. When I tried to update my rStudio, it says that I have the most recent version of rStudio. I do not know what else to try.
Any help would be much appreciated! This is my code:
library(igraph)
library(RColorBrewer)
links <- data.frame(
source=c("Pubertal Hormones, Timing, and Development","Pubertal Hormones, Timing, and Development","Pubertal Hormones, Timing, and Development","Pubertal Hormones, Timing, and Development","Genetic Vulnerability","Genetic Vulnerability","Temperament","Temperament","Depressogenic Vulnerability","Negative Cognitive Style","Negative Cognitive Style","Objectified Body Consciousness","Objectifed Body Consciousness","Rumination","Peer Sexual Harassment","Peer Sexual Harassment"),
target=c("Genetic Vulnerability","Objectified Body Consciousness","Peer Sexual Harassment","Depressogenic Vulnerability","Temperament","Depressogenic Vulnerability","Negative Cognitive Style","Depressogenic Vulnerability","Gender Difference in Depression","Rumination","Depressogenic Vulnerability","Rumination","Depressogenic Vulnerability","Depressogenic Vulnerability","Objectified Body Consciousness","Gender Difference in Depression"),
importance=(sample(1:4, 16, replace=T))
)
V = c(links$source,
links$target) %>%
unique()
nodes <- data.frame( name=V,
carac=c(
rep("Biological Vulnerability",2),rep("Affective Vulnerability",3),rep("Cognitive Vulnerability",3),rep("Negative Life Events",2)) )
network <- graph_from_data_frame(d=links, vertices=nodes, directed=F)
coul <- brewer.pal(4, "Set3")
my_color <- coul[as.numeric(as.factor(V(network)$carac))]
plot(network, vertex.color=my_color,vertex.shape=c("vrectangle"),vertex.size=c(150),vertex.label.cex=c(0.5))
legend("bottom", legend=levels(as.factor(V(network)$carac)) , col = coul , bty = "n", pch=20 , pt.cex = 3, cex = 1, text.col=coul , horiz = TRUE, inset = c(0.1, 0.1))
With a small graph like this, you can customize the layout so that things look nicer. We'll just step through the problems one at a time. Let's start from your plot statement, but let's make it reproducible by setting the random seed.
set.seed(123)
plot(network, vertex.color=my_color,vertex.shape=c("vrectangle"),
vertex.size=c(150),vertex.label.cex=c(0.5))
The biggest problem is that the plot does not use all of the space in the graphics window. You can adjust that some with the margin parameter. When I do that, the boxes seem too big, so I will make them a bit smaller at the same time and also change the text size to match the new boxes.
set.seed(123)
LO = layout_nicely(network)
plot(network, layout=LO, margin=-0.6, vertex.color=my_color,
vertex.shape=c("vrectangle"), vertex.size=c(100),
vertex.label.cex=c(0.7))
OK, this is better, but there still are some problems. First, the box for "Pubertal Hormones, Timing, and Development" is too small. We can adjust that by using a vector of vertex sizes. When we change that, there are some other changes in the plot, so let's just make that one change first.
VS = rep(100, vcount(network))
VS[1] = 150
plot(network, layout=LO, margin=-0.7, vertex.color=my_color,
vertex.shape=c("vrectangle"), vertex.size=VS,
vertex.label.cex=c(0.7))
Next, some of the boxes overlap. We can fix those by editing the layout matrix. This matrix is just the x,y coordinates at which to plot the nodes. I just looked at the matrix and adjusted the positions a little.
LO[1,] = c(6.3,7.3)
LO[4,] = c(5.4,6.7)
LO[5,] = c(5,5.5)
LO[7,] = c(7.4,6.8)
LO[8,] = c(5.1,6.2)
LO[9,] = c(5.2,8.4)
LO[10,] = c(7,8.3)
plot(network, layout=LO, margin=-0.7, vertex.color=my_color,
vertex.shape=c("vrectangle"), vertex.size=VS,
vertex.label.cex=c(0.7))
This is pretty good. More could be done, but I think the method is clear, so I will leave any additional aesthetic adjustments of the nodes to you.
Now to finish up, you wanted to adjust the background color. You can do that (before plotting) by setting bg using par. The final version is:
par(bg="lightblue1")
plot(network, layout=LO, margin=-0.7, vertex.color=my_color,
vertex.shape=c("vrectangle"), vertex.size=VS,
vertex.label.cex=c(0.7))
I am building a phylogenetic tree using data from NCBI taxonomy. The tree is quite simple, its aims is to show the relationship among a few Arthropods.
The problem is the tree looks very small and I can't seem to make its branches longer. I would also like to color some nodes (Ex: Pancrustaceans) but I don't know how to do this using ape.
Thanks for any help!
library(treeio)
library(ape)
treeText <- readLines('phyliptree.phy')
treeText <- paste0(treeText, collapse="")
tree <- read.tree(text = treeText) ## load tree
distMat <- cophenetic(tree) ## generate dist matrix
plot(tree, use.edge.length = TRUE,show.node.label = T, edge.width = 2, label.offset = 0.75, type = "cladogram", cex = 1, lwd=2)
Here are some pointers using the ape package. I am using a random tree as we don't have access to yours, but these examples should be easily adaptable to your problem. If your provide a reproducible example of a specific question, I could take another look.
First me make a random tree, add some species names, and plot it to show the numbers of nodes (both terminal and internal)
library(ape)
set.seed(123)
Tree <- rtree(10)
Tree$tip.label <- paste("Species", 1:10, sep="_")
plot.phylo(Tree)
nodelabels() # blue
tiplabels() # yellow
edgelabels() # green
Then, to color any node or edge of the tree, we can create a vector of colors and provide it to the appropriate *labels() function.
# using numbers for colors
node_colors <- rep(5:6, each=5)[1:9] # 9 internal nodes
edge_colors <- rep(3:4, each=9) # 18 branches
tip_colors <- rep(c(11,12,13), 4)
# plot:
plot.phylo(Tree, edge.color = edge_colors, tip.color = tip_colors)
nodelabels(pch = 21, bg = node_colors, cex=2)
To label just one node and the clade descending from it, we could do:
Nnode(Tree)
node_colors <- rep(NA, 9)
node_colors[7] <- "green"
node_shape <- ifelse(is.na(node_colors), NA, 21)
edge_colors <- rep("black", 18)
edge_colors[13:18] <- "green"
plot(Tree, edge.color = edge_colors, edge.width = 2, label.offset = .1)
nodelabels(pch=node_shape, bg=node_colors, cex=2)
Without your tree, it is harder to tell how to adjust the branches. One way is to reduce the size of the tip labels, so they take up less space. Another way might be to play around when saving the png or pdf.
There are other ways of doing these embellishments of trees, including the ggtree package.
I would like to get something like this
A network graph with or without labels but with nodes aligned.
How can I get it?
I'm already used the packages Diagrammer and Visnetwork for other graphs, so using the same will be a bonus.
library(DiagrammeR)
library(visNetwork)
from=c("A","A","A","A","B","B","B","C","C","D")
to=c("B","C","D","E","C","D","E","D","E","E")
nodesd=c("A","B","C","D","E")
With Diagrammer:
nodes <- create_node_df( n=length(nodesd), label=nodesd, width=0.3)
edges <- create_edge_df(from = factor(from, levels=nodesd), to = factor(to, levels=nodesd), rel = "leading_to")
graph <- create_graph(nodes_df = nodes, edges_df = edges)
render_graph(graph)
I've also tried with set_node_position() but it doesn't seem to make any difference.
With Visnetwork
nodes <- data.frame(id=nodesd, label= nodesd )
edges <- data.frame(from=from, to =to, length=150)
visNetwork(nodes,edges, width="100%" , height="100%") %>%
visNodes(shape = "circle") %>% visEdges(arrows = 'to', smooth =T)
As you can see the nodes are not aligned. How can I force it to do it?
I could drag them manually but it's not something you want to do if you have many graphs, and the result is not good anyway.
I got to do it vertically with visnetwork by adding the line
%>% visHierarchicalLayout()
at the end. But it doesn't work well because many edges disappear.
If I want to get a horizontal alignement I need to add this to the nodes definition.
level = c(1,1,1,1,1)
I can't help you with DiagrammeR or visNetwork, but it is easy to do this with igraph. You just need to specify a simple layout of the nodes. You will also want to adjust the curvature of the edges. My example below has something that works, but you might adjust it to make it more artistic.
library(igraph)
EL = cbind(from, to)
g = graph_from_edgelist(EL)
L = cbind(1:5, 5:1)
CURVE = c(0,0.15, 0.3, 0.45, 0, -0.15, -0.3, 0, 0.15, 0)
plot(g, layout=L, edge.curved=CURVE)
I'm trying to arrange a phylogenetic tree onto a graph showing physiological data for a set of related organisms. Something like the picture below. This was put together in powerpoint from 2 separate graphs. I guess it gets the job done, but I was hoping to create a single image which I think will be easier to format into a document. I am able to produce the graph I want using ggplot2, and import the tree using ape. I was thinking there should be a way to save the tree as a graphical object and then arrange it with the graph using the gridarrange function in gridExtra. The problem is that ape won't let me save the tree as a graphical object, e.g.,
p2<-plot(tree, dir = "u", show.tip.label = FALSE)
just plots the tree and when you call p2 it just gives a list of arguments. I'm wondering if anyone has any tips.
Thanks!
I'm not sure if that will work with gtable from CRAN
require(ggplot2)
require(gridBase)
require(gtable)
p <- qplot(1,1)
g <- ggplotGrob(p)
g <- gtable_add_rows(g, unit(2,"in"), nrow(g))
g <- gtable_add_grob(g, rectGrob(),
t = 7, l=4, b=7, r=4)
grid.newpage()
grid.draw(g)
#grid.force()
#grid.ls(grobs=F, viewports=T)
seekViewport("layout.7-4-7-4")
par(plt=gridPLT(), new=TRUE)
plot(rtree(10), "c", FALSE, direction = "u")
upViewport()
first I'd like to thanks baptiste for ALL his multiple answers that solved most of my issues with ggplot2.
second, I had a similar question which was to include a tree from ape inside a heatmap obtained with ggplot2. Baptiste made my day, and though my simplified version could help.
I used only what was useful for me (removing the addition of gg_rows).
library(ape)
tr <- read.tree("mytree.tree")
# heat is the heatmap ggplot, using geom_tile
g <- ggplotGrob(heat)
grid.newpage()
grid.draw(g)
# use oma to reduce the tree so it fits
par(new = TRUE, oma = c(5, 4, 5, 38))
plot(tr)
nodelabels(tr$node.label, cex = 1, frame = "none", col = "black", adj = c(-0.3, 0.5))
add.scale.bar()
# use dev.copy2pdf and not ggsave
dev.copy2pdf(file = "heatmap_prob.pdf")
the result is here
I've never used any graph plotting package in R, I'm familiar with basic plotting commands and with ggplot2 package. What I've found (but not tried out yet) are Rgraphviz, network and igraph packages. So I'd like to ask you, which package has simplest learning curve and satisfies following requirements:
Has simple layout engines (spring layout, random, ...)
Tries to draw multiple edges between two vertices so that they would not overlap. As a bonus it would be nice to being able to adjust this.
Can draw loops.
Vertex and edge labels, vertex and edge size and color are adjustable.
(No need for any of the graph algorithms like link analysis, shortest path, max flow etc, but nice, if present)
The igraph package seems to fulfill your requirements, with the tkplot() function helping adjusting the final layout if needed.
Here is an example of use:
s <- cbind(A=sample(letters[1:4], 100, replace=TRUE),
B=sample(letters[1:2], 100, replace=TRUE))
s.tab <- table(s[,1], s[,2])
library(igraph)
s.g <- graph.incidence(s.tab, weighted=T)
plot(s.g, layout=layout.circle,
vertex.label=c(letters[1:4],letters[2:1]),
vertex.color=c(rep("red",4),rep("blue",2)),
edge.width=c(s.tab)/3, vertex.size=20,
vertex.label.cex=3, vertex.label.color="white")
With the interactive display (there's a possibility of using rgl for 3D display), it looks like (I have slightly moved one vertex afterwards):
tkplot(s.g, layout=layout.circle, vertex.color=c(rep("red",4),rep("blue",2)))
Finally, you can even export you graph into most common format, like dot for graphviz.
The multigraph R package can be useful as well. For the above example bmgraph plots such graph:
library("multigraph")
bmgraph(s.tab, layout = "circ", pch = 16:16, pos = 0, vcol = 6:7, lwd = 3, cex = 9)
And for a directed version:
bmgraph(s.tab, "circ", pch = 16:16, pos = 0, vcol = 6:7, lwd = 3, cex = 9, directed = TRUE)