rggplot2nestedfacetgeom-bar

How to create a graph with multiple nested facets horizontally and vertically?


Below is a simplified version of my data. I want to plot the Means using vertical bars with ggplot() + geom_bar. There are a few things I want to do.

Target  Manner  Vfront  MedDor  Mean
p       Stop    front   NA      0.60
p       Stop    back    NA      0.59
p       Stop    front   cor     0.58
p       Stop    back    cor     0.56
p       Stop    front   incor   0.52
p       Stop    back    incor   0.52
p       Stop    front   X       0.24
p       Stop    back    X       0.52
b       Stop    front   NA      0.42
b       Stop    back    NA      0.39
b       Stop    front   cor     0.37
b       Stop    back    cor     0.42
b       Stop    front   incor   0.36
b       Stop    back    incor   0.33
b       Stop    front   X       0.14
b       Stop    back    X       0.39
f       Fric    front   NA      0.27
f       Fric    back    NA      0.23
f       Fric    front   cor     0.19
f       Fric    back    cor     0.40
f       Fric    front   incor   0.13
f       Fric    back    incor   0.32
f       Fric    front   X       0.08
f       Fric    back    X       0.13
v       Fric    front   NA      0.24
v       Fric    back    NA      0.18
v       Fric    front   cor     0.17
v       Fric    back    cor     0.11
v       Fric    front   incor   0.25
v       Fric    back    incor   0.16
v       Fric    front   X       0.09
v       Fric    back    X       0.16

So in total I should get something similar to the grouped data that I have below:

                         Front                              Back
pNA pcor pincor cX bNA bcor bincor bX pNA pcor pincor cX bNA bcor bincor bX
         p                    b                    p                    b 
fNA fcor fincor fX vNA vcor vincor vX fNA fcor fincor fX vNA vcor vincor vX
         f                    v                    f                    v

I can do some basic filtering of data, and factoring to get certain orders and I know facet_grid(~Vfront) gives me different columns according to Vfront values (based on my data) but the divisions I am asking about is beyond my current R abilities.


Solution

  • We can use ggh4x::facet_nested for nested facets like you want. If you want a certain order of facets, you need to create factor columns with levels that you desire; however, NA will always come last, so we need to convert NA to "NA".

    library(ggplot2)
    library(ggh4x)
    library(dplyr)
    library(tidyr)
    
    df1 %>% 
      mutate(MedDor_f = factor(replace_na(MedDor, "NA") , 
                               levels = c("NA", "cor", "incor", "X")),
             Manner_f = factor(Manner, levels = c("Stop", "Fric")), 
             Vfront_f = factor(Vfront, levels = c("front", "back"))) %>% 
     ggplot(aes(x = Target, y = Mean)) +
      geom_bar(stat = "identity") +
      facet_nested(rows = vars(Manner_f), cols = vars(Vfront_f, MedDor_f))
    

    Update:

    If you want the x-axis to have a free scale (like what we get in facet_wrap), you need to add scales = "free_x", independent = "x" to the facet_nested function.

    I have also looked at your previous question, and implemented that solution here (not sure whether you want that or not, but it looks nice).

    df1 %>% 
      mutate(MedDor_f = factor(replace_na(MedDor, "NA") , 
                               levels = c("NA", "cor", "incor", "X")),
             Manner_f = factor(Manner, levels = c("Stop", "Fric")), 
             Vfront_f = factor(Vfront, levels = c("front", "back")), 
             Deviation = Mean - 0.5) %>% 
     ggplot(aes(x = Target, y = Deviation)) +
      geom_col(aes(fill = Deviation > 0), position = position_dodge()) +
      geom_hline(yintercept = 0, linetype = "dashed", color = "black") +
      scale_fill_manual(values = c("TRUE" = "cadetblue3", "FALSE" = "coral3")) +
      theme_classic() +
      scale_y_continuous(limits = c(-0.5, 0.5),  
                         breaks = seq(-0.5, 0.5, by = 0.1),
                         labels = function(x) sprintf("%.1f", x + 0.5)) +
      theme(legend.position = "bottom", 
            axis.ticks.x = element_blank()) +
      facet_nested(rows = vars(Manner_f), cols = vars(Vfront_f, MedDor_f), 
                   scales = "free_x", independent = "x")
    

    Created on 2024-02-06 with reprex v2.0.2

    If you don't want to use ggh4x, then you need to use grid, gtable, and/or patchwork or other similar libraries, get your individual plots and arrange them in a grid. I personally would spend some more time on figuring out why ggh4x is not working, maybe updating my R version, etc., before going down that route. Good luck!