Search code examples
rggplot2colorsbar-chart

Bar plot with gradual colors and with bars of the same length in R


I need to make a barplot with gradual colors from green to red. I have two variables: the first variable takes values between 0.2 and 0.61, the second variable takes values between 0.1 and 0.41. I wrote the following code:

d <- data.frame(x = 1:2, y= c (0.61, 0.41))
vals <- lapply(d$y, function(y) seq(0.1, y, by = 0.0001))
y <- unlist(vals)
mid <- rep(d$x, lengths(vals))
d2 <- data.frame(x = mid - 0.4,
             xend = mid + 0.4,
             y = y,
             yend = y)

ggplot(data = d2, aes(x = x, xend = xend, y = y, yend = yend, color = y)) +
      geom_segment(size = 2) + theme(plot.title = element_text(hjust = 0.5, size=20),legend.text=element_text(size=13))+
      scale_color_gradient2(low = "green", mid = "yellow", high = "red", 
                    midpoint = .35)+ 
      theme(axis.text.y=element_blank(),  
            axis.ticks.y=element_blank(), 
            panel.background = element_blank(),
            axis.line.x = element_line(color="black", size = 1),
            axis.line.y = element_line(color="black", size = 1),
            axis.text.x=element_text(size=15,hjust=0.1))+ylab("")+xlab("")+
      scale_y_continuous(breaks = c(0.1, .35,0.61), 
                 labels = c('A ','B ','C '), limits = c(0.1, .61))+coord_flip()

However, it is not the result I want. I would like the bars to have the same length. In particular, I would like the first bar at the top to reach C with the color orange. Also, I would like the second bar at the bottom to have a lighter green color since in A the first variable takes value 0.2 (and not 0.1).

I hope someone can help me! Thank you for your cooperation.


Solution

  • At the moment, the colours and the length of the bars are mapped to the same variable. I think you need to separate these out. The colour should be some re-scaled, transformed version of the x-coordinates that create the bars.

    A more generic example, using bars between 0 and 1, and data for X and Y in different ranges:

    library(tidyverse)
    plot_data <- tibble(
      x = rep(seq(0, 1, length.out = 1000), 2),
      xend = rep(seq(0, 1, length.out = 1000), 2),
      y = rep(rep(-1, 1000), 2),
      yend = rep(rep(1, 1000), 2),
      variable = c(rep("X", 1000), rep("Y", 1000)),
      col = c(seq(0.2, 0.6, length.out = 1000), seq(0.3, 0.9, length.out = 1000)),
    )
    
    plot_data |> 
      ggplot() +
      geom_segment(mapping = aes(x = x, 
                                 xend = xend, 
                                 y = y, 
                                 yend = yend,
                                 colour = col)) +
      facet_wrap(~variable, ncol = 1) +
      scale_x_continuous(breaks = c(0, 0.5, 1), 
                         labels = c('A', 'B', 'C')) +
      scale_color_gradient2(low = "green",
                            mid = "yellow",
                            high = "red", 
                            midpoint = 0.5,
                            limits = c(0, 1))+ 
      theme(strip.background = element_blank(),
            legend.position = "none")
    
    

    enter image description here

    You'll need to be careful with the legend, to make sure the values make sense (or just use low, medium, high labels instead)