wilkelab / cowplot

cowplot: Streamlined Plot Theme and Plot Annotations for ggplot2
https://wilkelab.org/cowplot/
704 stars 84 forks source link

Extra padding in plot_grid(..., align="hv") #87

Closed fbreitwieser closed 6 years ago

fbreitwieser commented 6 years ago

Thanks for this great package!

I'm trying to create a scatter-plot with marginal densities. I'd like to have the density plots at the top and left border of the scatter plot without any space in-between the plots. However, there remains a gap when I use plot_grid(..., align="hv"); see plot 3. When I use plot_grid(..., align="h") or plot_grid(..., align="v"), the aligned plots are bordering each other as desired (plots 1 and 2).

Plot 1: plot_grid(..., align="h") works - no space between aligned plots at the bottom image

Plot 2: plot_grid(..., align="v") works - no space between aligned plots on the left image

Plot3: With plot_grid(..., align="hv") there's space between the plots image

Code:

DF = data.frame(y=rnorm(100),x=c(rnorm(50),rnorm(50)+2), group=rep(c("A","B"),each=50))
g <- ggplot(DF, aes(col=group, fill=group))
scatter_plot <-  g + geom_point(aes(x=x, y=y)) + theme(legend.position="none")  + theme(plot.margin=unit(c(0,0,1,1),"points"))

density_plot_f <- function(g, x) 
  g + geom_density(aes_string(x), alpha=.5) +
  cowplot::theme_nothing()  + labs(x = NULL, y = NULL) +
  scale_x_continuous(expand=c(0,0)) +
  scale_y_continuous(expand=c(0,0)) 

plotlist <- list(density_plot_f(g, "x"), ggplot(), scatter_plot, density_plot_f(g, "y") + coord_flip())

cowplot::plot_grid(plotlist = plotlist, align="h", axis="b", rel_widths=c(3,1), rel_heights = c(1,3))
cowplot::plot_grid(plotlist = plotlist, align="v", axis="b", rel_widths=c(3,1), rel_heights = c(1,3))
cowplot::plot_grid(plotlist = plotlist, align="hv", axis="b", rel_widths=c(2,1), rel_heights = c(1,2))

Thanks! Florian

clauswilke commented 6 years ago

Please take a look at the examples for the axis_canvas() function.

fbreitwieser commented 6 years ago

That looks great, thanks for the lead!

Marc-Ruebsam commented 2 years ago

Could you explains the origin of this behavior, or whether it is intended. And maybe give a generalized solution to the problem, e.g. in case axis labels are desired for the density plots. Example:

pDENSITY <-
  ggplot() +
  theme_bw() +
  geom_density( data = mtcars, aes( x = mpg, fill = factor(cyl) ), alpha = 0.6, size=.2 ) +
  theme( axis.title.x = element_blank(), axis.text.x = element_blank(), plot.margin = unit(c(5.5,5.5,1,5.5), "pt") ) +
  guides( fill = "none" )
pMAIN <-
  ggplot() +
  theme_bw() +
  geom_boxplot( data = mtcars, aes( x = mpg, y = factor(paste0(cyl," cylinders")), fill = factor(paste0(cyl," cylinders")) ) ) +
  theme(
    axis.title.y = element_blank(),
    axis.text.x = element_text( angle = 90, size = 14, vjust = 0.5 ) ) +
  guides( fill = "none" )
pBAR <-
  ggplot() +
  theme_bw() +
  geom_bar( data = mtcars, aes( y = factor(cyl), fill = factor(cyl), linetype = factor(gear) ), color = "black" ) +
  theme( axis.title.y = element_blank(), axis.text.y = element_blank(), plot.margin = unit(c(5.5,5.5,5.5,1), "pt") )
plot_grid(
  pDENSITY,
  NULL,
  pMAIN,
  pBAR,
  ncol = 2,
  nrow = 2,
  rel_heights = c(1,3),
  rel_widths = c(2,1),
  align = 'hv',
  axis = 'lbrt' )

image ... has to much padding.

ggdraw(
  insert_yaxis_grob(
    insert_xaxis_grob(
      pMAIN,
      pDENSITY,
      grid::unit(.2, "null"),
      position = "top" ),
    pBAR,
    grid::unit(.2, "null"),
    position = "right" ) )

image ... is missing axes (and legend).

EDIT: Looking at the results with the help of the egg::expose_layout made me realize that the plots get arranged in this way to leave the same margin around all central panels. Hence, the correct question would be whether it is possible to only align horizontally-column- and vertically-row-wise!?

plot_grid(
  expose_layout( pDENSITY, draw = FALSE, newpage = FALSE ),
  expose_layout( ggplot(), draw = FALSE, newpage = FALSE ),
  expose_layout( pMAIN, draw = FALSE, newpage = FALSE ),
  expose_layout( pBAR, draw = FALSE, newpage = FALSE ),
  ncol = 2,
  nrow = 2,
  rel_heights = c(1,1),
  rel_widths = c(1,1),
  align = 'hv',
  axis = 'lbrt' )

image

clauswilke commented 2 years ago

Honestly, you're probably better off using patchwork for these kinds of arrangements. The following gets pretty close to what you want (I think).

library(tidyverse)
library(patchwork)

pDENSITY <-
  ggplot() +
  theme_bw() +
  geom_density( data = mtcars, aes( x = mpg, fill = factor(cyl) ), alpha = 0.6, size=.2 ) +
  theme( axis.title.x = element_blank(), axis.text.x = element_blank(), plot.margin = unit(c(5.5,5.5,0,5.5), "pt") ) +
  guides( fill = "none" )
pMAIN <-
  ggplot() +
  theme_bw() +
  geom_boxplot( data = mtcars, aes( x = mpg, y = factor(paste0(cyl," cylinders")), fill = factor(paste0(cyl," cylinders")) ) ) +
  theme( axis.title.y = element_blank() ) +
  guides( fill = "none" )
pBAR <-
  ggplot() +
  theme_bw() +
  geom_bar( data = mtcars, aes( y = factor(cyl), fill = factor(cyl), linetype = factor(gear) ), color = "black" ) +
  theme( axis.title.y = element_blank(), axis.text.y = element_blank(), plot.margin = unit(c(5.5,5.5,5.5,0), "pt") )

pDENSITY + plot_spacer() + pMAIN + pBAR + plot_layout(ncol = 2, heights = c(1, 3), widths = c(2, 1))

Created on 2022-06-23 by the reprex package (v2.0.1)

When I wrote cowplot patchwork wasn't around, but now that it exists there's no reason not to use it.

Marc-Ruebsam commented 2 years ago

Thank you very much for the reply! I will have a look at patchwork. The solution looks pretty nice. I played around with egg now and was also able to get a result:

egg::ggarrange(
  plots = list( pDENSITY, ggplot() + theme_void(), pMAIN, pBAR ),
  ncol = 2, nrow = 2, widths = c(2, 1), heights = c(1, 3) )

image The only difference I can spot is the x-axis label at the density plot (before looking into whether this can be adapted).

clauswilke commented 2 years ago

Yes, patchwork will align all the axis labels, and that may not be what you want. It can cause some labels to float in space, as we see in my example.