在 for 循环中忽略 par 时如何绘制多个图形

5
我正在尝试生成10对图表,每页有几对图表,并使用for循环构建这些图表。但是,这些图表被单独发送到设备上,而不是作为页面一起呈现。
下面的MWE具有基本图形和ggplot版本相同的结构,但基本图形可以正常分页,而ggplot无法。我需要做什么才能在第二个版本中正确分页?
library(ggplot2)
attach(mtcars)

# correct configuration
par(mfrow=c(2,2))
for (ii in 1:3){
  vars <- c("wt", "disp", "wt")
  plot(get(vars[ii]), mpg)
  hist(get(vars[ii]))
}

# places each on separate plot
par(mfrow=c(2,2))
for (ii in 1:3){
  vars <- c("wt", "disp", "wt")
  p <- ggplot(mtcars, aes(get(vars[ii]), mpg)) + geom_point(size=4)
  plot(p)
  p <- ggplot(mtcars, aes(get(vars[ii]))) + geom_histogram()
  plot(p)
}

detach(mtcars)

6
par 命令只能用于 base R 图形,无法用于 ggplot 图形。您是否想要对图形进行分面显示(facet)处理? - camille
1
一个潜在的替代方案是 gridExtra::grid.arrange,例如请参考这篇文章 - Maurits Evers
很好知道 par 不可用。这不是 facet 的问题 - 画的是不同的图。我需要看看是否可以使 gridExtra::grid.arrangecowplot::plot_grid 足够灵活,以处理不命名个别绘图的情况。 - JenB
你可以尝试将绘图存储在列表中,以便使用你提到的包/函数进行处理。 - aosmith
1个回答

4

以下是使用 cowplot::plot_grid 的一种方法。在 ggplot2 v3.0.0 中,plot_duo 函数使用了 tidyeval 方法。

# install.packages("ggplot2", dependencies = TRUE)

library(rlang)
library(dplyr)
library(ggplot2)
library(cowplot)

plot_duo <- function(df, plot_var_x, plot_var_y) {

  if (is.character(plot_var_x)) {
    print('character column names supplied, use ensym()')
    plot_var_x <- ensym(plot_var_x)
  } else {
    print('bare column names supplied, use enquo()')
    plot_var_x <- enquo(plot_var_x)
  }

  if (is.character(plot_var_y)) {
    plot_var_y <- ensym(plot_var_y)
  } else {
    plot_var_y <- enquo(plot_var_y)
  }

  pts_plt <- ggplot(df, aes(x = !! plot_var_x, y = !! plot_var_y)) + geom_point(size = 4)
  his_plt <- ggplot(df, aes(x = !! plot_var_x)) + geom_histogram()

  duo_plot <- plot_grid(pts_plt, his_plt, ncol = 2)
}

### use character column names
plot_vars1 <- c("wt", "disp", "wt")
plt1 <- plot_vars1 %>% purrr::map(., ~ plot_duo(mtcars, .x, "mpg"))
#> [1] "character column names supplied, use ensym()"
#> `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
#> [1] "character column names supplied, use ensym()"
#> `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
#> [1] "character column names supplied, use ensym()"
#> `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

plot_grid(plotlist = plt1, nrow = 3)

### use bare column names
plot_vars2 <- alist(wt, disp, wt)
plt2 <- plot_vars2 %>% purrr::map(., ~ plot_duo(mtcars, .x, "mpg"))
#> [1] "bare column names supplied, use enquo()"
#> `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
#> [1] "bare column names supplied, use enquo()"
#> `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
#> [1] "bare column names supplied, use enquo()"
#> `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

plot_grid(plotlist = plt2, nrow = 3)

为了将绘图分成多个页面,我们可以使用gridExtra::marrangeGrob

ml1 <- marrangeGrob(plt, nrow = 2, ncol = 1)

# Interactive use
ml1

# Non-interactive use, multipage pdf
ggsave("multipage.pdf", ml1)

谢谢。这个几乎可以工作了。在我的 MWE 中,您可以看到我正在生成 6 个图表,第一个“页面”为 2x2,第二个为 2x1。我已经将您的代码适应到我的真实数据中,但是 do.call 将所有图表放在单个页面上。有没有办法强制限制 2x2,以便为每个 4 个子图创建一个单独的图表? - JenB

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