# Require basic tidyverse packages ---- library("dplyr") library("tidyr") library("ggplot2") library("colorspace") # Set up colours and basic accessor ---- .acme_colours <- c( red = "#eb3b5a", orange = "#fa8231", yellow = "#f7b731", green = "#20bf6b", topaz = "#0fb9b1", light_blue = "#2d98da", dark_blue = "#3867d6", purple = "#8854d0" ) # This function takes a character or integer index acme_colours <- function(index = NULL, named = FALSE) { # Default to everything if (is.null(index)) { index <- names(.acme_colours) } # This works with integer or character values return_value <- .acme_colours[index] if (!named) { names(return_value) <- NULL } return(return_value) } # Another convenience function acme_colour_names <- function() { names(.acme_colours) } # Example 1 ---- # Make a bad plot with these colours ggplot(mpg) + geom_point(aes(x = displ, y = hwy, colour = as.character(cyl))) + scale_colour_manual(values = acme_colours()) + theme_minimal() ggsave(filename = "bad_plot.png", height = 5, width = 5) # Set up a basic palette ---- acme_palette <- function() { acme_colour_length <- length(acme_colours()) function(n) { stopifnot(n <= acme_colour_length) return(acme_colours(1:n)) } } scale_colour_acme <- function(...) { ggplot2::discrete_scale( aesthetics = "colour", scale_name = "acme", palette = acme_palette(), ... ) } # Example 2 ---- # mpg plot using scale_colour_acme() ggplot(mpg) + geom_point(aes(x = displ, y = hwy, colour = as.character(cyl))) + scale_colour_acme() + theme_minimal() ggsave(filename = "basic_palette.png", width = 5, height = 5) # Automatic palette ---- acme_palette <- function() { acme_colour_length <- length(acme_colours()) function(n) { stopifnot(n <= acme_colour_length) # Shortcut: if n = 1, we can just return the first colour if (n == 1) { return(acme_colours(1)) } # Pick additional colours. Make them as spread out as possible interval_between_picks <- acme_colour_length / n additional_colour_indices <- 1 + (1:(n-1)) * interval_between_picks # Work out which colours to return colour_indices <- c(1, round(additional_colour_indices)) return(acme_colours(colour_indices)) } } # Example 3 ---- # Plot with automatic palette ggplot(mpg) + geom_point(aes(x = displ, y = hwy, colour = as.character(cyl))) + scale_colour_acme() + theme_minimal() ggsave(filename = "auto_palette.png", height = 5, width = 5) # Manual palette ---- acme_palette <- function() { acme_colour_length <- length(acme_colours()) function(n) { stopifnot(n <= acme_colour_length) colour_indices <- if (n == 1) { "red" } else if (n == 2) { c("red", "blue") } else if (n == 3) { c("red", "green", "blue") } else if (n == 4) { c("red", "green", "orange", "light_blue") } # ... etc. etc. else if (n == 8) { c( "red", "topaz", "orange", "light_blue", "yellow", "dark_blue", "green", "purple" ) } return(acme_colours(colour_indices)) } } scale_fill_acme <- function(...) { ggplot2::discrete_scale( aesthetics = "fill", scale_name = "acme", palette = acme_palette(), ... ) } # Example 4 ---- # Plot with the manual palette ggplot(mpg) + geom_point(aes(x = displ, y = hwy, colour = as.character(cyl))) + scale_colour_acme() + theme_minimal() ggsave(filename = "manual_palette.png", height = 5, width = 5) # 4a sales <- read.csv("sales.csv") %>% gather("Product", "Sales", -Year) ggplot(sales) + geom_col(aes(x = Year, y = Sales, fill = Product)) + scale_fill_acme() + coord_flip() + theme_minimal() ggsave(filename = "manual_palette_bars.png", width = 5, height = 5) # Continuous sequential scales ---- scale_colour_acme_c <- function(index = 1, colour_range = 0.75, ...) { low_colour <- acme_colours(index) high_colour <- colorspace::lighten(low_colour, amount = colour_range) ggplot2::scale_colour_gradient( low = low_colour, high = high_colour, ... ) } # Example 5 ---- # Sequential palette plot ggplot(mpg) + geom_point(aes(x = displ, y = hwy, colour = cty)) + scale_colour_acme_c() + theme_minimal() ggsave(filename = "sequential_palette.png", height = 5, width = 5) # Continuous diverging scales ---- scale_colour_acme_div <- function(high_index = 1, low_index = 5, ...) { high_colour <- acme_colours(high_index) low_colour <- acme_colours(low_index) ggplot2::scale_colour_gradient2( low = low_colour, high = high_colour, ... ) } # Example 6 ---- # Diverging palette plot toyota_cars_2008 <- filter(mpg, manufacturer == "toyota", year == 2008) mean_hwy <- mean(toyota_cars_2008$hwy) ggplot(toyota_cars_2008) + geom_vline(xintercept = mean_hwy, linetype = 2) + geom_point(aes(y = model, x = hwy, colour = hwy)) + scale_colour_acme_div(midpoint = mean_hwy) + theme_minimal() ggsave(filename = "diverging_palette.png", height = 5, width = 5)