当合并ggplot2对象时,在patchwork中设置轴限制

11
ggplot2对象使用patchwork组合时,我希望有一个选项可以轻松设置所有图的x轴和/或y轴范围相同。 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

使用reprex包 (v0.3.0),2020-02-01创建

期望结果是将两张图的坐标轴设置为相同范围:

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

reprex package (v0.3.0)于2020-02-01创建

有人有什么想法吗?


我可以问一下你现在做的有什么问题吗?解决方案会是什么样子?你是否想要一些像 f(p1 + p2) 这样的函数来设置坐标轴相等? - Allan Cameron
是的,我本来期望能够在 pkg 中直接有一个选项来实现这个,因为我的真实例子要复杂得多。不过,我现在已经找到了解决方案,很快就会发布答案。 - FMM
2个回答

17

好的,很抱歉我在回答自己的问题,但我刚刚找到了解决方法。

可以通过使用&来实现这一点,它会将函数应用于 patchwork 对象中的所有图形。

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

reprex package (v0.3.0) 创建于2020-02-01

2) 从范围中获取最小值和最大值:

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) 将这些范围应用于拼布对象:

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

创建于2020年2月1日,使用reprex软件包(v0.3.0)


5

这里有一点修改,将上述操作转化为一个函数:

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)
}

非常好的解决方案,但要注意:当右图中有比左图更高的y值数据时,它会截断右图中的数据。要查看此内容,请尝试应用apply_consistent_y_lims(p2+p1)。 - MartineJ
请参见 https://dev59.com/nmsz5IYBdhLWcg3wuKQm。 - MartineJ
@MartineJ 我没有看到那个问题,这个函数在我这里看起来运行得很好,目前为止。 - Ian
对我来说,这还是很奇怪的(同时其他RStudio、R和包版本),当我运行apply_consistent_y_lims(p2+p1)时,它仍然会删除包含缺失值的11行(geom_point)。 - MartineJ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接