12

When combining ggplot2 objects using patchwork I would like to be able to have an option that I could easily set an option for all the plots to have the same x-axis and/or y-axis range.

reprex:

library(patchwork)
library(ggplot2)
library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union

p1 <- mtcars %>% 
  ggplot() + 
  geom_point(aes(mpg, disp)) + 
  ggtitle('Plot 1')

p2 <- mtcars %>% 
  filter(disp < 300) %>% 
  ggplot() + 
  geom_point(aes(mpg, disp)) + 
  ggtitle('Plot 2')

p1 + p2

Created on 2020-02-01 by the reprex package (v0.3.0)

expected result setting it to both axes having the same range across both plots:

library(patchwork)
library(ggplot2)
library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union

p1 <- mtcars %>% 
  ggplot() + 
  geom_point(aes(mpg, disp)) + 
  ggtitle('Plot 1')

p2 <- mtcars %>% 
  filter(disp < 300) %>% 
  ggplot() + 
  geom_point(aes(mpg, disp)) + 
  ggtitle('Plot 2') +
  xlim(ggplot_build(p1)$layout$panel_scales_x[[1]]$range$range) +
  ylim(ggplot_build(p1)$layout$panel_scales_y[[1]]$range$range)

p1 + p2

Created on 2020-02-01 by the reprex package (v0.3.0)

Does anyone have any ideas?

2
  • Can I ask what's wrong with what you're already doing? What would a solution look like? Would you want some function like f(p1 + p2) that set the axes equally? Commented Feb 1, 2020 at 11:57
  • yeah I was expecting to be able to have an option directly in the pkg to do that, since my real example is much more complex.. although, I have found the solution now, I will post the answer soon Commented Feb 1, 2020 at 15:32

2 Answers 2

21

Alright, I am sorry for answering my own question, but I just found the solution..

This can be nicely achieved by using the &, which applies the function to all the plots in the patchwork object.

1) reprex:

library(patchwork)
library(ggplot2)
library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union

p1 <- mtcars %>% 
  ggplot() + 
  geom_point(aes(mpg, disp)) + 
  ggtitle('Plot 1')

p2 <- mtcars %>% 
  filter(disp < 300) %>% 
  ggplot() + 
  geom_point(aes(mpg, disp)) + 
  ggtitle('Plot 2')

p_combined <- p1 + p2

p_combined

Created on 2020-02-01 by the reprex package (v0.3.0)

2) Get the min and max values from the ranges:

p_ranges_x <- c(ggplot_build(p_combined[[1]])$layout$panel_scales_x[[1]]$range$range,
  ggplot_build(p_combined[[2]])$layout$panel_scales_x[[1]]$range$range)

p_ranges_y <- c(ggplot_build(p_combined[[1]])$layout$panel_scales_y[[1]]$range$range,
                ggplot_build(p_combined[[2]])$layout$panel_scales_y[[1]]$range$range)

3) Apply these ranges to the patchwork object:

p_combined & 
  xlim(min(p_ranges_x), max(p_ranges_x)) & 
  ylim(min(p_ranges_y), max(p_ranges_y))

Created on 2020-02-01 by the reprex package (v0.3.0)

Sign up to request clarification or add additional context in comments.

1 Comment

How will it work when we have more than two plots?
5

Here is a slight modification make the above operation into a function:

apply_consistent_y_lims <- function(this_plot){
    num_plots <- length(this_plot$layers)
    y_lims <- lapply(1:num_plots, function(x) ggplot_build(this_plot[[x]])$layout$panel_scales_y[[1]]$range$range)
    min_y <- min(unlist(y_lims))
    max_y <- max(unlist(y_lims))
    this_plot & ylim(min_y, max_y)
}

4 Comments

Very nice solution, beware however: it cuts of data in the right plot, when it has data with higher y values than the left plot, to see this try apply_consistent_y_lims(p2+p1)
@MartineJ I'm not seeing that problem, function seems to work just fine for me, so far.
strange, for me it still ( in the mean while other RStudio, R and packages versions) removes 11 rows containing missing values (geom_point), when i run apply_consistent_y_lims(p2+p1).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.