Search code examples
rggplot2facet-wrapx-axis

How to facet wrap plots with two different factors


For example, i have two trials, each with main factors of year and treatment. I want to plot response to the same plot, preferably Trial one / treatment / year and the same for trial 2. Closest that i can get is shown on the simple example picture. Basically i get two graphs joined together, one showing effects of treatment in trial 1 and trial 2 with y axis representing content, and other showing effect of year in trial 1 and trial 2 with y axis representing the same content.

Simple example of plot with Si content affected by treatments and year of sampling

Is it possible to facet wrap graphs together, or at least to remove redundant y axis?

Code that i use is:

a <- ggplot(I1, aes(x=fct_reorder(SISTEM, ORDER), y=Si)) + geom_jitter(show.legend=FALSE, width=0.25, color="black", size=0.5) + stat_summary(fun.data = mean_cl_normal, show.legend=FALSE, color="red", size=0.3) + labs(x=NULL,
   y="Si (mg / 100 g)") + facet_wrap(~POSKUS, ncol=2, scales="free_x") + theme_classic(base_family = "Palatino Linotype") + theme(axis.text=element_text(colour="black", size=8), axis.title=element_text(colour="black", size=8), axis.text.x=element_text(angle=45, vjust = 1, hjust=1)) + theme(strip.background = element_blank()) + ggplot(I1, aes(x=Leto, y=Si)) + geom_jitter(show.legend=FALSE, width=0.25, color="black", size=0.5) + scale_x_continuous(breaks=c(2016,2017)) + stat_summary(fun.data = mean_cl_normal, show.legend=FALSE, color="red", size=0.3) + labs(x=NULL,
   y="") + facet_wrap(~POSKUS + Leto, ncol=4, scales="free_x") + theme_classic(base_family = "Palatino Linotype") + theme(axis.text=element_text(colour="black", size=8), axis.title=element_text(colour="black", size=8), axis.text.x=element_text(angle=45, vjust = 1, hjust=1)) +  theme(strip.background = element_blank())`

The solution as given below sorta works with minor tweaks still needed. Using the provided code, and expanding it to sort the treatments as needed, and changing the order of variables in the facet wrap provided the plot as shown in figure 2. However, facets labels are now showing only 1 and 2 rather than Trial 1 and Trial 2. Furthermore, is it possible to have only one Trial 1 and Trial 2 name for both TREATMENT and YEAR variables? Plot using the code as proposed

Added dput:

I2 <- structure(list(Leto = c("2016", "2016", "2016", "2016", "2016", 
"2016", "2016", "2016", "2016", "2016", "2016", "2016", "2016", 
"2016", "2016", "2017", "2017", "2017", "2017", "2017", "2017", 
"2017", "2017", "2017", "2017", "2017", "2017", "2017", "2017", 
"2017", "2016", "2016", "2016", "2016", "2016", "2016", "2016", 
"2016", "2016", "2016"), POSKUS = structure(c(1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L), .Label = c("Trial 1", "Trial 2"), class = "factor"), 
    SISTEM = structure(c(5L, 5L, 5L, 1L, 1L, 1L, 2L, 2L, 2L, 
    3L, 3L, 3L, 4L, 4L, 4L, 5L, 5L, 5L, 1L, 1L, 1L, 2L, 2L, 2L, 
    3L, 3L, 3L, 4L, 4L, 4L, 6L, 6L, 6L, 7L, 7L, 7L, 8L, 8L, 8L, 
    9L), .Label = c("Manure-N0", "Manure-N1", "Manure-N2", "Manure-N3", 
    "No.org-N0", "No.org-N3", "Straw-N0", "Straw-N1", "Straw-N2", 
    "Straw-N3"), class = "factor"), ORDER = c(1, 1, 1, 2, 2, 
    2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 1, 1, 1, 2, 2, 2, 3, 3, 3, 
    4, 4, 4, 5, 5, 5, 5, 5, 5, 1, 1, 1, 2, 2, 2, 3), DUSIK = c(0, 
    0, 0, 0, 0, 0, 55, 55, 55, 110, 110, 110, 165, 165, 165, 
    0, 0, 0, 0, 0, 0, 55, 55, 55, 110, 110, 110, 165, 165, 165, 
    165, 165, 165, 0, 0, 0, 55, 55, 55, 110), Si = c(9.35, 11.6, 
    9.71, 8.96, 6.13, 7.08, 3.74, 3.72, 4.75, 1.3, 1.82, 3.41, 
    5.13, 3.41, 3.68, 7.67, 7.48, 6.21, 5.02, 9.46, 7.79, 8.11, 
    3.59, 8.28, 7.36, 9.69, 9.08, 6.46, 5.48, 7.9, 5.27, 4.06, 
    4.22, 5.6, 5.92, 6.9, 3.26, 4.45, 3.09, 4.38), P = c(2.62, 
    2.26, 2.33, 2.57, 3.06, 2.99, 1.71, 2.06, 2.18, 1.48, 1.71, 
    2.66, 2.24, 2.38, 2.55, 2.49, 2.48, 3.9, 2.65, 1.79, 2.88, 
    2.54, 3.22, 2.54, 2.88, 2.93, 3.26, 2.09, 3.03, 2.56, 2.43, 
    2.72, 2.59, 2.58, 3.71, 2.5, 2.45, 2.48, 3.49, 3.31), S = c(1.24, 
    0.95, 1.07, 1.17, 1.15, 1.15, 0.81, 1.08, 1.07, 0.89, 0.85, 
    1.15, 1.12, 1.22, 1.24, 1.16, 0.98, 1.32, 1.29, 1.04, 1, 
    0.9, 1.19, 1.03, 1.14, 1.05, 1.14, 1.1, 1.13, 1.25, 0.92, 
    1.19, 0.84, 1.27, 1.14, 1.05, 1.29, 1.05, 1.15, 1.02), Cl = c(0.39, 
    0.31, 0.32, 0.3, 0.39, 0.38, 0.24, 0.26, 0.32, 0.35, 0.3, 
    0.31, 0.3, 0.32, 0.28, 0.3, 0.24, 0.27, 0.29, 0.28, 0.25, 
    0.34, 0.38, 0.34, 0.33, 0.31, 0.33, 0.33, 0.31, 0.35, 0.25, 
    0.25, 0.26, 0.35, 0.35, 0.39, 0.33, 0.25, 0.25, 0.28), K = c(4.47, 
    4.05, 3.59, 4.18, 4.07, 4.43, 3.12, 3.79, 4.63, 5.02, 4.52, 
    4.49, 4.64, 4.21, 4.38, 4.27, 4.08, 5.23, 3.66, 3.39, 4.14, 
    3.99, 4.21, 3.83, 4.19, 4.95, 5.11, 3.44, 4.27, 4.6, 4.99, 
    4.54, 4.12, 3.82, 5.55, 4.48, 3.7, 3.8, 5.08, 4.47), Ca = c(0.78, 
    0.68, 0.66, 0.69, 0.77, 0.73, 0.46, 0.6, 0.66, 0.59, 0.61, 
    0.71, 0.77, 0.58, 0.7, 0.61, 0.79, 0.87, 0.77, 0.69, 0.84, 
    0.62, 0.77, 0.62, 0.66, 0.71, 0.68, 0.59, 0.67, 0.73, 0.62, 
    0.69, 0.61, 0.69, 0.8, 0.72, 0.56, 0.6, 0.63, 0.65), Ti = c(78.5, 
    73.7, 74, 69, 68.9, 52.3, 33.7, 35, 26.6, 41, 50.7, 42.2, 
    33.6, 38.7, 41.5, 56.9, 64.6, 60.1, 69.4, 65.7, 65.7, 52.6, 
    42.2, 46.1, 50.8, 44.1, 35.6, 47.3, 39.2, 47.7, 39.6, 40.3, 
    38.2, 67.9, 52.3, 63.1, 43.4, 35.1, 37.2, 27), Fe = c(56.2, 
    52.9, 57.1, 48.8, 46.7, 35.1, 45.8, 48.6, 49.6, 71.5, 66, 
    85.7, 45.6, 70.2, 58.8, 75.6, 85.2, 93.9, 85.7, 68.7, 70.1, 
    61.2, 60.6, 76.8, 113, 68.5, 74.9, 91.9, 44.4, 104, 62.1, 
    55.3, 78.5, 75.7, 51.7, 53.2, 49, 74.4, 51.9, 57.6), Zn = c(31.3, 
    29.9, 28, 27.4, 27.9, 27.7, 19.6, 19.6, 22, 20.6, 23.1, 20.6, 
    25.1, 22.6, 22.7, 32.5, 35.5, 31.1, 28.6, 29.2, 29.6, 21.8, 
    29.5, 25, 26.1, 24.7, 20.1, 23.9, 20.3, 24.6, 20.3, 21.1, 
    26.6, 27.4, 32.6, 30.4, 19.9, 21.8, 24.7, 20.7), Br = c(8.54, 
    7.65, 6.27, 5.83, 7.25, 6.92, 4.74, 4.79, 4.51, 7.53, 5.02, 
    4.35, 3.98, 3.64, 4.26, 10, 13.7, 12.7, 7.67, 8.62, 10.1, 
    2.52, 3.63, 2.7, 2.44, 2.73, 2.49, 5.9, 2.52, 2.56, 6.05, 
    5.6, 6.98, 7.81, 12.3, 8.11, 5.91, 6.01, 6.15, 5.74), Rb = c(1.95, 
    1.53, 2.12, 1.44, 2.54, 1.84, 1.62, 2.78, 2.35, 3.24, 3.62, 
    3.48, 4.74, 3.34, 4.21, 5.43, 3.94, 5.55, 3.01, 2.19, 3.34, 
    3.55, 5.08, 2.63, 5.44, 4.67, 4.71, 6.52, 2.99, 3.24, 4.19, 
    3.11, 4.11, 1.57, 1.26, 1.14, 1.95, 2.21, 2.57, 2.41), Sr = c(0.94, 
    0.97, 0.86, 1.07, 1.19, 1.97, 1.08, 1.23, 1.35, 1.23, 1.17, 
    1.03, 0.86, 0.96, 0.86, 3.51, 1.94, 3.44, 1.47, 1.95, 2.14, 
    1.36, 4.22, 2.07, 1.92, 1.8, 2.34, 2.89, 2.13, 2.62, 1.3, 
    1.16, 1.95, 1, 1.41, 0.77, 1.25, 1.09, 1.37, 1.28), N = c(5.68, 
    4.93, 4.36, 6.36, 4.68, 5, 4.67, 3.38, 3.33, 3.94, 3.61, 
    3.52, 3.03, 2.74, 2.7, 8.47, 7.33, 5.82, 8.01, 7.34, 7.12, 
    5.84, 4.5, 4.17, 3.91, 3.57, 2.35, 3.44, 4.2, 1.94, 2.97, 
    3.1, 3.42, 5.04, 5.42, 7.35, 3.28, 3.55, 4.2, 3.79), C = c(-29.04, 
    -28.81, -29.12, -28.91, -29.07, -29.13, -29.16, -29.16, -28.98, 
    -28.81, -28.74, -28.56, -28.58, -28.33, -28.51, -29.49, -30.45, 
    -30.34, -29.91, -30.13, -30.86, -30.3, -30.23, -30.46, -29.69, 
    -29.43, -29.74, -29.75, -29.92, -29.52, -28.44, -28.24, -28.01, 
    -28.68, -28.77, -29.13, -29.13, -29.41, -29, -28.85)), row.names = c(NA, 
40L), class = "data.frame")

Solution

  • One way to achieve your desired result using faceting would be to split your dataframe into two like so:

    1. The first dataframe contains the data by treatment, the second the data by year.
    2. In each of these data frames rename the vars to be plotted on the x-axis to have the same name (I chose ´x). Doing so allows use to have one x-axis for the two different variables. But make sure to convert year or ´Leto to a character.
    3. Add an identifier to each data.frame which could be used for facetting (besides your variable POSKUS).
    4. Splitting the data into two df we need both two geom_jitter and two stat_summary layers.
    5. Finally I added a custom labelled function to facet_wrap to show only the trial labels in the facet strip text.
    library(dplyr)
    library(ggplot2)
    
    d1 <- I2 %>% 
      select(x = SISTEM, Si, POSKUS) %>% 
      mutate(name = "SISTEM", name = factor(name, levels = c("SISTEM", "Leto")))
    
    d2 <- I2 %>% 
      select(x = Leto, Si, POSKUS) %>% 
      mutate(name = "Leto", name = factor(name, levels = c("SISTEM", "Leto")))
    
    base <- ggplot(mapping = aes(x = x, y = Si)) +
      geom_jitter(data = d1, show.legend = FALSE, width = 0.25, color = "black", size = 0.5) +
      stat_summary(data = d1, fun.data = mean_cl_normal, show.legend = FALSE, color = "red", size = 0.3) +
      geom_jitter(data = d2, show.legend = FALSE, width = 0.25, color = "black", size = 0.5) +
      stat_summary(data = d2, fun.data = mean_cl_normal, show.legend = FALSE, color = "red", size = 0.3) +
      labs(
        x = NULL,
        y = "Si (mg / 100 g)"
      ) +
      #theme_classic(base_family = "Palatino Linotype") +
      theme_classic() +
      theme(axis.text = element_text(colour = "black", size = 8), 
            axis.title = element_text(colour = "black", size = 8), 
            axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1)) +
      theme(strip.background = element_blank())
    
    base +
      facet_wrap(~name+POSKUS, nrow = 1, scales = "free_x", labeller = function(d) list(as.character(d$POSKUS)))
    #> Warning: Removed 1 rows containing missing values (geom_segment).
    

    EDIT To have only one label for each trial after changing the order of the variables you could make use of ggh4x:: facet_nested_wrap:

    base +
      ggh4x::facet_nested_wrap(~POSKUS+name, nrow = 1, scales = "free_x", labeller = function(d) list(as.character(d$POSKUS)))
    #> Warning: Removed 1 rows containing missing values (geom_segment).