How to use specific filling colors when using scale_fill_binned()?

Viewed 796

I would like to use my own filling colors (ex: c("red", "blue", "grey50", "black")) when using function scale_fill_binned() withing a ggplot code. How can I do this?

Here is a minimal reproducible example:

library(tidyverse)

dat <- mtcars %>% 
       group_by(cyl) %>% 
       summarise(n = n(),
                 mean_hp = mean(hp)) %>% 
       ungroup

ggplot(data = dat, aes(x = cyl, y = mean_hp, size = n, fill = n)) +
  geom_point(shape = 21) +
  scale_size_binned(breaks = c(8, 10, 12), guide = guide_bins(show.limits = T)) +
  scale_fill_binned(breaks = c(8, 10, 12), guide = guide_bins(show.limits = T), type = "viridis") +
  labs(x = "Cylinder", y = "Mean hp", fill = "Nb of cars", size = "Nb of cars") +
  theme_minimal()

Here is what the output looks like:

enter image description here

2 Answers

To use this family of functions you need to provide a function that returns a an object with class "ScaleContinuous" "Scale" "ggproto" "gg" (i.e. the equivalent output to scale_fill_viridis_c)!

scale_fill_custom <- function (..., alpha = 1, begin = 0, end = 1, direction = 1, 
  option = "D", values = NULL, space = "Lab", na.value = "grey50", 
  guide = "colourbar", aesthetics = "fill") {
  continuous_scale(aesthetics, scale_name = "custom", 
    palette = scales:::gradient_n_pal(c("red", "blue", "grey50", "black"), 
    values, space), na.value = na.value, 
    guide = guide, ...)
}
ggplot(data = dat, aes(x = cyl, y = mean_hp, size = n, fill = n)) +
  geom_point(shape = 21) +
  scale_size_binned(breaks = c(8, 10, 12), guide = guide_bins(show.limits = T)) +
  scale_fill_binned(breaks = c(8, 10, 12), guide = guide_bins(show.limits = T), 
    type = scale_fill_custom) +
  labs(x = "Cylinder", y = "Mean hp", fill = "Nb of cars", size = "Nb of cars") +
  theme_minimal()

Scatter plot of mtcars showing points filled with custom colours from continuous range

Note that you are using colour as a scale to be translated by the eye into numerically meaningful difference. The colours are interpolated between the manually applied points, so will not actually be your exact colours. If you wish to band your averages by colour it would be preferable to create a factor, then manually apply your theme.

ggplot(data = mutate(dat, n = cut(n, breaks = c(0, 8, 10, 12, 20))), 
  aes(x = cyl, y = mean_hp, size = n, fill = n)) +
  geom_point(shape = 21) +
  scale_size_discrete() +
  scale_fill_manual(values = c("red", "blue", "grey50", "black")) +
  labs(x = "Cylinder", y = "Mean hp", fill = "Nb of cars", size = "Nb of cars") +
  theme_minimal()

Scatter plot of mtcars showing points filled with custom colours from discrete scale

With the comment of @teunbrand, I was able to come up with something.

cols <- c("red", "blue", "grey50", "black")
ggplot(data = dat, aes(x = cyl, y = mean_hp, size = n, fill = n)) +
  geom_point(shape = 21) +
  scale_size_binned(breaks = c(8, 10, 12), guide = guide_bins(show.limits = T)) +
  labs(x = "Cylinder", y = "Mean hp", fill = "Nb of cars", size = "Nb of cars") +
  theme_minimal() +
  binned_scale(aesthetics = "fill", scale_name = "custom", 
               palette = ggplot2:::binned_pal(scales::manual_pal(values = cols)),
               guide = "bins",
               breaks = c(8, 10, 12), limits = c(min(dat$n), max(dat$n)), show.limits = T)

Here is what the output looks like:

enter image description here

Related