rggplot2background

How do I add alternating white and grey shading to a plot with categorical variables on the y-axis?


I have looked at this similar question but am struggling to make it work with my code.

Here is the plot that I have created: enter image description here

What I would like to add are alternating white and grey bars (background) behind each species so that it is easier to tell which dot-and-whiskers relates to which species. Similar to this figure from another paper, but with the bars extending fully across the plot (i.e., to the end of the plot or x-axis). Also, in my plot, the dot-and-whiskers are offset because there was too much overlap, so each background bar would have a blue and a red dot-and-whisker.

Source: https://onlinelibrary.wiley.com/doi/full/10.1111/gcb.17178

I've uploaded the dataset to my GitHub page, which can be found here.

And here is the code:

tr_df <-read_csv("treatment_dataframe.csv")

cols <-c("#fa5f2c", "#608cd9")

tr_prot_whisker <-ggplot(tr_df, aes(tr_df$effect_size, species, fill=parameter))+
   geom_vline(xintercept=0, linetype="dashed", color = "grey65", size=1.5) +
  geom_errorbarh(aes(xmin = LCI, xmax = UCI), color = "black", size = 1, height=0.8, 
                 position = position_dodge(width = 1)) +
  geom_point(color ="black",shape=21, stroke = 1, size=5, position = position_dodge(width = 1)) +
  scale_fill_manual(values = cols) +
  scale_x_continuous(limits=c(-10,5), breaks=c(-10,-8,-6,-4,-2,0,2,4))+
  labs(y=NULL, x = expression("Standardized " * beta * " coefficients")) + #\n makes the next word go underneath the first
  theme_classic()+
  theme(axis.line = element_line(colour="black", size=1.3), #because I remove the border of the plot later in this code, this ensures that the axes  
        panel.border = element_blank(), #removes border at top and right side of graph
        legend.position = "none",
        #legend.text=element_text(size=16),
        axis.ticks.length = unit(0.2, "cm"),
        axis.title.x = element_text(size=24, colour="black"), #controls title of x-axis
        axis.text.x  = element_text(size=18, colour="black"), #controls text of the ticks on the x.axis
        axis.title.y=element_text(size=24, colour="black", vjust=2), #controls title of y-axis
        axis.text.y=element_text(size=16, colour="black")) #controls text of the ticks on the y-axis

tr_prot_whisker

EDIT

As requested, here is the output from running dput(tr_df).

structure(list(species = c("American Black Duck", "American Wigeon", 
"Blue-winged Teal", "Canada Goose", "Green-winged Teal", "Mallard", 
"Northern Shoveler", "Pied-billed Grebe", "Red-winged Blackbird", 
"Ring-necked Duck", "Sora", "Swamp Sparrow", "Wood Duck", "American
Black Duck",  "American Wigeon", "Blue-winged Teal", "Canada Goose",
"Green-winged Teal",  "Mallard", "Northern Shoveler", "Pied-billed
Grebe", "Red-winged Blackbird",  "Ring-necked Duck", "Sora", "Swamp
Sparrow", "Wood Duck"), parameter = c("dd",  "dd", "dd", "dd", "dd",
"dd", "dd", "dd", "dd", "dd", "dd", "dd",  "dd", "pt", "pt", "pt",
"pt", "pt", "pt", "pt", "pt", "pt", "pt",  "pt", "pt", "pt"),

effect_size = c(-0.41, -0.69, 1.16, -0.4, 
1.75, -0.58, -0.04, -5.95, -0.21, -2.74, -4.26, 0.17, -2.83, 
0.24, -0.21, 0.57, 0.25, 0.2, -0.53, 0.15, -1.77, 0.31, -0.84, 
0.26, 0.39, -0.08), 

LCI = c(-1.1352, -1.5328, 0.1604, -1.2624, 
0.8092, -1.462, -0.5496, -8.204, -0.7196, -3.7984, -6.5924, -0.2808, 
-4.2412, -0.5048, -1.0136, -0.4296, -0.6908, -0.7016, -1.3924, 
-0.34, -2.8676, -0.0624, -1.5652, -1.1512, -0.0216, -1.3344),

UCI = c(0.3152, 0.1528, 2.1596, 0.4624, 2.6908, 0.302, 0.4696, 
-3.696, 0.2996, -1.6816, -1.9276, 0.6208, -1.4188, 0.9848, 
0.5936, 1.5696, 1.1908, 1.1016, 0.3324, 0.64, -0.6724, 0.6824, 
-0.1148, 1.6712, 0.8016, 1.1744), 

shading = c(0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 
            0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0)), 

row.names = c(NA, -26L), spec = structure(list(
cols = list(species = structure(list(), class = c("collector_character", 
"collector")), parameter = structure(list(), class = c("collector_character", 
"collector")), effect_size = structure(list(), class = c("collector_double", 
"collector")), LCI = structure(list(), class = c("collector_double", 
"collector")), UCI = structure(list(), class = c("collector_double", 
"collector")), shading = structure(list(), class = c("collector_double", 
"collector"))), default = structure(list(), class = c("collector_guess", 
"collector")), delim = ","), class = "col_spec"), 
class = c("spec_tbl_df",  "tbl_df", "tbl", "data.frame"))

Solution

  • geom_tile() lets us specify the centerpoint of the tile (x = 0, y taken from global assignment with species) and make the width be infinite. Then I arrange (in case the data is sorted differently than it plots) and then use distinct to make there only be one observation per species, so that the every-other-row filtering works.

    library(tidyverse)
    ggplot(tr_df, aes(effect_size, species, fill=parameter)) +
            geom_tile(aes(x = 0, width = Inf), fill = "gray95", height = 0.9,
                      data = ~arrange(., species) |> distinct(species) |> 
                              filter(row_number() %% 2 == 0)) +
    # .... [the rest]
    
    

    enter image description here