How to combine legends from different ggplot after extracting via get_legend - r

(EDIT: Removed original code and added reproducible example.)
I have two ggplot2 geom_tile plots.
Both have a legend.
The first one has one gradient scale.
The second one has two gradient scales.
Now I extract the legends from both plots via cowplot::get_legend(). The aim is to merge them to one legend and add it to the right of the composed final plot.
Then I try to combine them via: cowplot::plot_grid(legend1, legend2, ncol = 1, align = "v").
The problem is, that there is a large (EDIT: actually scaling) space between legend1 and legend2 (see figure below). I tried to remove margins of the legends via theme() when generating the initial geom_tile ggplots, but was not successful.
This there a way to completely "unwrap" the extracted legends and then stack them vertically afterwards into one ggplot figure?
Minimal example to showcase my problem:
m <- matrix(round(rnorm(200), 2), 10, 10)
colnames(m) <- paste("Col", 1:10)
rownames(m) <- paste("Row", 1:10)
df <- melt(m)
colnames(df) <- c("x", "y", "value")
df2 <- df
colnames(df2) <- c("x", "y", "value2")
library(ggnewscale)
ggplot1 <- ggplot(df, aes(x = x, y = y, fill = value)) +
geom_tile()
legend1 <- cowplot::get_legend(ggplot1)
ggplot2 <- ggplot() +
geom_tile(data = df2, aes(x = x, y = y, fill = value2)) +
ggnewscale::new_scale_fill() +
geom_tile(data = df, aes(x = x, y = y, fill = value))
legend2 <- cowplot::get_legend(ggplot2)
library(cowplot)
cowplot::plot_grid(legend1, legend2, ncol = 1, align = "v")
And here the result. The gap between the first scale and the second is too large -- what I learned just now, it that this large gap is being scaled according to the total size. So it seems to not be fixed:

When it comes to arranging plots it's always worthwhile to consider patchwork as an option. In your case you could use guides="collect" to arrange the legends without the need of extracting them first. However, at least for your example data one minor hack is necessary to show all legends, i.e. we have to add a space to the name of one of the value legends to prevent that they get merged.
library(ggplot2)
library(ggnewscale)
p1 <- ggplot(df, aes(x = x, y = y, fill = value)) +
geom_tile()
p2 <- ggplot() +
geom_tile(data = df2, aes(x = x, y = y, fill = value2)) +
ggnewscale::new_scale_fill() +
geom_tile(data = df, aes(x = x, y = y, fill = value)) +
scale_fill_continuous(name = "value ")
library(patchwork)
p1 / p2 + plot_layout(ncol = 1, guides = "collect")
DATA
set.seed(123)
m <- matrix(round(rnorm(100), 2), 10, 10)
colnames(m) <- paste("Col", 1:10)
rownames(m) <- paste("Row", 1:10)
df <- reshape2::melt(m)
colnames(df) <- c("x", "y", "value")
df2 <- df
colnames(df2) <- c("x", "y", "value2")

Related

How to more effectively plot points in ggplot2 by groups if they overlap?

So, I would like to plot points using ggplot separated by groups, but because they overlap the colour by group function doesn't seem so effective visually, I already set the alpha to 0.3. What else could I do?
I am assuming that you have something like the following:
df <- data.frame(x = c((1:10)-0.05, 1:10, 1:10), y = c(1:10, 1:20), group = paste('Group', 1:10))
df$group <- factor(df$group, levels = unique(df$group))
ggplot(df, aes(x, y, colour = group), alpha=0.3)+
geom_point()
So, as suggested by #Duck you can plot the points in separate plots using facet_wrap as in the following:
df <- data.frame(x = c((1:10)-0.05, 1:10, 1:10), y = c(1:10, 1:20), group = paste('Group', 1:10))
df$group <- factor(df$group, levels = unique(df$group))
ggplot(df, aes(x, y))+
geom_point()+
facet_wrap(~group)

How to add gaps using geom_tile in R?

I plot a heatmap using geom_tile (ggplot2):
library("reshape2")
library("ggplot2")
x <- matrix(1:12, nrow=3)
rownames(x) <- LETTERS[1:3]
colnames(x) <- letters[1:4]
x_melted <- melt(x)
x_melted$group1 <- rep(c("T1","T2"), each=6)
ggplot(x_melted, aes(x = Var1, y = Var2)) + geom_tile(aes(fill = value))
But I need add a gap according to group1 in x_melted so that a gap was produced between the first two rows and the last two rows. How could this be added?
One way would be to use facets -
x_melted$group1 = factor(x_melted$group1, levels = c("T2", "T1"))
ggplot(x_melted, aes(x = Var1, y = Var2)) +
geom_tile(aes(fill = value)) +
facet_grid(group1 ~ ., scales = "free_y")

How to support loop drawing in ggplot2?

data <- data.frame(a=1:10, b=1:10 * 2, c=1:10 * 3)
library(ggplot2)
p <- ggplot(NULL, aes(x = 1:10))
# Using for loop will cause the plot only to draw the last line.
for (i in names(data)){
p <- p + geom_line(aes(y = data[[i]], colour = i))
}
# Lines below works fine.
# p <- p + geom_line(aes(y = data[["a"]], colour = "a"))
# p <- p + geom_line(aes(y = data[["b"]], colour = "b"))
# p <- p + geom_line(aes(y = data[["c"]], colour = "c"))
print(p)
Why loop plotting doesn't work as what we expected?
Is this a lazy plotting method?
You don't actually have to loop to get your lines. You just need to reshape your data and actually include x in your data frame. Your data is wide, and ggplot2 likes long data. This is how you can easily make multiple lines in a single plot.
As an aside, your method doesn't work as you are replacing p each time you iterate, ending up with only the endpoint of the loop.
library(ggplot2)
library(tidyr)
data <- data.frame(x = 1:10, a=1:10, b=1:10 * 2, c=1:10 * 3)
df <- gather(data, name, value, -x)
ggplot(df, aes(x = x, y = value, color = name)) +
geom_line()

Facetting in ggplot2

I have this dataset: https://dl.dropboxusercontent.com/u/73950/data.csv
The dataset contains 3 variables.
Here's how I visualize the data right now:
library(ggplot2)
library(reshape2)
library(RColorBrewer)
dat = read.csv("data.csv", header = FALSE)
myPalette <- colorRampPalette(rev(brewer.pal(11, "Spectral")))
sc <- scale_colour_gradientn(colours = myPalette(100))
ggplot(dat, aes(x=V1, y=V3, colour = V2))+ geom_point(alpha = .2,size = 3) + sc
Instead of just one figure, I'd like to facet the figure to display 3 different ways to attribute variables to each axis and color. As such:
x = V1, y = V2, color = V3
x = V1, y = V3, color = V2
x = V2, y = V3, color = V1
How to do this kind of things with ggplot2's faceting?
You can get this by putting the data in the format ggplot likes. In this case, a column that can be used to split the data into facets (called var below). To do that, I just repeated the data three times, choosing the appropriate x and y variables for each 2-way combo, and using the variable left out of each combination as the coloring variable.
## Rearrange the data by 2-way combinations, the coloring is the remaining column
res <- do.call(rbind, combn(1:3, 2, function(ii)
cbind(setNames(dat[,c(ii, setdiff(1:3, ii))], c("x", "y", "color")),
var=paste(ii, collapse=".")), simplify=F))
ggplot(res, aes(x=x, y=y, color=color))+ geom_point(alpha = .2,size = 3) +
facet_wrap(~ var, scales="free") + sc

Align x axes of box plot and line plot using ggplot

Im trying to align the x-axes of a bar plot and line plot in one window frame using ggplot. Here is the fake data I'm trying to do it with.
library(ggplot2)
library(gridExtra)
m <- as.data.frame(matrix(0, ncol = 2, nrow = 27))
colnames(m) <- c("x", "y")
for( i in 1:nrow(m))
{
m$x[i] <- i
m$y[i] <- ((i*2) + 3)
}
My_plot <- (ggplot(data = m, aes(x = x, y = y)) + theme_bw())
Line_plot <- My_plot + geom_line()
Bar_plot <- My_plot + geom_bar(stat = "identity")
grid.arrange(Line_plot, Bar_plot)
Thank you for your help.
#eipi10 answers this particular case, but in general you also need to equalize the plot widths. If, for example, the y labels on one of the plots take up more space than on the other, even if you use the same axis on each plot, they will not line up when passed to grid.arrange:
axis <- scale_x_continuous(limits=range(m$x))
Line_plot <- ggplot(data = m, aes(x = x, y = y)) + theme_bw() + axis + geom_line()
m2 <- within(m, y <- y * 1e7)
Bar_plot <- ggplot(data = m2, aes(x = x, y = y)) + theme_bw() + axis + geom_bar(stat = "identity")
grid.arrange(Line_plot, Bar_plot)
In this case, you have to equalize the plot widths:
Line_plot <- ggplot_gtable(ggplot_build(Line_plot))
Bar_plot <- ggplot_gtable(ggplot_build(Bar_plot))
Bar_plot$widths <-Line_plot$widths
grid.arrange(Line_plot, Bar_plot)
The gridlines on the x axes will be aligned if you use scale_x_continuous to force ggplot to use limits you specify.
My_plot <- ggplot(data = m, aes(x = x, y = y)) + theme_bw() +
scale_x_continuous(limits=range(m$x))
Now, when you add the layers, the axes will share the common scaling.

Resources