Skip to content

Instantly share code, notes, and snippets.

@ctesta01
Last active February 3, 2022 17:16
Show Gist options
  • Select an option

  • Save ctesta01/7d4d73f6fc6c353d4da867d9d1a21a37 to your computer and use it in GitHub Desktop.

Select an option

Save ctesta01/7d4d73f6fc6c353d4da867d9d1a21a37 to your computer and use it in GitHub Desktop.
Using consistent color scales across different plots with scale_color_gradient
library(palmerpenguins)
library(purrr)
library(ggplot2)
library(dplyr)
library(patchwork)
# let's say I want to show bill_length_mm across different species (one plot for each species),
# but each plot should have the same color scale
# one common issue is that if you just use scale_color_gradient() or scale_color_brewer(), each
# of your plots will be shown with a color gradient palette that suits the data in that plot --
# with its own unique min/max range.
#
# if we're trying to compare the same variable in multiple plots, it can be important to
# standardize the legend on the color scale.
#
# this is a simple example script showing how to do this with across 3 figures using the
# palmerpenguins dataset, patchwork (for the layout), and purrr (to produce multiple plots in
# functional programming style).
# specify color scale -- in this case i'm using viridis::magma so that
# the color palette should be colorblind friendly.
viridis_5 <- viridis::magma(n=5, end = .8)
high <- viridis_5[4]
low <- viridis_5[2]
# observe range overall
range_observed_length <- range(penguins$bill_length_mm, na.rm=T)
range_observed_depth <- range(penguins$bill_depth_mm, na.rm=T)
# calculate cutpoints
cutpoints <- seq(range_observed_length[1], range_observed_length[2], length.out = 5)
# construct multiple ggplots with the same scale_color_gradient
ggplots <- purrr::map(
unique(penguins$species),
~ filter(penguins, species == .)) %>%
purrr::map(
~ ggplot(., aes(
x = bill_length_mm,
y = bill_depth_mm,
color = bill_length_mm)) +
geom_point() +
expand_limits(x = range_observed_length, y = range_observed_depth) +
scale_color_gradient(
low = low,
high = high,
breaks = cutpoints,
limits = range_observed_length))
# give them each appropriate titles
ggplots[[1]] <- ggplots[[1]] + ggtitle("Bill Length (mm) Relationship to Bill Depth", "Adelie Penguins")
ggplots[[2]] <- ggplots[[2]] + ggtitle("Bill Length (mm) Relationship to Bill Depth", "Gentoo Penguins")
ggplots[[3]] <- ggplots[[3]] + ggtitle("Bill Length (mm) Relationship to Bill Depth", "Chinstrap Penguins")
# create a patchwork layout
ggplots[[1]] + ggplots[[2]] / ggplots[[3]]
# render to image
ggsave("example.png", width = 12, height = 8)
@ctesta01

ctesta01 commented Feb 2, 2022

Copy link
Copy Markdown
Author

example image produced: 3 figures each on the same color palette, even if the extent of the data shown in each is different

@ctesta01

ctesta01 commented Feb 3, 2022

Copy link
Copy Markdown
Author

Here's an example using scale_color_gradient2 –– remember that you have to specify the midpoint argument if it's not 0 in scale_color_gradient2.

library(palmerpenguins)
library(purrr)
library(ggplot2)
library(dplyr)
library(patchwork)

# let's say I want to show bill_length_mm across different species (one plot for each species), 
# but each plot should have the same color scale

# one common issue is that if you just use scale_color_gradient() or scale_color_brewer(), each 
# of your plots will be shown with a color gradient palette that suits the data in that plot -- 
# with its own unique min/max range. 
# 
# if we're trying to compare the same variable in multiple plots, it can be important to 
# standardize the legend on the color scale.
# 
# this is a simple example script showing how to do this with across 3 figures using the 
# palmerpenguins dataset, patchwork (for the layout), and purrr (to produce multiple plots in
# functional programming style).

# specify color scale -- in this case i'm using viridis::magma so that 
# the color palette should be colorblind friendly. 
viridis_5 <- viridis::magma(n=5, end = .8)
high <- viridis_5[4]
mid <- viridis_5[3]
low <- viridis_5[2] 

# observe range overall
range_observed_length <- range(penguins$bill_length_mm, na.rm=T)
range_observed_depth <- range(penguins$bill_depth_mm, na.rm=T)

# calculate cutpoints
cutpoints <- seq(range_observed_length[1], range_observed_length[2], length.out = 5)

# construct multiple ggplots with the same scale_color_gradient 
ggplots <- purrr::map(
  unique(penguins$species),
  ~ filter(penguins, species == .)) %>% 
  purrr::map(
  ~ ggplot(., aes(
    x = bill_length_mm,
    y = bill_depth_mm,
    color = bill_length_mm)) + 
    geom_point() + 
    expand_limits(x = range_observed_length, y = range_observed_depth) + 
    scale_color_gradient2(
      low = low, 
      mid = mid,
      high = high,
      midpoint = mean(range_observed_length),
      breaks = cutpoints,
      limits = range_observed_length))

# give them each appropriate titles
ggplots[[1]] <- ggplots[[1]] + ggtitle("Bill Length (mm) Relationship to Bill Depth", "Adelie Penguins")
ggplots[[2]] <- ggplots[[2]] + ggtitle("Bill Length (mm) Relationship to Bill Depth", "Gentoo Penguins")
ggplots[[3]] <- ggplots[[3]] + ggtitle("Bill Length (mm) Relationship to Bill Depth", "Chinstrap Penguins")

# create a patchwork layout
ggplots[[1]] + ggplots[[2]] / ggplots[[3]]

# render to image
ggsave("example.png", width = 12, height = 8)

example image produced: 3 figures each on the same color palette, even if the extent of the data shown in each is different -- this time also using a mid argument to scale_color_gradient2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment