New to igraph. I would like to have vertex colours be defined by another parameter, preferably continuous colours (think heatmap or grayscale).
clusters_only <- as.character(temp_df$SeqID)
v_names <- data.frame(c(unique_order, as.character(temp_df$SeqID)))
graph_order <- graph.data.frame(temp_df, directed = FALSE, vertices = v_names)
V(graph_order)[clusters_only]$size <- ? #continuous colour based on variable in temp_df
Any ideas?
Much appreciated.
You can use the color attribute of vertices to specify the vertex colors. It may be a string (containing a color name known to R) or a numeric value, in which case the color will be selected from the current palette. E.g.:
library(igraph)
g <- grg.game(100, 0.2)
V(g)$color <- 1:100
palette(gray.colors(100))
plot(g)
Alternatively, you may specify the colors as the argument of plot instead of assigning them to a vertex attribute:
plot(g, vertex.color <- 1:100)
I had better luck with this syntax:
R> library(igraph)
R> g <- grg.game(100, 0.2)
R> V(g)$color <- 1:100
R> g$palette <- grey.colors(100) #### updated this line
R> plot(g)
Maybe the grammar has changed since the original answer?
Related
I am plotting a biological trasnport network in igraph (in R) where I want to show edges in a color gradient based on an edge attribute (which is a continuous variable called "width" in my case). I do not like the default color palette obtained in:
plot(graph, edge.color=E(graph)$width)
Looking at the igraph plot help I found a way to change this palette using cscale from the scales package:
plot(graph,
edge.color=cscale(E(graph)$width,palette = seq_gradient_pal(low = "yellow",high = "red")))
That works fine and may stick to it. However I was wondering whether I could use either viridis or colorbrewer palettes. I have not figured out how to do it. The main issue is that I cannot manage to assign color coding to all edges. For example if I just do this:
plot(graph,
edge.color=cscale(E(graph)$width,palette = viridis_pal())
I get this warning:
In seq.default(begin, end, length.out = n) :
first element used of 'length.out' argument
And indeed the first color is applied to all edges
If I try to specify the length of all edges:
plot(graph,
edge.color=cscale(E(graph)$width,palette = viridis_pal()(ecount(graph))
I get this error message:
Error in palette(x) : invalid argument type)
Any ideas?
I had a similar problem --- I wanted to color edges using the viridis palette --- that I solved with SymbolixAU's colourvalues.
library(igraph)
library(viridis)
library(colourvalues)
# read in data frame with pairwise distances,
# convert to lower triangular matrix, and
# stash the column names for later use. Then,
g <- graph_from_adjacency_matrix(m,mode="lower",weighted=TRUE,add.colnames=TRUE)
V(g)$name <- colnames(m)
E(g)$color <- colour_values(E(g)$weight,palette = "viridis")
plot(g, vertex.label=V(g)$name,edge.width = E(g)$weight/10, edge.label=E(g)$weight,edge.color=E(g)$color)
Warmest thanks, SymbolixAU!
I am new in R and I am starting to work on graph visualization over there using igraph. The example below create a simple network of 10 vertices and color them according to color values (which in this case for simplicity I set up to be the same as ids of vertices).
library(igraph)
vertices <- 1:10
first <- 1:10
second <- c(2:10,1)
edges = cbind(first,second)
color = 1:10
net = graph_from_data_frame(edges,vertices=vertices ,directed=F )
V(net)$color = color
plot(net)
However from this plot it is not clear which colors correspond to
which numbers:
To deal with this I have tried to create various
legends I was able to find in the documentation and online. Take for
instance the code below:
legend("bottom", legend=levels(as.factor(color)), bty = "n", cex =
1.5, pt.cex = 3, pch=20, col = color , horiz = FALSE , inset = c(0.1,
-0.3)
But in this case, the result is messy, obscure the picture, and do not provide a continuous color bar that would map the range of values on the nodes to color spectrum. Other options I was able to find are not better.
Do you know how to make a legend in a form of a continuous color bar placed below or to the right from the picture (so that it do not cover any part of it)? Ideally the color bar should show the whole continuous spectrum of colors and a few values corresponding to the colors (at least the extreme ones)?
Do you happen to know how to achieve this?
Thank you for your help!
You should check out this answer by kokkenbaker,although it is a bit cumbersome, it might be just what you need.
How to add colorbar with perspective plot in R
Thanks to ealbsho93 I was able to produce the following solution. It create a pallete, then map the values on the vertices on the graph to the pallete and displays it. It is not straightforward, but the result looks much better (see below)
rm(list=ls())
library(igraph)
library(fields)
vertices <- 1:10
first <- 1:10
second <- c(2:10,1)
edges = cbind(first,second)
net = graph_from_data_frame(edges,vertices=vertices ,directed=F )
#Here we create a sample function on the vertices of the graph
color_num = 10:1
#create a color palette of the same size as the number of vertices.
jet.colors <- colorRampPalette( rainbow( length( unique(color_num) ) ) )
color_spectrum <- jet.colors( length( unique(color_num ) ) )
#and over here we map the pallete to the order of values on vertices
ordered <- order(color_num)
color <- vector(length = length(ordered),mode="double")
for ( i in 1:length(ordered) )
{
color[ ordered[i] ] <- color_spectrum [ i ]
}
V(net)$color = color
#Display the graph and the legend.
plot(net)
image.plot(legend.only=T, zlim=range(color_num), col=color_spectrum )
If there is a better solution, please let me know. Othervise, this one seems to be OK to use.
I'm trying to plot a temporal social network in R. My approach is to create a master graph and layout for all nodes. Then, I will subset the graph based on a series of vertex id's. However, when I do this and layout the graph, I get completely different node locations. I think I'm either subsetting the layout matrix incorrectly. I can't locate where my issue is because I've done some smaller matrix subsets and everything seems to work fine.
I have some example code and an image of the issue in the network plots.
library(igraph)
# make graph
g <- barabasi.game(25)
# make graph and set some aestetics
set.seed(123)
l <- layout_nicely(g)
V(g)$size <- rescale(degree(g), c(5, 20))
V(g)$shape <- 'none'
V(g)$label.cex <- .75
V(g)$label.color <- 'black'
E(g)$arrow.size = .1
# plot graph
dev.off()
par(mfrow = c(1,2),
mar = c(1,1,5,1))
plot(g, layout = l,
main = 'Entire\ngraph')
# use index & induced subgraph
v_ids <- sample(1:25, 15, F)
sub_l <- l[v_ids, c(1,2)]
sub_g <- induced_subgraph(g, v_ids)
# plot second graph
plot(sub_g, layout = sub_l,
main = 'Sub\ngraph')
The vertices in the second plot should match layout of those in the first.
Unfortunately, you set the random seed after you generated the graph,
so we cannot exactly reproduce your result. I will use the same code but
with set.seed before the graph generation. This makes the result look
different than yours, but will be reproducible.
When I run your code, I do not see exactly the same problem as you are
showing.
Your code (with set.seed moved and scales added)
library(igraph)
library(scales) # for rescale function
# make graph
set.seed(123)
g <- barabasi.game(25)
# make graph and set some aestetics
l <- layout_nicely(g)
V(g)$size <- rescale(degree(g), c(5, 20))
V(g)$shape <- 'none'
V(g)$label.cex <- .75
V(g)$label.color <- 'black'
E(g)$arrow.size = .1
## V(g)$names = 1:25
# plot graph
dev.off()
par(mfrow = c(1,2),
mar = c(1,1,5,1))
plot(g, layout = l,
main = 'Entire\ngraph')
# use index & induced subgraph
v_ids <- sort(sample(1:25, 15, F))
sub_l <- l[v_ids, c(1,2)]
sub_g <- induced_subgraph(g, v_ids)
# plot second graph
plot(sub_g, layout = sub_l,
main = 'Sub\ngraph', vertex.label=V(sub_g)$names)
When I run your code, both graphs have nodes in the same
positions. That is not what I see in the graph in your question.
I suggest that you run just this code and see if you don't get
the same result (nodes in the same positions in both graphs).
The only difference between the two graphs in my version is the
node labels. When you take the subgraph, it renumbers the nodes
from 1 to 15 so the labels on the nodes disagree. You can fix
this by storing the node labels in the graph before taking the
subgraph. Specifically, add V(g)$names = 1:25 immediately after
your statement E(g)$arrow.size = .1. Then run the whole thing
again, starting at set.seed(123). This will preserve the
original numbering as the node labels.
The graph looks slightly different because the new, sub-graph
does not take up all of the space and so is stretched to use
up the empty space.
Possible fast way around: draw the same graph, but color nodes and vertices that you dont need in color of your background. Depending on your purposes it can suit you.
I am trying to plot a map with positive and negative values.
All positive values should have red color while negative should have blue color and zero should have white just like in this sample plot with discrete colors
Below is the code I'm using:
library (rasterVis)
ras1 <- raster(nrow=10,ncol=10)
set.seed(1)
ras1[] <- rchisq(df=10,n=10*10)
ras2=ras1*(-1)/2
s <- stack(ras1,ras2)
levelplot(s,par.settings=RdBuTheme())
Thanks very much for providing a general solution which can be applied in other mapping exercises as well.
I wrote a gist to do this. It takes a trellis object generated by rasterVis::levelplot, and a colour ramp, and plots the object with the colours diverging around zero.
Using your s, you can use it like this:
devtools::source_gist('306e4b7e69c87b1826db')
p <- levelplot(s)
diverge0(p, ramp='RdBu')
ramp should be the name of a RColorBrewer palette, a vector of colours to be interpolated, or a colorRampPalette.
Here's the source:
diverge0 <- function(p, ramp) {
# p: a trellis object resulting from rasterVis::levelplot
# ramp: the name of an RColorBrewer palette (as character), a character
# vector of colour names to interpolate, or a colorRampPalette.
require(RColorBrewer)
require(rasterVis)
if(length(ramp)==1 && is.character(ramp) && ramp %in%
row.names(brewer.pal.info)) {
ramp <- suppressWarnings(colorRampPalette(brewer.pal(11, ramp)))
} else if(length(ramp) > 1 && is.character(ramp) && all(ramp %in% colors())) {
ramp <- colorRampPalette(ramp)
} else if(!is.function(ramp))
stop('ramp should be either the name of a RColorBrewer palette, ',
'a vector of colours to be interpolated, or a colorRampPalette.')
rng <- range(p$legend[[1]]$args$key$at)
s <- seq(-max(abs(rng)), max(abs(rng)), len=1001)
i <- findInterval(rng[which.min(abs(rng))], s)
zlim <- switch(which.min(abs(rng)), `1`=i:(1000+1), `2`=1:(i+1))
p$legend[[1]]$args$key$at <- s[zlim]
p$par.settings$regions$col <- ramp(1000)[zlim[-length(zlim)]]
p
}
Note that, as suggested in #LucasFortini's post, the process is much simpler if you're happy to have the colorkey extend the same distance above and below zero, e.g.: levelplot(s,par.settings=RdBuTheme(), at=seq(-max(abs(cellStats(s, range))), max(abs(cellStats(s, range))), len=100)).
This is something I do frequently with the script below:
library(colorRamps)
col5 <- colorRampPalette(c('blue', 'gray96', 'red')) #create color ramp starting from blue to red
color_levels=20 #the number of colors to use
max_absolute_value=0.4 #what is the maximum absolute value of raster?
plot(img, col=col5(n=color_levels), breaks=seq(-max_absolute_value,max_absolute_value,length.out=color_levels+1) , axes=FALSE)
Using the data from here, here is an example output and actual script:
library(raster)
library(colorRamps)
mask_data=shapefile("D:/temp/so/Main_Hawaiian_Islands_simple3.shp")
img=raster("D:/temp/so/PPT_wet_minus_dry.tif")
col5 <- colorRampPalette(c('blue', 'gray96', 'red')) #create color ramp starting from blue to red
color_levels=10 #the number of colors to use
max_absolute_value=max(abs(c(cellStats(img, min), cellStats(img, max)))) #what is the maximum absolute value of raster?
color_sequence=seq(-max_absolute_value,max_absolute_value,length.out=color_levels+1)
plot(img, col=col5(n=color_levels), breaks=color_sequence, axes=FALSE)
plot(mask_data, add=T)
This may bother some as there are a lot of color bins on the negative range that are unused (like the example you provided). The modification below allows for the exclusion of the empty colors from the map legend:
n_in_class=hist(img, breaks=color_sequence, plot=F)$counts>0
col_to_include=min(which(n_in_class==T)):max(which(n_in_class==T))
breaks_to_include=min(which(n_in_class==T)):(max(which(n_in_class==T))+1)
plot(img, col=col5(n=color_levels)[col_to_include], breaks=color_sequence[breaks_to_include] , axes=FALSE)
plot(mask_data, add=T)
From a dataframe data.main, I am able to generate a hclust dendrogram as,
aa1<- c(2,4,6,8)
bb1<- c(1,3,7,11)
aa2<-c(3,6,9,12)
bb2<-c(3,5,7,9)
data.main<- data.frame(aa1,bb1,aa2,bb2)
d1<-dist(t(data.main))
hcl1<- hclust(d1)
plot(hcl1)
Further, I know there are ways to use a tree cutoff to color the branches or leaves. However, is it possible to color them based on partial column names or column number (e.g. I want that branch corresponding to aa1, aa2 be red and bb1 and bb2 be blue)?
I have checked the R package dendextend but am still not able to find a direct/easy way to get the desired result.
It's easier to change colors for a dendrogram than an hclust object, but it's pretty straightforward to convert. You can do
drg1 <- dendrapply(as.dendrogram(hcl1, hang=.1), function(n){
if(is.leaf(n)){
labelCol <- c(a="red", b="blue")[substr(attr(n,"label"),1,1)];
attr(n, "nodePar") <- list(pch = NA, lab.col = labelCol);
attr(n, "edgePar") <- list(col = labelCol); # to color branch as well
}
n;
});
plot(drg1)
which will draw
UPDATE
I'm only leaving my answer because it is valid and someone might find OOMPA useful. However, after seeing the solution of using dendrapply as suggested by MrFlick, I recommend it instead. You might find other features of the OOMPA package useful, but I wouldn't install it just for functionality that already exists in core R.
Original Answer
Install OOMPA (Object-Oriented Microarray and Proteomics Analysis package):
source("http://silicovore.com/OOMPA/oompaLite.R")
oompaLite()
Then use the plotColoredClusters function from the library ClassDiscovery:
library(ClassDiscovery)
aa1<- c(2,4,6,8)
bb1<- c(1,3,7,11)
aa2<-c(3,6,9,12)
bb2<-c(3,5,7,9)
data.main<- data.frame(aa1,bb1,aa2,bb2)
d1<-dist(t(data.main))
hcl1<- hclust(d1)
#identify the labels
labels=hcl1[4]$labels
# Choose which ones are in the "aa" group
aa_present <- grepl("aa", labels)
colors <- ifelse(aa_present, "red", "blue")
plotColoredClusters(hcl1,labs=labels,cols=colors)
Result:
ice, the dendextend package allows to do this using the assign_values_to_leaves_edgePar function.
Here is how to use it:
aa1 <- c(2,4,6,8)
bb1 <- c(1,3,7,11)
aa2 <- c(3,6,9,12)
bb2 <- c(3,5,7,9)
data.main <- data.frame(aa1,bb1,aa2,bb2)
d1 <- dist(t(data.main))
hcl1 <- hclust(d1)
# plot(hcl1)
dend <- as.dendrogram(hcl1)
col_aa_red <- ifelse(grepl("aa", labels(dend)), "red", "blue")
dend2 <- assign_values_to_leaves_edgePar(dend=dend, value = col_aa_red, edgePar = "col")
plot(dend2)
Result: