Search code examples
rggplot2geom-col

Change ggplot bar chart fill colors


With this data:

df <- data.frame(value =c(20, 50, 90), 
                 group = c(1, 2,3))

I can get a bar chart:

df %>% ggplot(aes(x = group, y = value, fill = value)) +
  geom_col() +
  coord_flip()+ 
  scale_fill_viridis_c(option = "C") +
  theme(legend.position = "none")

enter image description here

But I would like to have the colors of those bars to vary according to their corresponding values in value.

I have managed to change them using geom_raster:

ggplot() + 
  geom_raster(aes(x = c(0:20), y = .9, fill = c(0:20)),  
              interpolate = TRUE) +
  geom_raster(aes(x = c(0:50), y = 2, fill = c(0:50)), 
              interpolate = TRUE) +
  geom_raster(aes(x = c(0:90), y = 3.1, fill = c(0:90)),               
              interpolate = TRUE) +
  scale_fill_viridis_c(option = "C") +
  theme(legend.position = "none")

enter image description here

This approach is not efficient when I have many groups in real data. Any suggestions to get it done more efficiently would be appreciated.

I found the accepted answer to a previous similar question, but "These numbers needs to be adjusted depending on the number of x values and range of y". I was looking for an approach that I do not have to adjust numbers based on data. David Gibson's answer fits my purpose.


Solution

  • It does not look like this is supported natively in ggplot. I was able to get something close by adding additional rows, ranging from 0 to value) to the data. Then use geom_tile and separating the tiles by specifying width.

    library(tidyverse)
    
    df <- data.frame(value = c(20, 50, 90),
                     group = c(1, 2, 3))
    
    df_expanded <- df %>%
      rowwise() %>%
      summarise(group = group,
                value = list(0:value)) %>%
      unnest(cols = value)
    
    df_expanded %>%
      ggplot() +
      geom_tile(aes(
        x = group,
        y = value,
        fill = value,
        width = 0.9
      )) +
      coord_flip() +
      scale_fill_viridis_c(option = "C") +
      theme(legend.position = "none")
    

    enter image description here

    If this is too pixilated you can increase the number of rows generated by replacing list(0:value) with seq(0, value, by = 0.1).

    enter image description here