I'm looking to use the cowplot package to give two ggplots a shared legend. However, how can I center the shared legend when there's an even number of plots.
Here's some example code:
library(ggplot2)
library(cowplot)
library(rlang)
# down-sampled diamonds data set
dsamp <- diamonds[sample(nrow(diamonds), 1000), ]
# function to create plots
plot_diamonds <- function(xaes) {
xaes <- enquo(xaes)
ggplot(dsamp, aes(!!xaes, price, color = clarity)) +
geom_point() +
theme_half_open(12) +
# we set the left and right margins to 0 to remove
# unnecessary spacing in the final plot arrangement.
theme(plot.margin = margin(6, 0, 6, 0))
}
# make two plots
p1 <- plot_diamonds(carat)
p2 <- plot_diamonds(depth) + ylab(NULL)
# arrange the three plots in a single row
prow <- plot_grid(
p1 + theme(legend.position="none"),
p2 + theme(legend.position="none"),
align = 'vh',
labels = c("A", "B"),
hjust = -1,
nrow = 1
)
prow
# extract a legend that is laid out horizontally
legend_b <- get_legend(
p1 +
guides(color = guide_legend(nrow = 1)) +
theme(legend.position = "bottom")
)
# add the legend underneath the row we made earlier. Give it 10%
# of the height of one plot (via rel_heights).
plot_grid(prow, legend_b, ncol = 1, rel_heights = c(1, .1))
Which produces this image:
As you can see, cow_plot puts the the legend is located underneath the left image. Is there a way to make this shared legend centered between the two images?
Change the theme like below;
legend_b <- get_legend( p1 +
guides(color = guide_legend(nrow = 1)) +
theme(legend.direction = "horizontal",
legend.justification="center",
legend.box.just = "bottom")
)
Related
I am using cowplot to arrange two plots with a common legend below. The approach works, yet the legend has whitespace around I would like to get rid of.
Note: I am ware of the ggpubr::ggarange common.legend option I though want to stick to cowplot::plot_grid (which masks ggpubr::get_legend)
library(tidyverse)
library(ggpubr)
library(cowplot)
theme_set(theme_cowplot())
p1 <- iris %>%
ggplot(aes(x=Sepal.Width,y=Petal.Width,color=Species)) +
geom_point() + coord_fixed()
p2 <- iris %>%
ggplot(aes(x=Sepal.Width,y=Petal.Width,color=Species)) +
geom_point() + coord_fixed()
compound_plot <- plot_grid(p1 + theme(legend.position="none"),
p2 + theme(legend.position="none"),
ncol = 2,
labels = c("A","B"))
legend <- get_legend(p1 +
theme(legend.direction = "horizontal",
legend.justification="center" ,
legend.box.just = "bottom"))
plot_grid(compound_plot,
legend,
ncol = 1)
Thanks in advance!
You can set rel_heights inside plot_grid
plot_grid(compound_plot,
legend,
ncol = 1, rel_heights = c(0.95, 0.05))
I have 16 plots that I want to arrange together for illustration purposes. Below I show one graph as an example.
The code for creating each plot is next:
P1<- ggplot(Fish_acc_C.D.Mean_bottom_invierno_P16, aes(C.D.Mean_bottom,meanAcc)) +
geom_point(aes(C.D.Mean_bottom,meanAcc, color = C.I.Mean_bottom),show.legend = FALSE) +
scale_colour_gradientn(colours=c("green","black")) +
theme_bw() +
geom_smooth(aes(linetype = "Activity"),fill = "lightblue",color="red", alpha = 0.99) +
ggtitle("Activity ~ Curr Direct Mean bottom WINTER (Hourly data)") +
theme(plot.title = element_text(size=10,hjust = 0.5)) +
geom_smooth(aes(C.D.Mean_bottom, C.I.Mean_bottom * max(range(Fish_acc_C.D.Mean_bottom_invierno_P16$C.I.Mean_bottom)), linetype = "C.I.M.B"), se=FALSE, colour = "blue",show.legend = FALSE) +
scale_y_continuous(sec.axis = sec_axis(trans = ~ . /max(range(Fish_acc_C.D.Mean_bottom_invierno_P16$C.I.Mean_bottom)), name = "C.I.Mean bottom")) +
scale_linetype_manual(values = c(1,1),guide = guide_legend(override.aes = list(colour = c("red", "blue")))) +
coord_cartesian(ylim = c(0, 1.25)) +
theme(legend.justification = c(1,1),
legend.position = c(1,1))
My problem is that when I use grid.arrange() to group them all together, the legends of each plot increase their size with regard to their size in the individual ones. Here an example:
Here I show the code for creating the grid_arrange:
grid.arrange(P1,P2,P3,P4,P5,P6,P7,P8,P9,P10,P11,P12,P13,P14,P15,P16,ncol=4)
Does anyone know how to reduce the size of the legends in the grid_arranged graph in order to see the lines? I thought that maybe I could place the legends in the upper-middle position of the graph, delete the word "linetype" from the legend and display the linetypes in one line (side by side instead of up and down). However I don't know how to do it.
Does anyone have any recommendation?
You can look at the ggarrange function from the ggpubr package.
It allows you to group your plots as you need and have a common legend for all of them, for which you can specify the position.
e.g.
library(ggpubr)
ggarrange(g1, g2, ncol = 2, common.legend = T, legend = 'bottom')
# or
ggarrange(plotlist = my_list, ncol = 2, common.legend = T, legend = 'bottom')
#Dekike then you can extract the legend and put the legend on top/bottom of the main plot.
Here are my psude code
library(ggplot2)
library(cowplot)
P1 <- ggplot() + ... + guides(lineType=guide_legend(ncol=2))
legend_extracted <- get_legend(P1)
P1 <- P1 + theme(legend.position="none")
P2 <- ggplot() + ... + theme(legend.position="none")
...
P16 <- ggplot() + ... + theme(legend.position="none")
main_plot <- grid.arrange(P1,P2,P3,P4,P5,P6,P7,P8,P9,P10,P11,P12,P13,P14,P15,P16,ncol=4)
main_plot_wLegend <- grid.arrange(legend_extracted, main_plot, ncol=1, nrow=2)
Please try and feedback on this!
Say I have three SQUARE plots p1 p2 p3 made from the ggplot2 package. I applied ggarrange command under ggpubr package to make a 1*3 plot after that. Here are the commands:
library(ggplot2)
library(ggpubr)
library(gridExtra)
data <- data.frame(matrix(seq(1, 30, 1), 2))
for(i in 1:5){
plot1 <- ggplot(data = data, aes(y = data[, (i*3-2)])) +
theme(aspect.ratio = 1)
plot2 <- ggplot(data = data, aes(y = data[, (i*3-1)])) +
theme(aspect.ratio = 1)
plot3 <- ggplot(data = data, aes(y = data[, (i*3)])) +
theme(aspect.ratio = 1)
p <- ggarrange(plot1, plot2, plot3,
ncol = 3, common.legend = TRUE, legend = "bottom")
grid.arrange(p, top = paste(colnames(data)[i]), heights = c(1, 1))
}
The rmarkdown output (below) shows a large white space below the arranged plots:
Is there any way to remove it? What I thought is to change the default size of canvas..
I have three plots p1, p2 and p3.
I would like to combine p2 and p3 and add the legends of p2 and p1 on the right side above each other. In the following example the legends are identical. In the real data they are differend.
I use ggplot2 and cowplot
# plot 1
p1 <- ggplot(iris, aes(Sepal.Length, fill = Species)) +
geom_density(alpha = .7)
# plot 2
p2 <- ggplot(iris, aes(Sepal.Width, fill = Species)) +
geom_density(alpha = .7)
# plot 3
p3 <- ggplot(iris, aes(Petal.Width, fill = Species)) +
geom_density(alpha = .7)
# legend1
legend1 <- get_legend(p1)
# legend2
legend2 <- get_legend(p2)
# combine plots
prow <- plot_grid( p2 + theme(legend.position="none"),
p3 + theme(legend.position="none"),
align = 'vh',
labels = c("a", "b"),
hjust = -1,
nrow = 1,
axis="1"
)
prow
# add legend1
p <- plot_grid( prow, legend1, rel_widths = c(1, .3))
p
# add legend2
plot_grid(p, legend2, rel_widths =c(1, .3))
This gives me this:
What I try to get is:
I tried to solve the problem using
+ theme(legend.position=c()
and
+ theme(legend.justification = "top"))
however, I could not get the desired plot.
You're actually very close. You can use ggdraw to achieve what you want. See ?get_legend for another example of this.
# combine plots
prow <- ggdraw(
plot_grid(
plot_grid(p2 + theme(legend.position="none") ,
p3 +theme(legend.position="none"),
align = 'vh',
labels = c("a", "b"),
hjust = -1,
nrow = 1,
axis="1"),
# as suggested by aosmith you can add additional columns to make legends appear closer
plot_grid(legend1, legend2,ncol=4),
# I also set the relative widths so the legend takes up less space
nrow=1, rel_widths = c(1,0.2))
)
prow
I would like to combine some graphs together using cowplot. But I cannot change the margin sizes. I want to use only one y-axes, but than the margin is still quite large, which I want to decrease. I have used the plot.margin code from ggplot, although that works when I look at the single plot, it doesn't seem to work when the plots are combined.
I have made some example code:
library(ggplot2)
library(cowplot)
x <- c("a", "b")
y1 <- c(3,6)
y2 <- c(10,15)
data1 <- data.frame(x,y1)
data2 <- data.frame(x, y2)
ylab1 <- ylab("Very nice y values")
xlab1 <- xlab("Very nice factors")
plot1 <- ggplot(data1, aes(x=x, y = y1)) +
geom_bar(stat ="identity", position=position_dodge(), fill = "grey")+
theme(plot.margin = unit(c(0.5,0.5,0.5,0.5), "cm")) + xlab1 + ylab1
plot1
ylab2 <- ylab("")
xlab2 <- xlab("Very nice factors")
plot2 <- ggplot(data2, aes(x=x, y = y2)) +
geom_bar(stat = "identity",position=position_dodge(), fill = "grey")+
theme(plot.margin = unit(c(0.5,0.5,0.5,-0.5), "cm")) + xlab2 + ylab2
plot2
plot3 <- plot_grid(plot1, plot2, labels = c("A", "B"), align = "hv",nrow = 1, ncol = 2)
plot3 # Quite large margin between the two plots
I am aware that I could avoid this problem by using facets, however my real plot is rather more complicated than this graph.
Increasing the space between plots in plot_grid was also addressed in this issue.
An extra interesting solution is the one suggested in this comment - try to add an extra empty plot between the two plots and adjust the relative columns widths:
plot4 <- plot_grid(plot1, NULL, plot2, rel_widths = c(1, 0, 1), align = "hv",
labels = c("A", "B"), nrow = 1)
plot4
Can even try negative values in rel_widths, which gives better results:
plot5 <- plot_grid(plot1, NULL, plot2, rel_widths = c(1, -0.1, 1), align = "hv",
labels = c("A", "B"), nrow = 1)
plot5
So, try a combination of adjusting the plot.margin (as answered by #J.Con) and adding an extra empty plot with tweaking rel_widths.
EDIT 2019-12-11
Also check out this comment of the author of cowplot (Claus Wilke):
For those kinds of problems I would now recommend the patchwork library. It's inherently difficult with plot_grid(), due to its underlying design
So, a fast example with patchwork based on their vignette Adding Annotation and Style goes like this:
library(patchwork)
plot3 <- plot1 + plot2 +
plot_annotation(tag_levels = 'A') &
theme(plot.tag = element_text(size = 8))
plot3
Created on 2019-12-11 by the reprex package (v0.3.0)
Your plot.margins were actually working against you. Set them to zero to fill up that white space.
plot1 <- ggplot(data1, aes(x=x, y = y1)) +
geom_bar(stat ="identity", position=position_dodge(), fill = "grey")+
theme(plot.margin = unit(c(0,0,0,0), "cm")) + xlab1 + ylab1
plot1
ylab2 <- ylab("")
xlab2 <- xlab("Very nice factors")
plot2 <- ggplot(data2, aes(x=x, y = y2)) +
geom_bar(stat = "identity",position=position_dodge(), fill = "grey")+
theme(plot.margin = unit(c(0,0,0,0), "cm")) + xlab2 + ylab2
plot2
plot3 <- plot_grid(plot1, plot2, labels = c("A", "B"), align = "hv",nrow = 1, ncol = 2)
plot3