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