jtanman
jtanman

Reputation: 684

ggplot Color by factor and gradient

I'm trying to draw a plot that colors on two variables (a factor and an intensity). I would like each factor to be a different color, and I want the intensity to be a gradient between white and that color.

So far I've used techniques like facetting on the factor, setting color to be the interaction between the two variables, and setting color to the factor and alpha to intensity to approximate what I would like. However, I still feel like a gradient between white and the full color on one plot would represent this best.

Does anyone know how to do this without custom creating all of the color gradients and just setting them? In addition, is there a way to do it such that the legend works as if the graph was using color and alpha versus listing all of the colors as it does when setting color to the interaction?

So far I've tried:

ggplot(diamonds, aes(carat, price, color=color, alpha=cut)) +
  geom_point()

ggplot(diamonds, aes(carat, price, color=interaction(color, cut))) +
  geom_point()

ggplot(diamonds, aes(carat, price, color=color)) +
  geom_point() +
  facet_wrap(~cut)

What I'm trying to achieve is something that looks most like the graph using alpha, but instead of transparency, I would like a gradient between white and that color. In addition, I would like the legend to look like the one using color and alpha rather than the legend from for example the interaction plot.

Upvotes: 2

Views: 2164

Answers (1)

yake84
yake84

Reputation: 3236

The approach I usually use is to manipulate the factor values so I can plug them into the hcl() function.

First, some raw data:

library(tidyverse)

raw_data <-
  diamonds %>% 
  filter(price < 500, color %in% c("E", "F", "G")) %>% 
  mutate(
    factor = factor(color),
    intensity = cut,
    interaction = paste(factor, intensity)
  )

Next use this kind of wrangling to get hex colors:

color_values <-
  raw_data %>%
  distinct(factor, intensity, interaction) %>%
  arrange(factor, intensity) %>%
  mutate(
    interaction = fct_inorder(interaction),
    # get integer position of factors
    factor_int = as.integer(factor) - 1,
    intensity_int = as.integer(intensity),
    # create equal intervals for color, adding in some padding so we avoid extremes of 0, 1
    hue_base = factor_int / (max(factor_int) + 0.5),
    light_base = 1 - (intensity_int / (max(intensity_int) + 2)),
    # using ^^^ to feed into hcl()
    hue = floor(hue_base * 360),
    light = floor(light_base * 100),
    # final colors
    hex = hcl(h = hue, l = light)
  )

color_values %>% filter(intensity == "Good")
#  factor intensity interaction factor_int intensity_int hue_base light_base   hue light hex    
#  <ord>  <ord>     <fct>            <dbl>         <int>    <dbl>      <dbl> <dbl> <dbl> <chr>  
# E      Good      E Good               0             2      0        0.714     0    71 #D89FA9
# F      Good      F Good               1             2      0.4      0.714   144    71 #81BA98
# G      Good      G Good               2             2      0.8      0.714   288    71 #BDA4D2

Plot it:

ggplot(df, aes(x, y, color = interaction)) +
  geom_count() +
  facet_wrap(~factor) +
  scale_color_manual(
    values = color_values$hex,
    labels = color_values$interaction
  ) +
  guides(color = guide_legend(override.aes = list(size = 5)))

enter image description here

Upvotes: 5

Related Questions