ggplot - Centralize facet_grid title and appear only once [duplicate]

陌路散爱 提交于 2020-05-29 06:24:06

问题


I've created a graph in ggplot with two variables inside facet_grid.

I want the title of each facet to repeat only once and in the center of the facet.

For example, the zeros and ones in the first raw (upper facet), will appear only once and in the middle.

In my original plot, the number of plots per facet is not equal. Thus, patching together two plots using patchwork/ cowplot / ggpubr doesn't work very well.
I prefer a solution/hack only using ggplot.

Sample data:

df <- head(mtcars, 5)

Example plot:

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

Edit - new data

I created a sample data which resembles my actual data more accurately.

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

Plot:

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


回答1:


The quickest hack: fake the facet with a plot and combine. This requires some hacking, but it's probably still less hack than messing with the grobs:

  • make joint variable for facet plot.
  • make fake facet and combine with package such as patchwork. reduce margins of plots to minus, so that there is really no margin.
  • make the relative height ratio kind of ridiculously high, so the second plot disappears and only facet strip remains.
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) )

Created on 2020-03-24 by the reprex package (v0.3.0)

update with new data - some more complex facets. Indeed, patchwork is difficult here. Easier to combine the fake facets with cowplot, after transforming the fake facets to grid object and changing the widths. All within 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. 

Created on 2020-03-24 by the reprex package (v0.3.0)

Some additional thoughts

I was thinking that one cannot get around a hack like that - because the gtable_layout of the original plot (with two facet variables) shows the entire facet strip is one grob! THis answer proved me wrong - the grob contains a nested table for both strips!. But there is an easier solution thanks to the ggnomics package - see my second answer

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)

Created on 2020-03-24 by the reprex package (v0.3.0)




回答2:


Sorry to add a second answer, but I believe it's different enough to merit a separate answer. I should have thought of the ggnomics package earlier, which makes this task super simple!

 #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"))

Created on 2020-03-24 by the reprex package (v0.3.0)



来源:https://stackoverflow.com/questions/60822398/ggplot-centralize-facet-grid-title-and-appear-only-once

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!