rggplot2themes

Change theme of ggplot2 based on a category in R


i have the following data frame in R

A tibble: 24 × 4
   answers  Year Categories Satisfaction
   <chr>   <dbl> <chr>             <dbl>
 1 A        2019 Football           46.7
 2 A        2019 Basket             20.7
 3 A        2019 Volley             36.5
 4 A        2020 Football           43.7
 5 A        2020 Basket             21  
 6 A        2020 Volley             31.2
 7 A        2022 Football           49  
 8 A        2022 Basket             17.9
 9 A        2022 Volley             34.2
10 A        2023 Football           33.8

which its structure in R is the following:

df = structure(list(answers = c("A", "A", "A", "A", "A", "A", "A", 
"A", "A", "A", "A", "A", "B", "B", "B", "B", "B", "B", "B", "B", 
"B", "B", "B", "B"), Year = c(2019, 2019, 2019, 2020, 2020, 2020, 
2022, 2022, 2022, 2023, 2023, 2023, 2019, 2019, 2019, 2020, 2020, 
2020, 2022, 2022, 2022, 2023, 2023, 2023), Categories = c("Football", 
"Basket", "Volley", "Football", "Basket", "Volley", "Football", 
"Basket", "Volley", "Football", "Basket", "Volley", "Tennis", 
"Hockey", "Other", "Tennis", "Hockey", "Other", "Tennis", "Hockey", 
"Other", "Tennis", "Hockey", "Other"), Satisfaction = c(46.7, 
20.7, 36.5, 43.7, 21, 31.2, 49, 17.9, 34.2, 33.8, 30.1, 33.2, 
68.7, 68.7, 68.7, 69.7, 70.2, 70.2, 66.8, 72.7, 72.7, 76.1, 75.4, 
75.4)), row.names = c(NA, -24L), class = c("tbl_df", "tbl", "data.frame"
))

i have grouped the plot using ggplot2 as follows and as the picture shows. But I want to change the colours of the background themes.

If it is the A group the theme to be green and if is group B to be red. And then to display from right to left the red and then the green (ie at the left the red one B and at the right the green A). How can i do it in R ?

P2 = ggplot(df, aes(x = Year, y = Satisfaction, color = factor(Categories), group = Categories)) +
  geom_line(aes(color = ifelse(answers == "Unfavorable", "darkred", "forestgreen"))) +
  geom_point(size = 2) +
  facet_grid(Categories ~ answers, scales = "free_y") +
  theme_minimal() +
  labs(
    x = "Year",
    y = "Satisfaction",
    color = "Categories") +
  # theme(axis.text.x = element_text(angle = 45, hjust = 1))+
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        strip.background = element_rect(fill = "lightgrey"), # Add background color to facet labels
        strip.text = element_text(size = 12, face = "bold"), # Enhance facet label text
        panel.spacing = unit(1, "lines")) + # Increase spacing between facets
  geom_text(aes(label = paste(Satisfaction,"%") ), nudge_x = 0.1,color="black")+
  theme(legend.position = "none")
P2

enter image description here


Solution

  • To change the facets' order use the standard trick of coercing the faceting variable to factor with the levels in the order you want.
    And to have a different background color, the fast hack is to add another layer, geom_rect, going from -Inf to Inf. Play with the alpha value at will.

    First I define a new, custom theme

    theme_so_q78904457 <- function(){ 
      theme_minimal(base_size = 10) %+replace%    #
        theme(
          axis.text.x = element_text(angle = 45, hjust = 1),
          strip.background = element_rect(fill = "lightgrey"), # Add background color to facet labels
          strip.text = element_text(size = 12, face = "bold"), # Enhance facet label text
          panel.spacing = unit(1, "lines"),                    # Increase spacing between facets
          legend.position = "none"
        )
    }
    

    Created on 2024-08-23 with reprex v2.1.0


    Plot code

    Note that the fill variable length must be the same as the number of rows in data. That's why I repeat 12 times each value with rep(12L).

    library(ggplot2)
    
    df$answers <- factor(df$answers, levels = sort(unique(df$answers), decreasing = TRUE))
    
    P2 <- ggplot(df, aes(x = Year, y = Satisfaction, color = factor(Categories), group = Categories)) +
      geom_line(aes(color = ifelse(answers == "Unfavorable", "darkred", "forestgreen"))) +
      geom_point(size = 2) +
      geom_text(aes(label = paste(Satisfaction,"%") ), nudge_x = 0.1,color="black")+
      facet_grid(Categories ~ answers, scales = "free_y") +
      labs(
        x = "Year",
        y = "Satisfaction",
        color = "Categories"
      ) +
      theme_so_q78904457()
    
    P2 +
      geom_rect(
        fill = c(A = "green", B = "red") |> rep(each = 12L),
        color = NA,  # removes the rectangles' border
        xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = Inf,
        alpha = 0.05
      )
    

    Created on 2024-08-23 with reprex v2.1.0


    Edit

    To group the panels by color, add the following code prior to plotting. Once again, the trick is to set the factor levels by the wanted order.

    library(dplyr)
    #> 
    #> Attaching package: 'dplyr'
    #> The following objects are masked from 'package:stats':
    #> 
    #>     filter, lag
    #> The following objects are masked from 'package:base':
    #> 
    #>     intersect, setdiff, setequal, union
    
    df %>%
      select(answers, Categories) %>%
      unique() %>%
      arrange(answers) %>%
      pull(Categories) -> cat_levels
    
    df$Categories <- factor(df$Categories, levels = cat_levels)
    

    Created on 2024-08-23 with reprex v2.1.0