Dot chart with two different gradients

How to use multiple colour scales in ggplot with {ggnewscale}

For week 23 of Tidy Tuesday the chart I wanted to make required two colour scales. For context the dataset detailed pride sponsors that also contributed to anti-LGBTQ+ politicians. TL;DR I wanted to make some rainbows with rainbow colours if the company made the HRC business pledge and a neutral colour for the companies that hadn’t.

I could use scale_colour_gradientn() for the colour rainbows but needed a solution for the neutral rainbows. I probably could have hacked it together by assigning a colour to each line, but fortunately, I found the {ggnewscale} package by Elio Campitelli that allows you to use two scales. The plot below is the final product. You can find the code on Git.

I think {ggnewscale} is pretty neat and thought it was worth sharing.

What does {ggnewscale} do exactly?

It allows you to apply multiple colour scales to a ggplot. You do this by

  • First fitting one set of geoms and a scale
  • Insert the function new_scale_colour() or new_scale_fill()
  • Fit another set of geoms with a new scale

The new_scale_*() functions essentially partition the geoms that you need under each scale.


I’ll demonstrate. Let’s set up some data first.


df <- bind_rows(
  "group1" = tibble(x = runif(2000)),
  "group2" = tibble(x = runif(2000)),
  .id = "group"
# A tibble: 4,000 × 2
   group      x
   <chr>  <dbl>
 1 group1 0.207
 2 group1 0.102
 3 group1 0.817
 4 group1 0.321
 5 group1 0.371
 6 group1 0.406
 7 group1 0.730
 8 group1 0.673
 9 group1 0.735
10 group1 0.358
# … with 3,990 more rows

I’ve taken 2000 random draws from a uniform distribution for two different groups. We’ll apply a colour gradient to x.

df |> 
  ggplot() +
    aes(x, group, colour = x), 
    size = 8, alpha = 0.5) +
  scale_colour_gradientn(colours = c("purple", "orange")) +
    colour = "Purple-Orange", 
    y = "Group"

Both groups get the same colour scale applied, as per usual. To treat group1 and group2 differently and apply a different colour scale to each we use the new_scale_colour() function.


df |> 
  ggplot() +
  # apply the purple-orange gradient to group 1
    aes(x, group, colour = x), 
    filter(df, group == "group1"), 
    size = 8, alpha = 0.5) +
  scale_colour_gradientn(colours = c("purple", "orange")) +
  labs(colour = "Purple-Orange") +
  # start a new scale
  new_scale_colour() +
  # apply the black-grey gradient to group 2
    aes(x, group, colour = x), 
    filter(df, group == "group2"), 
    size = 8, alpha = 0.5) +
  scale_colour_gradientn(colours = c("black", "grey80")) +
    colour = "Black-Grey",
    y = "Group")

Done! There are a few ways to do this but this is the most convenient that I have found. It’s also neat that you can easily change the legend title to correspond to each palette.

This is simple to do for only 2 groups. For many groups it becomes a bit more arduous and may be worth trying to functionalise the geoms. Although having any more than two groups will start to look like someone vomited Skittles.

Follow me on social media: