ggplot2:从图中删除未使用的因子水平组合的方面(facet_grid)

Posted

技术标签:

【中文标题】ggplot2:从图中删除未使用的因子水平组合的方面(facet_grid)【英文标题】:ggplot2: Deleting facets of unused factor level combinations from a plot (facet_grid) 【发布时间】:2017-04-09 23:43:13 【问题描述】:

我想从多面 ggplot2 图形中选择性地删除不必要的面。我看了这个问题,但不知道该怎么做(也许那里的建议现在已经过时了):

adding empty graphs to facet_wrap in ggplot2

这是一个最小的例子。我想删除右下角的空白刻面 (b, 2)。

library('ggplot2')
d <- data.frame('factor_1' = factor(c('a', 'a', 'b')),
                'factor_2' =    factor(c('1', '2', '1')),
                x = 1:3, y = 1:3)

ggplot(data = d, mapping = aes(x = x, y = y)) +
  geom_point() +
  facet_grid(facets = factor_1 ~ factor_2, drop = TRUE)

显然drop = TRUE 在这里不起作用,因为没有未使用的因子水平,只有未使用的组合。

【问题讨论】:

【参考方案1】:

在 ggplot2 2.2.0 中,绘图中的 grobs 的名称已更改。

library(ggplot2)
library(grid)
d <- data.frame('factor_1' = factor(c('a', 'a', 'b')),
                'factor_2' =    factor(c('1', '2', '1')),
                x = 1:3, y = 1:3)

p = ggplot(data = d, mapping = aes(x = x, y = y)) +
  geom_point() +
  facet_grid(facets = factor_1 ~ factor_2, drop = TRUE)

# Get ggplot grob
g = ggplotGrob(p)

# Get the layout dataframe. 
# Note the names.
# You want to remove "panel-2-2"
g$layout

# gtable::gtable_show_layout(g) # Might also be useful

# Remove the grobs
# The grob needs to be remove,
#  and the relevant row in the layout data frame needs to be removed
pos <- grepl(pattern = "panel-2-2", g$layout$name)
g$grobs <- g$grobs[!pos]
g$layout <- g$layout[!pos, ]


# Alternatively, replace the grobs with the nullGrob
g = ggplotGrob(p)
pos <- grep(pattern = "panel-2-2", g$layout$name)
g$grobs[[pos]] <- nullGrob()

# If you want, move the axis
# g$layout[g$layout$name == "axis-b-2", c("t", "b")] = c(8, 8)

# Draw the plot
grid.newpage()
grid.draw(g)

您的链接中的答案需要修改如下:

n <- 1000
df <- data.frame(x = runif(n), y=rnorm(n), label = sample(letters[1:7], 
                 size = n, replace = TRUE), stringsAsFactors=TRUE)
df$label.new <- factor(df$label, levels=sort(c(""," ",levels(df$label))))


p <- ggplot(df, aes(x=x, y=y)) + geom_point() + 
         facet_wrap(~ label.new, ncol=3,drop=FALSE)

g = ggplotGrob(p)

g$layout # Note the names and their positions (t, b, l, r)
# gtable::gtable_show_layout(g) # Might also be useful

pos <- g$layout$name %in% c("panel-1-1", "panel-1-2", "strip-t-1-1", "strip-t-2-1")
g$grobs <- g$grobs[!pos]
g$layout <- g$layout[!pos, ]

# Or replace the grobs with the nullGrob
g = ggplotGrob(p)
pos <- g$layout$name %in% c("panel-1-1", "panel-1-2", "strip-t-1-1", "strip-t-2-1")
g$grobs[pos] <- list(nullGrob())

# Move the axis
g$layout[g$layout$name == "axis-l-1-1", c("l", "r")] = c(10,10)

grid.newpage()
grid.draw(g)

【讨论】:

这是一个很好的答案,对我帮助很大。但是,当将它应用于我的非玩具问题时,我注意到(i)面板的命名(即“panel-5-3”等)似乎不是指情节中面板的坐标,但至少它们是在panel$layout 中排序的主要列,并且(ii)在调整轴/条的位置时(命名很简单),我不太了解位置信息(t(op), panel$layout 中的 b(ottom), r(ight), l(eft)) 实际上暗示。你能解释一下或指出一些有用的资源吗?无论如何,非常感谢。 (i) t(op), b(ottom), r(ight), l(eft) 给出 grob 相对于底层 gtable 的范围 - 请参阅布局数据框。您还可以使用gtable_show_layout() 获得底层 gtable 的图像。在布局数据框中的names 列中给出的 grobs 名称中的数字不是以 t、l、b、r 表示的。在 v2.2.0 中,“panel-5-3”表示“向下 5 个面板,跨 3 个面板”。对于条带,第一个数字是横,第二个数字是向下。使用 gtable_show_layout() 和/或布局数据框将 grobs 匹配到 grobs 名称到 tlbr。 (ii) 在gtable_show_layout() 中,注意您希望轴连接到的面板的行(t 和 b)。在您的示例中,它是第 7 行。轴位于下一行,即第 8 行。因此,t 和 b 都是 8。列号(r 和 l)保持不变。希望这会有所帮助。 我正在尝试删除从facet_grid(var1+var2 ~ var3) 创建的整整两行构面。不幸的是,在使用g$layout 时,我只看到没有数字的短语“面板”。我总共有 4x6 个方面。关于我如何在这种情况下工作的任何线索?【参考方案2】:

不是最好的解决方案,但它给出了一些令人满意的结果:

    d$fInter <- interaction(d$factor_2, d$factor_1, sep = ' V ')

    ggplot(data = d, mapping = aes(x = x, y = y)) +
      geom_point() +
      facet_wrap(~ fInter, drop = TRUE, 
                 ncol = nlevels(d$factor_1))

还有情节:

【讨论】:

恐怕我肯定需要使用facet_grid 而不是facet_wrap 请问有什么特别的原因吗?您可以只使用 ~factor_1 + factor_2 而不是新的交互值,但这对眼睛来说会不太舒服。 这只是一个最小的例子,实际上我已经有列的嵌套因子。

以上是关于ggplot2:从图中删除未使用的因子水平组合的方面(facet_grid)的主要内容,如果未能解决你的问题,请参考以下文章

从使用 ggplot2 创建的多面条形图中删除重复的类别标签

ggplot2:将颜色固定到因子水平

在ggplot2中的散点图中添加一条水平线

使用 `scale_colour_manual` 或替代方法(有时)缺少因子水平时,`ggplot2` 中的一致着色

ggplot2 中图例的自定义顺序,因此它与图中因子的顺序不匹配

r 从ggplot2图中删除图例