Skip to content
R for the Rest of Us Logo

How to make your own color palettes in ggplot

David Keyes David Keyes
January 23rd, 2023

One of the great things about creating data viz with ggplot is that you can create color palettes that match your or your clients' branding. We've written about how we do this in our consulting work. But the way we work is fairly complicated and I was asked recently for a simpler solution to making custom ggplot color palettes.

I recorded a video to show how to make three different types of palettes

  • Qualitative (i.e. categorical)

  • Sequential (going from a low to a high value)

  • Diverging (going from low to high with a midpoint)

As you'll see in the video, there are a few steps to this process. I begin by defining colors that I want to use:

# Define Colors -----------------------------------------------------------

ga_purple <- "#8359AB"
ga_yellow <- "#FFDE39"
ga_gray <- "#827C78"
ga_blue <- "#49B8F1"
ga_brown <- "#B88262"
ga_pink <- "#DC458E"

Qualitative Color Scale

To make a qualitative color scale, I used the colors I defined in combination with the scale_color_manual() function.

# Qualitative -------------------------------------------------------------

scale_color_ga_qualitative <- function() {
  
  scale_color_manual(values = c(ga_blue, 
                                ga_pink, 
                                ga_yellow, 
                                ga_purple, 
                                ga_gray, 
                                ga_brown))
  
}

Sequential Color Scale

Next, I made a sequential color scale. I adapted the scale_fill_gradient() function to make this function.

scale_fill_ga_sequential <- function(low_color = ga_yellow, 
                                     high_color = ga_purple) {
  
  scale_fill_gradient(low = low_color, 
                      high = high_color)
  
}

Diverging Color Scale

Finally, I made a diverging color scale. To do this, I adapted the scale_fill_gradient2() function, which gives me the ability to set a medium color, in addition to the high and low colors.

scale_fill_ga_diverging <- function(low_color = ga_yellow, 
                                    medium_color = "white",
                                    high_color = ga_pink) {
  
  scale_fill_gradient2(low = low_color, 
                       mid = medium_color,
                       high = high_color)
  
}

Full Code

I've included the full code used in the video below. You can see where I get the data for the map of North Carolina that I use and run the code yourself to see how it works.

# Load Packages -----------------------------------------------------------

library(tidyverse)

# Define Colors -----------------------------------------------------------

ga_purple <- "#8359AB"
ga_yellow <- "#FFDE39"
ga_gray <- "#827C78"
ga_blue <- "#49B8F1"
ga_brown <- "#B88262"
ga_pink <- "#DC458E"


# Qualitative -------------------------------------------------------------

scale_color_ga_qualitative <- function() {
  
  scale_color_manual(values = c(ga_blue, 
                                ga_pink, 
                                ga_yellow, 
                                ga_purple, 
                                ga_gray, 
                                ga_brown))
  
}

palmerpenguins::penguins %>%
  ggplot() +
  geom_point(aes(x = bill_length_mm, 
                 y = flipper_length_mm,
                 color = island)) +
  labs(title = "Palmer Penguins", 
       subtitle = "Look at them go!",
       x = "Bill length",
       y = "Flipper length") +
  theme_minimal() +
  scale_color_ga_qualitative()


# Download Data -----------------------------------------------------------

library(tigris)

# Downloaded from https://github.com/tonmcg/US_County_Level_Election_Results_08-20
presidential_returns_by_county <- read_csv("https://github.com/tonmcg/US_County_Level_Election_Results_08-20/raw/master/2020_US_County_Level_Presidential_Results.csv")

# Done with tigris package
us_counties <- counties()

# Merge datasets
nc_presidential_returns_by_county <- us_counties %>% 
  left_join(presidential_returns_by_county,
            by = c("GEOID" = "county_fips")) %>% 
  filter(state_name == "North Carolina") %>% 
  mutate(county_name = str_remove(county_name, " County")) %>% 
  select(county_name, contains("votes"), per_point_diff) 

# Sequential --------------------------------------------------------------

scale_fill_ga_sequential <- function(low_color = ga_yellow, 
                                     high_color = ga_purple) {
  
  scale_fill_gradient(low = low_color, 
                      high = high_color)
  
}

nc_presidential_returns_by_county %>% 
  ggplot(aes(fill = total_votes)) +
  geom_sf() +
  theme_void() +
  scale_fill_ga_sequential()

nc_presidential_returns_by_county %>% 
  ggplot(aes(fill = total_votes)) +
  geom_sf() +
  theme_void() +
  scale_fill_ga_sequential(low_color = ga_purple,
                           high_color = ga_yellow)


# Diverging ---------------------------------------------------------------

scale_fill_ga_diverging <- function(low_color = ga_yellow, 
                                    medium_color = "white",
                                    high_color = ga_pink) {
  
  scale_fill_gradient2(low = low_color, 
                       mid = medium_color,
                       high = high_color)
  
}

nc_presidential_returns_by_county %>% 
  ggplot(aes(fill = per_point_diff)) +
  geom_sf() +
  theme_void() +
  scale_fill_ga_diverging()

A Couple Caveats

This post has shown how to make custom color scales. What I haven't done is talked about choosing good colors for you color scales. If you want to read more on that, check out:

The other important thing to note is that it's important to consider colorblindness when creating color palettes. Again, to keep things focused, I haven't done that in this blog post. However, there is a great R package called colorblindr to help you ensure your custom ggplot color palettes are accessible to all users.

Good luck making your own custom ggplot color palettes!

Let us know what you think by adding a comment below.

You need to be signed-in to comment on this post. Login.