wilkelab / cowplot

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

Automatically define rel_widths or rel_heights when plots use fixed aspect ratio #153

Open ikashnitsky opened 4 years ago

ikashnitsky commented 4 years ago

A follow up on this SO question two years later, maybe a feature request if you agree on its usefulness.

Sometimes plots require fixed aspect ratio, e.g. ternary plots when the coordinate space triangle has to be regular. It would be very useful if cowplot::plot_grid can define rel_widths or rel_height automatically in order to scale and align the plots. Consider the example below:

library(tidyverse)
library(ggtern)
#> Registered S3 methods overwritten by 'ggtern':
#>   method           from   
#>   +.gg             ggplot2
#>   grid.draw.ggplot ggplot2
#>   plot.ggplot      ggplot2
#>   print.ggplot     ggplot2
#> --
#> Remember to cite, run citation(package = 'ggtern') for further info.
#> --
#> 
#> Attaching package: 'ggtern'
#> The following objects are masked from 'package:ggplot2':
#> 
#>     %+%, aes, annotate, calc_element, ggplot, ggplot_build,
#>     ggplot_gtable, ggplotGrob, ggsave, layer_data, theme,
#>     theme_bw, theme_classic, theme_dark, theme_gray, theme_light,
#>     theme_linedraw, theme_minimal, theme_void
library(cowplot)
#> 
#> ********************************************************
#> Note: As of version 1.0.0, cowplot does not change the
#>   default ggplot2 theme anymore. To recover the previous
#>   behavior, execute:
#>   theme_set(theme_cowplot())
#> ********************************************************

set.seed(911)

df <- crossing(id = LETTERS[1:4],
               obs = 1:10) %>%
    mutate(x = runif(40),
           y = runif(40),
           z = runif(40)) %>%
    pivot_longer(x:z) %>%
    group_by(id, obs) %>% 
    mutate(value = value %>% prop.table) %>% 
    pivot_wider()

simple <- df %>% 
    ggtern(aes(x, y, z = z, color = id)) +
    geom_path(size = 1)+
    theme_bluedark()

faceted <- simple + facet_wrap(~id, ncol = 2)

plot_grid(simple, faceted, align = 'h', axis = 'tb')


plot_grid(simple, faceted, ncol = 1, align = 'v', axis = 'tb')

Created on 2019-12-21 by the reprex package (v0.3.0)

clauswilke commented 4 years ago

This would be nearly impossible to add to the plot_grid() function, for various technical reasons. Have you checked whether this works as expected with the patchwork package?

ikashnitsky commented 4 years ago

Yes, I expected that this might be very difficult. {patchwork} doesn’t work in this particular case – {ggtern} redefines most of the {ggplot2} functions including %+%. I wonder if it can be largely improved to work seamlessly with {ggplot2} and its extensions. Perhaps, something alike what {sf} does defining new coordinates. But that's clearly another story.

{patchwork} works with simple plots

library(tidyverse)
library(patchwork)

a <- mtcars %>% 
    mutate(cyl = cyl %>% factor) %>% 
    ggplot(aes(hp, wt, color = cyl, group = cyl))+
    geom_point()+
    stat_ellipse()+
    theme(aspect.ratio = 1)

b <- a + facet_wrap(~cyl, ncol = 2) 

a + b
#> Warning in as.numeric(w)/as.numeric(h): longer object length is not a
#> multiple of shorter object length
#> Warning in xList[i] <- valueList: number of items to replace is not a
#> multiple of replacement length


a + b + plot_layout(guides = "collect")
#> Warning in as.numeric(w)/as.numeric(h): longer object length is not a
#> multiple of shorter object length

#> Warning in as.numeric(w)/as.numeric(h): number of items to replace is not a
#> multiple of replacement length

Created on 2019-12-22 by the reprex package (v0.3.0)