ggplot - 将 facet_grid 标题居中并仅出现一次

4

我已经在ggplot中使用了两个变量创建了一个图形,并使用facet_grid进行了分面。

我希望每个分面的标题只重复一次,并且位于分面的中央。

例如,在第一行(上部分面)中的零和一将仅出现一次,并位于正中间。

在我的原始图中,每个分面的绘图数量不相等。因此,使用patchwork / cowplot / ggpubr将两个图表拼接在一起并不很好。
我更喜欢仅使用ggplot的解决方案/技巧。

enter image description here

示例数据:

df <- head(mtcars, 5)

示例图:

df %>% 
  ggplot(aes(gear, disp)) + 
  geom_bar(stat = "identity") + 
  facet_grid(~am + carb,
             space = "free_x", 
             scales = "free_x") +
  ggplot2::theme(
    panel.spacing.x = unit(0,"cm"), 
    axis.ticks.length=unit(.25, "cm"), 
    strip.placement = "outside",
    legend.position = "top",
    legend.justification = "center",
    legend.direction = "horizontal",
    legend.key.size = ggplot2::unit(1.5, "lines"),
    # switch off the rectangle around symbols
    legend.key = ggplot2::element_blank(),
    legend.key.width = grid::unit(2, "lines"),
    # # facet titles
    strip.background = ggplot2::element_rect(
      colour = "black",
      fill = "white"),
    panel.background = ggplot2::element_rect(
      colour = "white",
      fill = "white"), 
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank())

编辑 - 新数据

我创建了一个样本数据,更准确地类似于我的实际数据。

structure(list(par = c("Par1", "Par1", "Par1", "Par1", "Par1", 
"Par1", "Par1", "Par1", "Par1", "Par1", "Par1", "Par1", "Par1", 
"Par1", "Par1", "Par1", "Par1", "Par1", "Par1", "Par1", "Par1", 
"Par1", "Par1", "Par1", "Par1", "Par1", "Par1", "Par2", "Par2", 
"Par2"), channel_1 = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 11L, 11L, 11L, 11L, 
11L, 11L, 11L, 11L, 11L, 1L, 1L, 1L), .Label = c("Center", "Left \nFrontal", 
"Left \nFrontal Central", "Left \nCentral Parietal", "Left \nParietal Ooccipital", 
"Left", "Right \nFrontal", "Right \nFrontal Central", "Right \nCentral Parietal", 
"Right \nParietal Ooccipital", "Right"), class = "factor"), freq = structure(c(1L, 
1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L, 1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 
3L, 1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L), .Label = c("Alpha", 
"Beta", "Gamma"), class = "factor"), group = c("a", "b", "c", 
"a", "b", "c", "a", "b", "c", "a", "b", "c", "a", "b", "c", "a", 
"b", "c", "a", "b", "c", "a", "b", "c", "a", "b", "c", "a", "b", 
"c"), m = c(0.488630500442935, 0.548666228768508, 0.0441536349332613, 
0.304475866391531, 0.330039488441422, 0.0980622573307064, 0.0963996979198171, 
0.301679466108907, 0.240618782227119, 0.35779695722622, 0.156116647839907, 
0.0274546218676152, 0.0752501569920047, 0.289342864254614, 0.770518960576786, 
0.548130676907356, 0.180158614358946, 0.238520826021687, 0.406326198917495, 
0.159739769132509, 0.140739952534666, 0.295427640977557, 0.106130817023844, 
0.214006898241167, 0.31081727835652, 0.366982521446529, 0.264432086988446, 
0.0761271112139142, 0.0811642772125171, 0.0700455890939194), 
    se = c(0.00919040825504951, 0.00664655073810519, 0.0095517721611042, 
    0.00657090455386036, 0.00451135146762504, 0.0188625074573698, 
    0.00875378313351897, 0.000569521129673224, 0.00691447732630984, 
    0.000241814142091401, 0.0124584589176995, 0.00366855139256551, 
    0.0072981677277562, 0.0160663614099261, 0.00359337442316408, 
    0.00919725279757502, 0.040856967817406, 0.00240910563984416, 
    0.0152236046767608, 0.00765487375180611, 0.00354140237391633, 
    0.00145468584619171, 0.0185141245423404, 0.000833307847848054, 
    0.0038193622895167, 0.0206130436440409, 0.0066911922721337, 
    7.3079999953491e-05, 0.0246233416039572, 0.00328150956514463
    )), row.names = c(NA, -30L), class = c("tbl_df", "tbl", "data.frame"
))

剧情:

df %>%
  ggplot(aes(channel_1, m, 
             group = group,
             fill = group, 
             color = group)) +
  facet_grid(~par + freq,
             space="free_x", 
             scales="free_x") +
  geom_errorbar(
    aes(min = m - se, ymax = m + se, alpha = 0.01), 
    width = 0.2, size = 2, color = "black", 
    position = position_dodge(width = 0.6)) +
  geom_bar(stat = "identity",
           position = position_dodge(width = 0.6),
           # color = "black", 
           # fill = "white",
           width = 0.6, 
           size = 2, aes(alpha = 0.01))  + 
  scale_shape_manual(values = c(1, 8, 5)) + 
  labs(
    color = "",
    fill = "", 
    shape = "") +
  guides(
    color = FALSE,
    shape = FALSE) +
  scale_alpha(guide = "none")

enter image description here


早些时候应该查找重复项哈哈!但我学到了一些新东西,所以还不错 :) ggplot2中跨组嵌套因素 - tjebo
2个回答

5

最快的方法:用绘图和组合来伪造facet。这需要一些技巧,但可能仍然比搞grobs更容易:

  • 为facet plot创建联合变量。
  • 制作假的facet并与patchwork等软件包组合。将图的边距减小到负数,以便确实没有边距。
  • 使相对高度比率非常高,这样第二个图就会消失,只剩下facet strip。
library(patchwork)
library(tidyverse)

df <- head(mtcars,5)
df <- df %>% mutate(am_carb = factor(paste(am,carb,sep = '_'), 
                      labels = c( ' 1','2','1','4')))
##note!! the blank space in ' 1' label is on purpose!!! this is to make those labels unique, otherwise it would consider both '1' the same category!!

p1 <-
  df %>% 
  ggplot(aes(gear, disp)) + 
  geom_bar(stat = "identity") + 
  facet_grid(~am_carb, scales = "free_x") +
theme(panel.spacing.x = unit(0,"cm"),
      plot.margin = margin(t = -2),
      strip.background = element_rect(colour = "black",fill = "white"),
      panel.background = element_rect(colour = "white", fill = "white"), 
      panel.grid.major = element_blank(),
      panel.grid.minor = element_blank())

p2 <-
  df %>% 
  ggplot(aes(gear, disp)) + 
  geom_blank() + 
  facet_grid(~ am, scales = "free_x") +
  theme(panel.spacing.x = unit(0,"cm"),
        axis.text = element_blank(),
        axis.ticks = element_blank(),
        axis.title = element_blank(),
        plot.margin = margin(b = -2),
        strip.background = element_rect(colour = "black",fill = "white"),
        panel.background = element_rect(colour = "white", fill = "white"), 
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank())


p2/p1 + plot_layout(heights = c(0.1,100) )

本文创建于2020年3月24日,使用reprex包(v0.3.0)

使用新数据进行更新 - 一些更复杂的图层。确实,在这里使用patchwork很困难。最好先将虚假的图层转换为网格对象并更改宽度,然后再使用cowplot组合。所有操作都在cowplot中完成。

mydat <- structure(list(par = c("Par1", "Par1", "Par1", "Par1", "Par1", "Par1", "Par1", "Par1", "Par1", "Par1", "Par1", "Par1", "Par1", "Par1", "Par1", "Par1", "Par1", "Par1", "Par1", "Par1", "Par1", "Par1", "Par1", "Par1", "Par1", "Par1", "Par1", "Par2", "Par2", "Par2"), channel_1 = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 6L, 11L, 11L, 11L, 11L, 11L, 11L, 11L, 11L, 11L, 1L, 1L, 1L), .Label = c("Center", "Left \nFrontal", "Left \nFrontal Central", "Left \nCentral Parietal", "Left \nParietal Ooccipital", "Left", "Right \nFrontal", "Right \nFrontal Central", "Right \nCentral Parietal", "Right \nParietal Ooccipital", "Right"), class = "factor"), freq = structure(c(1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L, 1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L, 1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L), .Label = c("Alpha", "Beta", "Gamma"), class = "factor"), group = c("a", "b", "c", "a", "b", "c", "a", "b", "c", "a", "b", "c", "a", "b", "c", "a", "b", "c", "a", "b", "c", "a", "b", "c", "a", "b", "c", "a", "b", "c"), m = c(0.488630500442935, 0.548666228768508, 0.0441536349332613, 0.304475866391531, 0.330039488441422, 0.0980622573307064, 0.0963996979198171, 0.301679466108907, 0.240618782227119, 0.35779695722622, 0.156116647839907, 0.0274546218676152, 0.0752501569920047, 0.289342864254614, 0.770518960576786, 0.548130676907356, 0.180158614358946, 0.238520826021687, 0.406326198917495, 0.159739769132509, 0.140739952534666, 0.295427640977557, 0.106130817023844, 0.214006898241167, 0.31081727835652, 0.366982521446529, 0.264432086988446, 0.0761271112139142, 0.0811642772125171, 0.0700455890939194), se = c(0.00919040825504951, 0.00664655073810519, 0.0095517721611042, 0.00657090455386036, 0.00451135146762504, 0.0188625074573698, 0.00875378313351897, 0.000569521129673224, 0.00691447732630984, 0.000241814142091401, 0.0124584589176995, 0.00366855139256551, 0.0072981677277562, 0.0160663614099261, 0.00359337442316408, 0.00919725279757502, 0.040856967817406, 0.00240910563984416, 0.0152236046767608, 0.00765487375180611, 0.00354140237391633, 0.00145468584619171, 0.0185141245423404, 0.000833307847848054, 0.0038193622895167, 0.0206130436440409, 0.0066911922721337, 7.3079999953491e-05, 0.0246233416039572, 0.00328150956514463)), row.names = c(NA, -30L), class = c("tbl_df", "tbl", "data.frame"))

library(tidyverse)
library(cowplot)
#> 
#> ********************************************************
#> Note: As of version 1.0.0, cowplot does not change the
#>   default ggplot2 theme anymore. To recover the previous
#>   behavior, execute:
#>   theme_set(theme_cowplot())
#> ********************************************************

mydat <- mydat %>% mutate(par_freq = factor(paste(par,freq,sep = '_'), labels = c('Alpha', 'Beta', 'Gamma', 'Gamma ' )))

p1 <-
  mydat %>% 
    ggplot(aes(channel_1, m, group = group, fill = group, color = group)) +
  geom_bar(stat = "identity") + 
  facet_grid( ~ par_freq, scales = "free_x", space="free_x") +
  theme(panel.spacing.x = unit(0,"cm"),
        plot.margin = margin(t = -2),
        strip.background = element_rect(colour = "black",fill = "white"),
        panel.background = element_rect(colour = "white", fill = "white"), 
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        legend.position = 'none')

p2 <-
  mydat %>%
    ggplot(aes(channel_1, m, group = group, fill = group, color = group)) +
    geom_blank() + 
    facet_grid(~ par) +
    theme(panel.spacing.x = unit(0,"cm"),
          axis.text = element_blank(),
          axis.ticks = element_blank(),
          axis.title = element_blank(),
          plot.margin = margin(b = -2),
          strip.background = element_rect(colour = "black",fill = "white"),
          panel.background = element_rect(colour = "white", fill = "white"), 
          panel.grid.major = element_blank(),
          panel.grid.minor = element_blank())


gt <-  cowplot::as_gtable(p2)
gt$widths[5] <- 8*gt$widths[7]
cowplot::plot_grid(gt, p1, align = "v", axis = 'l',nrow = 2, rel_heights = c(5, 100))
# you need to play around with the values unfortunately. 

该内容创建于2020年3月24日,使用reprex package (v0.3.0)

一些额外的想法

我认为无法避免像那样的hack - 因为原始图表的gtable_layout(具有两个facet变量)显示整个facet strip是一个grob!这个答案证明了我错了 - grob包含了两个strip的嵌套表格!。但是,由于ggnomics包的存在,有一个更简单的解决方案 - 请参见我的第二个答案。

p_demo <-   ggplot(mydat, aes(channel_1, m)) + 
  geom_bar(stat = "identity") + 
  facet_grid(~par +freq , space = "free_x",  scales = "free_x") +
  theme(panel.spacing.x = unit(0,"cm"))

gt <-  cowplot::as_gtable(p_demo)
gtable::gtable_show_layout(gt)

2020年3月24日创建,使用reprex包 (v0.3.0)


patchwork 是一个非常棒的包。然而,我的问题是我的原始两个图不是相同大小的。因此,如果我不使用 facet_grid,比例看起来会非常糟糕。 - DJV
1
天啊,那真是个噩梦;)。我希望这次不会难以再现!实际上,我开始尝试查看的是在面板标题上绘制矩形(https://stackoverflow.com/questions/60827811/ggplot-cover-facet-grid-title-with-rectangle),但没有成功。 - DJV

1

很抱歉要再次回答,但我认为这个问题与之前的不同,值得单独回答。我早该想到使用ggnomics包,它可以使这个任务变得非常简单!

 #devtools::install_github("teunbrand/ggnomics")
  library(ggnomics)
#> Loading required package: ggplot2
  library(tidyverse)

  mydat<- head(mtcars, 5)
  mydat %>% 
    ggplot(aes(gear, disp)) + 
    geom_bar(stat = "identity") + 
    facet_nested(~am + carb) +
    theme(panel.spacing.x = unit(0,"cm"), 
          axis.ticks.length=unit(.25, "cm"), 
          strip.placement = "inside",
          strip.background = element_rect( colour = "black", fill = "white"),
          panel.background = element_rect( colour = "black", fill = "white"))

该内容由reprex package (v0.3.0)于2020-03-24创建


2
顺便提一下,在出现错误后,似乎ggnomics和新的ggplot之间存在冲突(https://github.com/teunbrand/ggnomics/issues/37)。因此,作者建议使用包`ggh4x`(https://github.com/teunbrand/ggh4x),如果您想使用`facet_nested`。再次感谢! - DJV

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