Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

set axes limits in patchwork when combining ggplot2 objects

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?

like image 895
FMM Avatar asked Feb 01 '20 11:02

FMM


Video Answer


2 Answers

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)

like image 111
FMM Avatar answered Sep 28 '22 02:09

FMM


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)
}
like image 20
squidy Avatar answered Sep 28 '22 02:09

squidy