Search code examples
rggplot2colorbargeom-bargeom-col

Change order in y-direction of stacked bar chart in ggplot2 as indicated by sequence


using this reproducible example tibble

 # install and attach packages
if (!require("pacman")) install.packages("pacman")
pacman::p_load(tidyverse, dplyr, ggplot2)  

# Create example dataset (tib1)
tib1 = tibble(location = c("loc1", rep(c("loc1", "loc2"), 8), rep("loc2",2)),
              drill = sort(c(1, rep(1:4, 4),4, 4)),
              thickness = c(20, 34, 99, 67, 29, 22, 53, 93, 64, 98, 76, 42, 49, 23, 11, 74, 
                            19, 50, 40),
              soiltype = c("gravel", rep( c("sand", "loam", "clay"),5 ), "sand", "gravel", "clay")) %>% 
  arrange(location, drill)

tib1 <- tib1 %>% group_by(location, drill) %>% 
  mutate(order = row_number(),
         bottom_of_layer = cumsum(thickness),
         top_of_layer = bottom_of_layer-thickness) %>% 
  ungroup %>% 
  select(location, drill, bottom_of_layer, top_of_layer, thickness, soiltype, order)

tib1

I would like to plot a cross section of a soil. I attempt to do this with geom_bar or geom_col from ggplot2. In the example data there is an order given (1:3). I would like the bars to be stacked in the order as specified in the "order column". So this would implicate that the bar where:

  • location == "loc2" and drill == 4 should be colored in the order (from top to bottom):

orange (loam) - yellow (sand) - grey(gravel) - seagreen (clay)

AND

  • location == "loc1" and drill == 1 should be colored in the order (from top to bottom):

grey(gravel) - yellow (sand) - seagreen (clay)

While the other stacked bars remain in the same order & color.

In other words: I need the colors in the stacked bar to vary along with the sequence as indicated in the column "order".

colpalette = c("darkseagreen3", "darkgrey", "#FF9966", "palegoldenrod")

ggplot(tib1,
       aes(x = drill))+
  geom_bar(aes(fill = soiltype, y = -thickness),
           stat = "identity")+
  scale_fill_manual(values = colpalette)+
  facet_wrap(vars(location), scale = "free_x")+
  xlab("drill")+
  ylab("depth (cm)")+
  ggtitle("how to plot the bars in the 'preferred order'? ",
          subtitle = "the order of loc2 and drill == 4 should be: loam-sand-gravel-clay")+
  theme_minimal()

cross section of soil profile with geom_bar

Comparable, but slightly different issues are:

Order of stacked bars ggplot2 - Soil profile and Change the order of Stacked Bar Chart in ggplot2

I wonder whether the thing I am asking for is possible at all in ggplot as:

Bar charts are automatically stacked when multiple bars are placed at the same location. The order of the fill is designed to match the legend.

So I might have to search for an alternative option... unless anyone has a hack? Any help, answers, alternative plotting options, links are appreciated :) I prefer ggplot2 if possible.


Solution

  • geom_col and geom_bar are not the appropriate ggplot2 functions when you want the fill or color to vary along with the sequence as the fill and or color are grouped in one bar. geom_rect is able to seperate two layer of fill or color within a bar/rectangle.

    p1 <- ggplot(tib1)+
      geom_rect(data = tib1,
                aes(x = NULL, NULL, 
                    xmin = drill-0.45, xmax = drill+0.45,
                    fill = soiltype,
                    ymin = -bottom_of_layer, ymax = -top_of_layer))+
      scale_fill_manual(values = colpalette)+
      facet_wrap(vars(location))+
      xlab("drill")+
      ylab("depth (cm)")+
      ggtitle("how to plot the bars in the 'preferred order'? ",
              subtitle = "the order of loc2 and drill == 4 should be: loam-sand-gravel-clay")+
      theme_minimal()
    
      # Optional:
      # Adding in text the column called "order"
    p1 + geom_text(aes(x = drill,
                    y = (bottom_of_layer + top_of_layer)/-2,
                    label = order))
    

    This is also possible with discrete x-axis values: how do I use geom_rect with discrete axis values

    Soil profile plot with geom_rect