将平面图分割成图表列表

时间:2015-05-28 15:27:37

标签: r ggplot2

ggplot2中的分面图的巨大粉丝。但是,有时我会有太多的子图,并且很容易将它们分解成一个图表列表。例如

df <- data.frame(x=seq(1,24,1), y=seq(1,24,1), z=rep(seq(1,12),each=2))
df
    x  y  z
1   1  1  1
2   2  2  1
3   3  3  2
4   4  4  2
5   5  5  3
.   .  .  .
.   .  .  .

myplot <- ggplot(df,aes(x=x, y=y))+geom_point()+facet_wrap(~z)
myplot

enter image description here

我如何编写一个函数来获取结果图并将其拆分成一个图表列表?沿着这些方向的东西

splitFacet <- function(subsPerPlot){
  # Method to break a single facet plot into a list of facet plots, each with at most `subsPerPlot` subplots

  # code...

  return(listOfPlots)
}

4 个答案:

答案 0 :(得分:11)

将地块分割成单个地块

我们按照以下步骤构建一个函数:

  1. 我们遍历对象的结构以获取用于构面的变量的名称(此处为'z')。
  2. 我们用空的facet对象中的元素覆盖绘图对象的ggplot元素(因此,如果我们在此阶段进行打印,则刻面消失了)。
  3. 我们提取数据并将其按照第一步中确定的变量进行拆分。
  4. 我们用每个子集覆盖原始数据(此处12次),并将所有输出存储在列表中。

代码

splitFacet <- function(x){
  facet_vars <- names(x$facet$params$facets)         # 1
  x$facet    <- ggplot2::ggplot()$facet              # 2
  datasets   <- split(x$data, x$data[facet_vars])    # 3
  new_plots  <- lapply(datasets,function(new_data) { # 4
    x$data <- new_data
    x})
}    

new_plots <- splitFacet(myplot)
length(new_plots) # [1] 12
new_plots[[3]]    # 3rd plot


将图分割成最大n个子图的多面图

如果我们要保留构面但按构面划分的图较少,则可以跳过第2步,而是重新分割拆分,以便它包含用于构面的变量的多个值。

n是通过绘制获得的构面数量,而不是单独构建函数,我们将概括第一个。

n = NULL表示您得到的是先前的输出,它与n = 1略有不同(按图一个面)。

splitFacet <- function(x, n = NULL){
  facet_vars <- names(x$facet$params$facets)               # 1
  if(is.null(n)){
    x$facet  <- ggplot2::ggplot()$facet                    # 2a
    datasets <- split(x$data, x$data[facet_vars])          # 3a
  } else {
    inter0 <- interaction(x$data[facet_vars], drop = TRUE) # 2b
    inter  <- ceiling(as.numeric(inter0)/n)
    datasets <- split(x$data, inter)                       # 3b
  }
  new_plots  <- lapply(datasets,function(new_data) {       # 4
    x$data <- new_data
    x})
} 

new_plots2 <- splitFacet(myplot,4)
length(new_plots2) # [1] 3
new_plots2[[2]]    


这也可能派上用场:

unfacet <- function(x){
  x$facet <- ggplot2::ggplot()$facet
  x
}

整洁的方式

如果代码可用,则无需经历所有麻烦,我们可以先拆分数据,然后再将数据提供给ggplot

library(tidyverse)
myplots3 <-
  df %>% 
  split(ceiling(group_indices(.,z)/n_facets)) %>% 
  map(~ggplot(.,aes(x =x, y=y))+geom_point()+facet_wrap(~z))

myplots3[[3]]

答案 1 :(得分:5)

虽然我正在为此寻找解决方案,但我可以跨越ggplus。特别是函数facet_multiple

https://github.com/guiastrennec/ggplus

它允许您通过指定每页所需的绘图量来分割多个页面上的构面。在您的示例中,它将是:

library(ggplus)

df <- data.frame(x=seq(1,24,1), y=seq(1,24,1), z=rep(seq(1,12),each=2))

myplot <- ggplot(df,aes(x=x, y=y))+geom_point()

facet_multiple(plot = myplot, facets = 'z', ncol = 2, nrow = 2)

这是你需要的吗?它对我有用。

答案 2 :(得分:2)

这类似于Moody_Muddskipper的回答,但可用于任何类型的构面(facet_gridfacet_wrap),可处理构面中的任意表达式,并且不会绘制构面条。

library(rlang)
library(ggplot2)

split_facets <- function(x) {
  facet_expr <- unlist(x[["facet"]][["params"]][c("cols", "rows", "facets")])
  facet_levels <- lapply(facet_expr, rlang::eval_tidy, data = x[["data"]])
  facet_id <- do.call(interaction, facet_levels)
  panel_data <- split(x[["data"]], facet_id)
  plots <- vector("list", length(panel_data))
  for (ii in seq_along(plots)) {
    plots[[ii]] <- x
    plots[[ii]][["data"]] <- panel_data[[ii]]
    plots[[ii]][["facet"]] <- facet_null()
  }
  plots
}

split_facets(ggplot(df,aes(x=x, y=y))+geom_point()+facet_wrap(~z))
split_facets(ggplot(df,aes(x=x, y=y))+geom_point()+facet_grid(z %% 2 ~ z %% 5))

它使用rlang::eval_tidy来评估构面表达式,将它们组合成一个单一的分类因子,然后使用它来拆分数据。通过用facet_null()替换每个子图的刻面部分,它也“抑制”了它。

答案 3 :(得分:0)

将其发布给想要使用ggplus的任何人。 ggplus可以在R的更高版本中使用,但是您需要按照开发人员的指导进行安装,即

 devtools::install_github("guiastrennec/ggplus")

当我尝试使用RStudio安装它时遇到了相同的问题,然后意识到它不是“标准软件包”之一。我正在使用3.4.4。