Author

Andrew Siefert

A little color theory

Three components of color (HCL space):

Code
library(colorspace)

swatchplot(
  "Hue (type of color)" = hex(polarLUV(H = seq(0, 300, length.out = 10), C = 50, L = 70)),
  "Chroma (colorfulness)" = hex(polarLUV(H = 0, C = seq(0, 100, length.out = 10), L = 65)),
  "Luminance (brightness)"  = hex(polarLUV(H = 260, C = 25, L = seq(90, 10, length.out = 10)))
)

  • Captures human perceptual axes well
  • Perceptually uniform – a unit step anywhere in HCL space produces a constant perceptual change in color

colorspace package lets you create and explore palettes based on trajectories in HCL space.

Hue

  • Type of color (red, blue, green, etc.)
  • Not perceived as ordered
  • Values go from 0 to 360 (color wheel)
Code
library(colorspace)

hue <- polarLUV(H = seq(0, 300, 75), C = 60, L = 65)
hue
      L  C   H
[1,] 65 60   0
[2,] 65 60  75
[3,] 65 60 150
[4,] 65 60 225
[5,] 65 60 300
Code
hex(hue)
[1] "#DF8396" "#AF9E3F" "#28B37F" "#2FAAD0" "#C787D3"
Code
swatchplot(hex(hue))
text(x = seq(0.1, 1, 0.2), y = 0.05, labels = seq(0, 300, 75))

Chroma

  • Purity or colorfulness of the color
  • Perceived as ordered
  • Ranges from 0 (gray) to maximum that varies with hue and luminescence
Code
chroma <- polarLUV(H = 0, C = seq(0, 100, 25), L = 65) 
swatchplot(hex(chroma))
text(x = seq(0.1, 1, 0.2), y = 0.05, labels = seq(0, 100, 25))

Luminance

  • Brightness
  • Perceived as ordered
  • Ranges from 0 (black) to 100 (white)
Code
lum <- polarLUV(H = 260, C = 25, L = seq(90, 10, -20))
swatchplot(hex(lum))
text(x = seq(0.1, 1, 0.2), y = 0.05, labels = seq(90, 10, -20))

Type of palettes

  • Qualitative: categorical information
  • Sequential: ordered/numerical information (high to low)
  • Diverging: ordered/numeric information around a central neutral value

Qualitative palettes

  • Distinguishes categories by a sequence of hues while keeping chroma and luminance constant
  • Best to use equidistant sequence of hues spanning the color wheel
  • Use lighter colors (moderate chroma, high luminance) for shading areas (e.g., bar plots, maps)
  • Use more flashy colors (high chroma) for points and lines

Qualitative palettes in colorspace:

Code
hcl_palettes(type = "qualitative", plot = T)

Create a palette using qualitative_hcl():

Code
my_qual <- qualitative_hcl(6, palette = "Set3")
my_qual
[1] "#FFB3B5" "#DAC584" "#95D69A" "#61D8D6" "#AAC8FC" "#F1B2EE"
Code
demoplot(my_qual)

Code
# plot palette in HCL space
hclplot(my_qual)

Sequential palettes

  • Codes numeric values by sequence of increasing or decreasing luminance
  • Without chroma (c = 0), corresponds to grayscale
  • Use larger range of luminance if you are plotting more values
  • Can also vary chroma and/or hue to better distinguish colors
Code
hcl_palettes("sequential (single-hue)", n = 7, plot = TRUE, nrow = 6)

Code
hcl_palettes("sequential (multi-hue)", n = 7, plot = TRUE)

Code
seq9 <- sequential_hcl(10, palette = "Greens 3")
demoplot(seq9, "heatmap")

Code
hclplot(seq9)

Code
specplot(seq9, type = "o")

Diverging palettes

  • Combination of two sequential palettes with different hues in the left and right “arms”
  • Neutral central value has zero chroma
  • Chroma and luminance trajectories are mirrored in the two arms
Code
hcl_palettes("diverging", n = 7, plot = TRUE, nrow = 10)

Code
div12 <- diverging_hcl(12, palette = "Blue-Red")
demoplot(div12)

Code
hclplot(div12)

Code
specplot(div12, type = "o")

Using colorspace with ggplot2

Scales are named via the scheme:

scale_<aesthetic>_<datatype>_<colorscale>(palette = <Palette>)

  • <aesthetic> is the name of the aesthetic (fill, color, etc.)
  • <datatype> is the type of variable plotted (discrete or continuous)
  • <colorscale> sets the type of color scale used (qualitative, sequential, or diverging)
  • <Palette> is the name of the palette (e.g., "Dark 3", "Blue-Red")
Code
library(ggplot2)

ggplot(iris, aes(x = Sepal.Length, fill = Species)) + 
  geom_density(alpha = 0.6) + 
  scale_fill_discrete_qualitative(palette = "Dark 3")

Color blindness

colorblindr package simulates how a color palette will look to people with common forms of color blindness.

Make a figure using default ggplot color scale:

Code
df <- data.frame(x = c("a", "b", "c", "d"), y = c(3, 4, 1, 2))
bars <- ggplot(df, aes(x, y, fill = x)) + 
  geom_bar(stat = "identity") + 
  labs(x = NULL, y = NULL) +
  theme(legend.position = "none")
bars

Look at color-vision-deficiency simulations:

Code
library(colorblindr)

cvd_grid(bars)

A discrete color scale that works better for people with color blindness is the Okabe Ito palette.

Code
palette_OkabeIto
[1] "#E69F00" "#56B4E9" "#009E73" "#F0E442" "#0072B2" "#D55E00" "#CC79A7"
[8] "#999999"
Code
swatchplot(palette_OkabeIto)

Code
bars2 <- bars + scale_fill_OkabeIto()
bars2

Code
cvd_grid(bars2)

Some useful palettes

viridis

viridis color scales are designed to have good perceptual properties, work well for people with colorblindness, and print well in gray scale.

Code
library(viridis)

viridis(10)
 [1] "#440154FF" "#482878FF" "#3E4A89FF" "#31688EFF" "#26828EFF" "#1F9E89FF"
 [7] "#35B779FF" "#6DCD59FF" "#B4DE2CFF" "#FDE725FF"
Code
swatchplot(
  "viridis" = viridis(10),
  "magma" = viridis(10, option = "magma"),
  "inferno" = viridis(10, option = "inferno"), 
  "cividis" = viridis(10, option = "cividis"), 
  "rocket" = viridis(10, option = "rocket"),
  "mako" = viridis(10, option = "mako")
)

The viridis scales are available in ggplot2 using using scale_fill_viridis_d() and scale_fill_viridis_c().

Discrete viridis scale:

Code
bars + scale_fill_viridis_d()

Continuous viridis scale:

Code
erupt <- ggplot(faithfuld, aes(waiting, eruptions, fill = density)) +
  geom_raster()

erupt

Code
erupt + scale_fill_viridis_c(option = "magma")

ColorBrewer

ColorBrewer scales are designed to work well for maps, but are also good for other types of data. They are available in the RColorBrewer package:

Code
library(RColorBrewer)

display.brewer.all()

Most palettes are colorblind friendly.

Code
display.brewer.all(colorblindFriendly = T)

You can construct a palette using brewer.pal():

Code
brewer.pal(9, name = "PuBu")
[1] "#FFF7FB" "#ECE7F2" "#D0D1E6" "#A6BDDB" "#74A9CF" "#3690C0" "#0570B0"
[8] "#045A8D" "#023858"
Code
display.brewer.pal(10, name = "PuBu")

ColorBrewer scales are also built into ggplot2:

  • scale_color_brewer() and scale_fill_brewer() for discrete scales
  • scale_color_distiller() and scale_fill_distiller() for continuous scales
Code
bars + scale_fill_brewer(palette = "Set2")

Code
erupt + scale_fill_distiller(palette = "RdPu")

scico

scico includes 39 palettes designed for scientific data visualization. They have good perceptual properties and are colorblind safe.

Code
library(scico)

scico_palette_show()

Code
scico(20, palette = "lapaz") |> swatchplot()

Code
erupt + scale_fill_scico(palette = "davos")

Paletteer

The paletteer package provides a unified interface to color scales from many packages.

Code
library(paletteer)

paletteer_d("nationalparkcolors::BryceCanyon", 5)
<colors>
#E39B38FF #C7D8C8FF #B6BDCCFF #BFC4C5FF #9B593FFF 
Code
paletteer_c("scico::devon", 10)
<colors>
#2C194CFF #283467FF #265085FF #3568ACFF #6181D0FF #979AE6FF #B9B2F1FF #D0CCF4FF #E7E4FAFF #FFFFFFFF 
Code
bars + scale_fill_paletteer_d("wesanderson::FantasticFox1")

Manual scales

You can set colors manually in ggplot2 using scale_color_manual() and scale_fill_manual().

Code
bars + scale_fill_manual(values = c("forestgreen", "goldenrod", "firebrick", "cornflowerblue"))

Here are Erika’s cheat sheets for ColorBrewer scales:

Code
bars + scale_fill_manual(values = c("#7FC97F", "#BEAED4", "#FDC086", "#FFFF99"))