rggplot2cowplot

ggplot cowplot ensuring y axes are identical when arranging plots with log scale


I want to create a combination plot using plot_grid from the cowplot package. The two plots that I want to combine use a log scale. Of the data plotted, some is negative, which gets dropped.

I can quite easily produce a decent result using facet_wrap that looks like this:

library(tidyverse)
tibble(x = rnorm(100), 
       y = rnorm(100),
       type = "A") %>% 
  bind_rows(tibble(x = rnorm(100, mean = 10), 
                   y = rnorm(100, mean = 10),
                   type = "B")) %>% 
  
  ggplot(aes(y = y, x = x)) + 
  geom_point() + 
  facet_wrap(~type)

enter image description here

But in my particular situation, I can't use facet_wrap because I want to give the panels A and B different x-axis labels and want to change the number format slightly (e.g. adding a $ sign to the axis ticks of panel A and a % sign to panel B).

Therefore I use plot_grid:

tibble(x = rnorm(100), 
       y = rnorm(100),
       type = "A") %>% 
  ggplot(aes(y = y, x = x)) + 
  geom_point() + 
  scale_y_log10() -> a



tibble(x = rnorm(100, mean = 10), 
       y = rnorm(100, mean = 10),
       type = "B") %>% 
  ggplot(aes(y = y, x = x)) + 
  geom_point() + 
  scale_y_log10() -> b

cowplot::plot_grid(a,b)

enter image description here

Now the problem is that the axis is completely distorted (this would be equal to scales = "free_y" in facet_wrap)

So therefore I attempt to set the limits/ranges for both plots manually by choosing the min and max from both plots:

lims <- c(min(layer_scales(a)$y$range$range, layer_scales(b)$y$range$range),
          max(layer_scales(a)$y$range$range, layer_scales(b)$y$range$range))


cowplot::plot_grid(a + ylim(lims),b + ylim(lims))

But now the result is this:

enter image description here

So essentially I want to replicate the scales="fixed" in facet_wrap using plot_grid Any ideas?

many thanks!


Solution

  • The issue is that you provide y axis limits in log10 scale as returned by layer_scales. You need to convert it to actual values.

    lims = 10^c(min(layer_scales(a)$y$range$range, layer_scales(b)$y$range$range),
                max(layer_scales(a)$y$range$range, layer_scales(b)$y$range$range))
    

    Alternatively, you can compute the range of the actual data.