The plot does not display when arranged as single plot? - r

I created a heatmap and a pca plot and tried to merge them as single figure. But the are not displayed as single figure.
library(factoextra)
library(FactoMineR)
library(pheatmap)
library(RColorBrewer)
library(ggpubr)
# make test matrix
test = matrix(rnorm(200), 20, 10)
test[1:10, seq(1, 10, 2)] = test[1:10, seq(1, 10, 2)] + 3
test[11:20, seq(2, 10, 2)] = test[11:20, seq(2, 10, 2)] + 2
test[15:20, seq(2, 10, 2)] = test[15:20, seq(2, 10, 2)] + 4
colnames(test) = paste("Test", 1:10, sep = "")
rownames(test) = paste("Gene", 1:20, sep = "")
# define the annotation
annotation_row = data.frame(GeneClass = factor(rep(c("Path1", "Path2", "Path3"), c(10, 4, 6))),
AdditionalAnnotation = c(rep("random1", 10), rep("random2", 10)))
rownames(annotation_row) = paste("Gene", 1:20, sep = "")
a=pheatmap(test, annotation_row = annotation_row)
# creating pca
# Compute PCA with ncp = 3
res.pca <- PCA(test, ncp = 3, graph = FALSE)
# Compute hierarchical clustering on principal components
res.hcpc <- HCPC(res.pca, graph = FALSE)
# Principal components + tree
b=plot(res.hcpc, choice = "3D.map")
#arranging in a single plot
ggarrange(a$gtable, b, labels = c("A", "B"))
The output was without pca:

plot (or plot.HCPC) returns NULL and therefore b is NULL.
And from ?ggarrange, it expects a list of plots to be arranged into the grid. The plots can be either ggplot2 plot objects or arbitrary gtables.
So one option could be using as.ggplot() function from {ggplotify} package to convert that base plot to ggplot object and then pass it to ggarrange.
b <- ggplotify::as.ggplot(~plot(res.hcpc, choice = "3D.map"))
#arranging in a single plot
ggarrange(a$gtable, b, labels = c("A", "B"))

Related

how to put key values and legends at the bottom of the heatmap

Does anyone show me how to put the expression key index and the legend key to appear at the bottom of the heatmap using pheatmap? you can use the following code to generate the heatmap.
Thank you so much!
test = matrix(rnorm(200), 20, 10)
test[1:10, seq(1, 10, 2)] = test[1:10, seq(1, 10, 2)] + 3
test[11:20, seq(2, 10, 2)] = test[11:20, seq(2, 10, 2)] + 2
test[15:20, seq(2, 10, 2)] = test[15:20, seq(2, 10, 2)] + 4
colnames(test) = paste("Test", 1:10, sep = "")
rownames(test) = paste("Gene", 1:20, sep = "")
annotation_col = data.frame(
CellType = factor(rep(c("CT1", "CT2"), 5)), Time = c("A", "B", "C","D","E"))
rownames(annotation_col) = paste("Test",1:10, sep = "")
ann_colors = list(
Time = c(A = "white", B= "firebrick", C= "#fdbb84",D = "#e34a33", E = "red"),
CellType = c(CT1 = "#1B9E77", CT2 = "#D95F02"))
library("pheatmap")
pheatmap(test, annotation_col = annotation_col, annotation_colors = ann_colors)
pheatmap doesn't appear to offer the ability to control the position of the legend.
The code the draws your heatmap can be found here https://github.com/raivokolde/pheatmap.
Check out the R/pheatmap-package.r file.
That legend seems to be pretty hard-coded, see # Legend position and draw_legend = function(color, breaks, legend, ...

Creating subplot (facets) with custom x,y position of the subplots in ggplot2

How can we custom the position of the panels/subplot in ggplot2?
Concretely I have a grouped times series and I want to produce 1 subplot per time series with custom positions of the subplot, not necessarily in a grid.
The facet_grid() or facet_wrap() functions do not provide a full customization of the position of the panel as it uses grid.
library(tidyverse)
df = data.frame(group = LETTERS[1:5],
x = c(1,2,3,1.5,2.5),
y =c(2,1,2,3,3),
stringsAsFactors = F)%>%
group_by(group)%>%
expand_grid(time = 1:20)%>%
ungroup()%>%
mutate(dv = rnorm(n()))%>%
arrange(group,time)
## plot in grid
df%>%
ggplot()+
geom_line(aes(x=time,y=dv))+
facet_grid(~group)
## plot with custom x, y position
## Is there an equivalent of facet_custom()?
df%>%
ggplot()+
geom_line(aes(x=time,y=dv))+
facet_custom(~group, x.subplot = x, y.subplot = y)
FYI: This dataset is only an example. My data are EEG data where each group represents an electrode (up to 64) and I want to plot the EEG signals of each electrode accordingly to the position of the electrode on the head.
Well, I guess this would not really be a 'facet plot' any more. I therefore don't think there is a specific function out there.
But you can use the fantastic patchwork package for that, in particular the layout option in wrap_plots.
As the main package author Thomas describes in the vignette, the below option using area() may be a bit verbose, but it would give you full programmatic options about positioning all your plots.
library(tidyverse)
library(patchwork)
mydf <- data.frame(
group = LETTERS[1:5],
x = c(1, 2, 3, 1.5, 2.5),
y = c(2, 1, 2, 3, 3),
stringsAsFactors = F
) %>%
group_by(group) %>%
expand_grid(time = 1:20) %>%
ungroup() %>%
mutate(dv = rnorm(n())) %>%
arrange(group, time)
## plot in grid
mylist <-
mydf %>%
split(., .$group)
p_list <-
map(1:length(mylist), function(i){
ggplot(mylist[[i]]) +
geom_line(aes(x = time, y = dv)) +
ggtitle(names(mylist)[i])
}
)
layout <- c(
area(t = 1, l = 1, b = 2, r = 2),
area(t = 2, l = 3, b = 3, r = 4),
area(t = 3, l = 5, b = 4, r = 6),
area(t = 4, l = 3, b = 5, r = 4),
area(t = 5, l = 1, b = 6, r = 2)
)
wrap_plots(p_list, design = layout)
#> result not shown, it's the same as below
For a more programmatic approach, one option is to create the required "patch_area" object manually.
t = 1:5
b = t+1
l = c(1,3,5,3,1)
r = l+1
list_area <- list(t = t, b = b, l = l, r = r)
class(list_area) <- "patch_area"
wrap_plots(p_list, design = list_area)
Created on 2020-04-22 by the reprex package (v0.3.0)

How to force the row labels in a fixed width and be aligned in pheatmap in R?

Usually there is no problem to show the row labels in pheatmap in R. However, see I have a little bit complicated row labels which are strings that combined a head of one string and an end of another string. For example, "ABC**** 123".
Here is an example and my code:
library(pheatmap)
library(stringr)
# create an example
test = matrix(rnorm(200), 20, 10)
test[1:10, seq(1, 10, 2)] = test[1:10, seq(1, 10, 2)] + 3
test[11:20, seq(2, 10, 2)] = test[11:20, seq(2, 10, 2)] + 2
test[15:20, seq(2, 10, 2)] = test[15:20, seq(2, 10, 2)] + 4
colnames(test) = paste("Test", 1:10, sep = "")
rownames(test) = paste("Gene", 1:20, sep = "")
# make random pvalue to show at the end of rownames
random.pvalue <- formatC(runif(n = 20,min = 0.0000000000001,max = 0.00000000001),format = "e",
digits = 2)
# creat new rownames with fixed width
add.label <- paste0(str_pad(rownames(test),
width=12,
side="right"),
random.pvalue)
rownames(test) <- add.label # update rownames
# Draw heatmaps
pheatmap(test) # you could see the pvalues are not aligned
Trust me I have forced these row labels in a fixed width by using formatC() and str_pad() in R. However, when I used pheatmap with those row labels, the labels did not show as I thought, they went like the following, and you can clearly see that the row labels are not aligned even they have the same string width.
[1] "Gene1 7.77e-12" "Gene2 2.67e-12" "Gene3 8.67e-12" "Gene4 6.61e-12"
[5] "Gene5 2.36e-12" "Gene6 3.09e-12" "Gene7 5.44e-12" "Gene8 3.18e-13"
[9] "Gene9 1.34e-12" "Gene10 4.52e-12" "Gene11 2.03e-12" "Gene12 5.31e-12"
[13] "Gene13 9.66e-12" "Gene14 9.02e-12" "Gene15 2.91e-13" "Gene16 7.37e-13"
[17] "Gene17 7.95e-12" "Gene18 8.04e-12" "Gene19 8.31e-12" "Gene20 9.94e-12"
Maybe someone could use a simple example to teach me how to fix this.
Many thanks advanced!
You could use a fixed font (not a proportional one):
library(pheatmap)
library(grid)
library(stringr)
mat <- mtcars[1:10,1:6]
rn <- stringr::str_pad(rownames(mat), max(nchar(rownames(mat))), side = "right")
p <- signif(1e-9*mat[,4], digits = 4)
pheatmap::pheatmap(as.matrix(mtcars[1:10,1:6]), scale="column",
labels_row=paste(rn, p, sep=" "), fontfamily = "mono")

R heatmap.2 manual grouping of rows and columns [duplicate]

This question already has answers here:
How to create pre-annotated rowside column in heatmap.2
(2 answers)
Closed 6 years ago.
I have the following MWE in which I make a heatmap without performing any clustering and showing any dendrogram. I want to group my rows (genes) together in categories, in a better looking way than how it is now.
This is the MWE:
#MWE
library(gplots)
mymat <- matrix(rexp(600, rate=.1), ncol=12)
colnames(mymat) <- c(rep("treatment_1", 3), rep("treatment_2", 3), rep("treatment_3", 3), rep("treatment_4", 3))
rownames(mymat) <- paste("gene", 1:dim(mymat)[1], sep="_")
rownames(mymat) <- paste(rownames(mymat), c(rep("CATEGORY_1", 10), rep("CATEGORY_2", 10), rep("CATEGORY_3", 10), rep("CATEGORY_4", 10), rep("CATEGORY_5", 10)), sep=" --- ")
mymat #50x12 MATRIX. 50 GENES IN 5 CATEGORIES, ACROSS 4 TREATMENTS WITH 3 REPLICATES EACH
png(filename="TEST.png", height=800, width=600)
print(
heatmap.2(mymat, col=greenred(75),
trace="none",
keysize=1,
margins=c(8,14),
scale="row",
dendrogram="none",
Colv = FALSE,
Rowv = FALSE,
cexRow=0.5 + 1/log10(dim(mymat)[1]),
cexCol=1.25,
main="Genes grouped by categories")
)
dev.off()
Which produces this:
I would like to group the CATEGORIES in the rows together (and, if possible, the treatments in the columns as well), so it looks something like the following:
Or, maybe even better, with the CATEGORIES on the left, the same way as when clustering is performed and dendrograms are shown; however is easier and clearer...
Is there any way? Thanks!!
EDIT!!
I was made aware of the RowSideColors in the comments and I made the MWE below. However, I don't seem to be able to print the legend in the output png, plus the colors in the legend are not correct, and I cannot get the position right either. So please help me with the legend in the MWE below.
On another hand, I use the palette "Set3", consisting of 12 colors, but what if I need more than 12 colors (if I have more than 12 categories)??
NEW MWE
library(gplots)
library(RColorBrewer)
col1 <- brewer.pal(12, "Set3")
mymat <- matrix(rexp(600, rate=.1), ncol=12)
colnames(mymat) <- c(rep("treatment_1", 3), rep("treatment_2", 3), rep("treatment_3", 3), rep("treatment_4", 3))
rownames(mymat) <- paste("gene", 1:dim(mymat)[1], sep="_")
mymat
mydf <- data.frame(gene=paste("gene", 1:dim(mymat)[1], sep="_"), category=c(rep("CATEGORY_1", 10), rep("CATEGORY_2", 10), rep("CATEGORY_3", 10), rep("CATEGORY_4", 10), rep("CATEGORY_5", 10)))
mydf
png(filename="TEST.png", height=800, width=600)
print(
heatmap.2(mymat, col=greenred(75),
trace="none",
keysize=1,
margins=c(8,6),
scale="row",
dendrogram="none",
Colv = FALSE,
Rowv = FALSE,
cexRow=0.5 + 1/log10(dim(mymat)[1]),
cexCol=1.25,
main="Genes grouped by categories",
RowSideColors=col1[as.numeric(mydf$category)]
)
#THE LEGEND DOESN'T WORK INSIDE print(), AND THE POSITION AND COLORS ARE WRONG
#legend("topright",
# legend = unique(mydf$category),
# col = col1[as.numeric(mydf$category)],
# lty= 1,
# lwd = 5,
# cex=.7
# )
)
dev.off()
Which produces:
Please help me with the legend, and with the hypothetical case I need more than 12 colors. Thanks!
I would use pheatmap package. Your example would look something like that:
library(pheatmap)
library(RColorBrewer)
# Generte data (modified the mydf slightly)
col1 <- brewer.pal(12, "Set3")
mymat <- matrix(rexp(600, rate=.1), ncol=12)
colnames(mymat) <- c(rep("treatment_1", 3), rep("treatment_2", 3), rep("treatment_3", 3), rep("treatment_4", 3))
rownames(mymat) <- paste("gene", 1:dim(mymat)[1], sep="_")
mydf <- data.frame(row.names = paste("gene", 1:dim(mymat)[1], sep="_"), category = c(rep("CATEGORY_1", 10), rep("CATEGORY_2", 10), rep("CATEGORY_3", 10), rep("CATEGORY_4", 10), rep("CATEGORY_5", 10)))
# add row annotations
pheatmap(mymat, cluster_cols = F, cluster_rows = F, annotation_row = mydf)
# Add gaps
pheatmap(mymat, cluster_cols = F, cluster_rows = F, annotation_row = mydf, gaps_row = c(10, 20, 30, 40))
# Save to file with dimensions that keep both row and column names readable
pheatmap(mymat, cluster_cols = F, cluster_rows = F, annotation_row = mydf, gaps_row = c(10, 20, 30, 40), cellheight = 10, cellwidth = 20, file = "TEST.png")

Graphical output of density for the function gammamixEM (package mixtools)

I'm using the function gammamixEM from the package mixtools. How can I return the graphical output of density as in the function normalmixEM (i.e., the second plot in plot(...,which=2)) ?
Update:
Here is a reproducible example for the function gammamixEM:
x <- c(rgamma(200, shape = 0.2, scale = 14), rgamma(200,
shape = 32, scale = 10), rgamma(200, shape = 5, scale = 6))
out <- gammamixEM(x, lambda = c(1, 1, 1)/3, verb = TRUE)
Here is a reproducible example for the function normalmixEM:
data(faithful)
attach(faithful)
out <- normalmixEM(waiting, arbvar = FALSE, epsilon = 1e-03)
plot(out, which=2)
I would like to obtain this graphical output of density from the function gammamixEM.
Here you go.
out <- normalmixEM(waiting, arbvar = FALSE, epsilon = 1e-03)
x <- out
whichplots <- 2
density = 2 %in% whichplots
loglik = 1 %in% whichplots
def.par <- par(ask=(loglik + density > 1), "mar") # only ask and mar are changed
mix.object <- x
k <- ncol(mix.object$posterior)
x <- sort(mix.object$x)
a <- hist(x, plot = FALSE)
maxy <- max(max(a$density), .3989*mix.object$lambda/mix.object$sigma)
I just had to dig into the source code of plot.mixEM
So, now to do this with gammamixEM:
x <- c(rgamma(200, shape = 0.2, scale = 14), rgamma(200,
shape = 32, scale = 10), rgamma(200, shape = 5, scale = 6))
gammamixEM.out <- gammamixEM(x, lambda = c(1, 1, 1)/3, verb = TRUE)
mix.object <- gammamixEM.out
k <- ncol(mix.object$posterior)
x <- sort(mix.object$x)
a <- hist(x, plot = FALSE)
maxy <- max(max(a$density), .3989*mix.object$lambda/mix.object$sigma)
main2 <- "Density Curves"
xlab2 <- "Data"
col2 <- 2:(k+1)
hist(x, prob = TRUE, main = main2, xlab = xlab2,
ylim = c(0,maxy))
for (i in 1:k) {
lines(x, mix.object$lambda[i] *
dnorm(x,
sd = sd(x)))
}
I believe it should be pretty straight forward to continue this example a bit, if you want to add the labels, smooth lines, etc. Here's the source of the plot.mixEM function.

Resources