rggplot2

How to use gradient of a color for scale of discrete integers?


I want to use a gradient along a single color (i.e. from light to dark) for a set of integers that can be considered discrete in the sense that there cannot be any fractional values between them.

But if I use a continuous scale then the legend unnecessarily displays colors for the potential fractional values. And if I use a discrete scale then fundamentally different colors are displayed (as opposed to gradient of shades). What to do?

Consider the following chart:

library(ggplot2) 
set.seed(123) 
(df <-rbind(data.frame(x=1:5, y=rnorm(5, 3), age=1),
            data.frame(x=1:5, y=rnorm(5, 5), age=2),
            data.frame(x=1:5, y=rnorm(5, 7), age=3)))

(p <- ggplot(df, aes(x, y, group=age, color=age)) +
   geom_point() + geom_line())

ggplot2 chart.
To get rid of the fractional values I attempted the following, which produced different legends showing unnecessary colors for the in-between values.

p + scale_color_continuous(n.breaks=3) 
p + scale_color_binned()

Legends from continuous scales

If I use a factor then I don't get a gradient. Here are the legends after two attempts.

(q <- ggplot(df, aes(x, y, group=age, color=factor(age, ordered = T))) +
    geom_point() + geom_line())

q + scale_color_discrete()   

legends from discrete scales

How do I get a legend that shows colors only for the discrete values but auto-selects those colors from a gradient of shades (i.e. light to dark) rather than using fundamentally different colors.


Solution

  • To apply a color gradient to the discrete values you can map factor(age) to the color aesthetic as you tried, and use a palette that provides the gradient appearance you're looking for.

    Manually specified palette

    You can create a vector of colors manually, and there are many sources that can help generate a suitable gradient.

    custom_blues <- c("#5E93CF","#21548D","#002650")
    
    p +
      scale_color_manual(values = custom_blues) +
      labs(color = 'Age')
    

    Paletteer

    This package is an interface to a large collection of color palettes.

    library(paletteer)
    
    p +
      scale_color_paletteer_d("beyonce::X40") +
      labs(color = 'Age')
    

    RColorBrewer (Original Example)

    Using the RColorBrewer package was in my original answer. If you like the Paletteer interface, you can still access and apply palettes from this package (e.g. RColorBrewer::Blues)

    library(RColorBrewer)
    
    p +
      scale_color_brewer(palette= "Blues") +
      labs(color = 'Age') +
      theme_bw()
    

    Setup: Data and base plot

    library(ggplot2)
    
    set.seed(123) 
    (df <-rbind(data.frame(x=1:5, y=rnorm(5, 3), age=1),
                data.frame(x=1:5, y=rnorm(5, 5), age=2),
                data.frame(x=1:5, y=rnorm(5, 7), age=3)))
    #>    x        y age
    #> 1  1 2.439524   1
    #> 2  2 2.769823   1
    #> 3  3 4.558708   1
    #> 4  4 3.070508   1
    #> 5  5 3.129288   1
    #> 6  1 6.715065   2
    #> 7  2 5.460916   2
    #> 8  3 3.734939   2
    #> 9  4 4.313147   2
    #> 10 5 4.554338   2
    #> 11 1 8.224082   3
    #> 12 2 7.359814   3
    #> 13 3 7.400771   3
    #> 14 4 7.110683   3
    #> 15 5 6.444159   3
    
    p <- ggplot(df, aes(x, y, group=age, color=factor(age, ordered = TRUE))) +
      geom_point(size = 4) +
      geom_line(linewidth = 2)