D.4 Using color packages
Most packages that primarily deal with visualizations — like ggplot2, lattice, or plotly — provide their own color palettes. To reach beyond the 657 predefined colors of R and the color palettes included in grDevices, the primary resource are packages that provide additional — and typically more specialized — color support.
There is a large number of R packages that provide dedicated color support (i.e., define colors and color scales, and corresponding functions) for all means and purposes. As a consequence, many users of R never define a new color palette, but use the color palettes provided by others. However, to choose nice colors, we have to know which options exist and how they can be chosen and compared. As choosing colors is not just an art, but also a matter of taste, we merely mention some personal preferences in this section.
The colors at http://colorbrewer2.org (Brewer, 2019) were primarily designed to color maps. Beyond cartography, the vibrant color palettes are widely used in the R community, thanks to the popular RColorBrewer package (Neuwirth, 2014) and their integration into the ggplot2 package (Wickham et al., 2021).
Actually, unless you happen to need very special colors, RColorBrewer provides nice and useful color palettes that are sufficient for most purposes.
library(RColorBrewer) # load package
The following command prints all color palettes included in RColorBrewer:
The color scales of the viridis package (Garnier, 2018a) were specifically designed to be perceptually-uniform, both in regular form and when converted to black-and-white.
Its color palettes
inferno can also be perceived by readers with the most common form of color blindness, and the
cividis scale is even suited for people with color vision deficiency.
library(viridis) # load package <- y <- seq(-8*pi, 8*pi, len = 40) x <- sqrt(outer(x^2, y^2, "+")) r filled.contour(cos(r^2) * exp(-r/(2*pi)), axes = FALSE, color.palette = viridis, asp = 1)
<- y <- seq(-6*pi, 6*pi, len = 36) x <- sqrt(outer(x^2, y^2, "+")) r filled.contour(cos(r^2) * exp(-r/(2*pi)), axes = FALSE, color.palette = inferno, asp = 1)
In recent versions of ggplot2, the viridis scales are integrated and can be used by specifying
scale_color_viridis_c() (for continuous color scales) and
scale_fill_viridis_d() (for discrete color scales).
(See also Chapter 12.3 Using a Colorblind-Friendly Palette in the R Graphics Cookbook.)
The viridisLite package (Garnier, 2018b) is a simpler version of the viridis package and sufficient for most purposes:
library(viridisLite) # load package <- viridis(n = 10) vir_10 seecol(vir_10, col_brd = "white", lwd_brd = 4, title = "Example of a viridis color palette (n = 10)", pal_names = paste0("viridis_", 1:10))
The following functions each define a color scale of
<- 20 # number of colors n # define 5 different color scales (n colors each): <- viridis(n) v1 <- magma(n) v2 <- inferno(n) v3 <- plasma(n) v4 <- cividis(n) v5 # See and compare color scales: seecol(list(v1, v2, v3, v4, v5), col_brd = "white", lwd_brd = 4, title = "Various viridis color palettes (n = 20)", pal_names = c("v1: viridis", "v2: magma", "v3: inferno", "v4: plasma", "v5: cividis"))
?viridisLite::viridis for additional information.
Another option for obtaining perceptually ordered and uniform color palettes are the Scientific colour maps by Fabio Crameri (F. Crameri, 2018). They are provided in many different formats — implemented by the scico package in R — friendly to people with color vision deficiency, and still readable in black-and-white print.
Finally, the dichromat package focuses on palettes for color-impaired viewers and allows simulating the effects of different types of color-blindness.
Please note: As one of the authors of the unikn package, I cannot help thinking that it is indispensable for working with colors. However, many people appear to live quite happy and colorful lives without ever needing this package.
Besides providing a range of pre-defined color palettes, the package provides some color functions that are generally useful:
seecol()function allows a quick and easy inspections of color palettes. It has two distint modes, depending on the type of its first argument
When called with a (single) color palette, it allows seeing (or printing the details of) a particular color palette;
When called with a list of (several) color palettes or a recognized keyword, it allows comparing multiple color palettes.
Here are examples for seeing a single color palette:
library(unikn) # load package seecol(pal = pal_unikn) # see/print details of a particular color palette
and for comparing several color palettes:
seecol(pal = "all") # compare all available color palettes
usecol()function makes creating new and modifying existing color palettes very easy:
<- usecol(pal = c(Karpfenblau, "white", Peach), n = 15) # define color palette from 3 colors mix_1 <- usecol(pal = c(rev(pal_seeblau), "white", pal_pinky)) # combining 2 color palettes mix_2 <- usecol(pal = c(rev(pal_bordeaux), "white", pal_petrol), n = 15) # mix and extend color palettes mix_3 # Show and compare custom color palettes: seecol(list(mix_1, mix_2, mix_3), col_brd = "white", lwd_brd = 4, title = "Comparing palettes mixed from unikn colors", pal_names = c("mix_1", "mix_2", "mix_3"))
usecol() function also provides a wrapper for using and modifying (pre-defined or newly created) color palettes in graphs:
<- y <- seq(-8*pi, 8*pi, len = 40) x <- sqrt(outer(x^2, y^2, "+")) r filled.contour(cos(r^2) * exp(-r/(2*pi)), axes = FALSE, col = usecol(mix_2, n = 20), asp = 1)
Even when not using the color palettes of the University of Konstanz, the
seecol() functions are often useful, as they also work with the color palettes provided by other packages.
For instance, we can use the
seecol() function to compare (and modify) sets of color palettes from different packages.
In the following example, we first create 12 color palettes from three packages:
four color palettes from
hcl.pals() of grDevices (R Core Team, 2021),
four color palettes from RColorBrewer (Neuwirth, 2014), and
four color palettes from yarrr (Phillips, 2017).
We then uses the
seecol() function to view and compare all 12 color palettes:
# (a) get some HCL palettes (assuming R version 3.6.0+): # hcl.pals() shows the names of all HCL palettes <- hcl.colors(n = 10, palette = "Fall") hcl_1 <- hcl.colors(n = 10, palette = "Geyser") hcl_2 <- hcl.colors(n = 10, palette = "Berlin") hcl_3 <- hcl.colors(n = 10, palette = "Zissou 1") hcl_4 # (b) get some palettes from RColorBrewer: library(RColorBrewer) # display.brewer.all() # shows all Brewer palettes <- brewer.pal(n = 11, name = "BrBG") brew_1 <- brewer.pal(n = 11, name = "PRGn") brew_2 <- brewer.pal(n = 11, name = "Spectral") brew_3 <- brewer.pal(n = 8, name = "Pastel1") brew_4 # (c) get some palettes from yarrr: library(yarrr) # yarrr::piratepal() # shows all pirate palettes <- yarrr::piratepal(palette = "basel") yarrr_1 <- yarrr::piratepal(palette = "appletv") yarrr_2 <- yarrr::piratepal(palette = "espresso") yarrr_3 <- yarrr::piratepal(palette = "info") yarrr_4 <- list(hcl_1, hcl_2, hcl_3, hcl_4, my_pals brew_1, brew_2, brew_3, brew_4, yarrr_1, yarrr_2, yarrr_3, yarrr_4)<- c("hcl_1", "hcl_2", "hcl_3", "hcl_4", my_names "brew_1", "brew_2", "brew_3", "brew_4", "yarrr_1", "yarrr_2", "yarrr_3", "yarrr_4") # Show and compare color palettes: library(unikn) seecol(pal = my_pals, col_brd = "white", lwd_brd = 2, title = "Comparing HCL, RColorBrewer and yarrr color palettes", pal_names = my_names)
Similarly, we can use the
usecol() function to mix and modify color palettes from various sources. Again, it makes sense to inspect the results with
# Mix, extend and modify some palettes (from other packages): <- usecol(c(rev( brewer.pal(n = 4, name = "Reds")), brew_mix "white", brewer.pal(n = 4, name = "Blues")), n = 13) <- usecol(brewer.pal(n = 11, name = "Spectral"), n = 12) brew_ext <- usecol(c(piratepal("nemo"), piratepal("bugs"))) yarrr_mix <- usecol(c(piratepal("ipod")), n = 9) yarrr_mod <- list(brew_mix, brew_ext, my_pals yarrr_mix, yarrr_mod)<- c("brew_mix", "brew_ext", my_names "yarrr_mix", "yarrr_mod") # Show and compare new color palettes: seecol(pal = my_pals, col_brd = "white", lwd_brd = 2, title = "Using usecol() and seecol() to mix and modify palettes", pal_names = my_names)
Additionally, the unikn package provides two functions that help with defining new named color palettes or finding colors with specific names:
newpal()function makes it easy to define new named color palettes:
# (1) Source: <https://www.schemecolor.com/germany-flag-colors.php> <- c("#000000", "#dd0000", "#ffce00") col_flag <- c("Black", "Electric red", "Tangerine yellow") names_de # (2) Source: <https://en.wikipedia.org/wiki/Flag_of_Germany#Design> <- c("#000000", "#FF0000", "#FFCC00") col_flag <- c("Jet black", "Traffic red", "Rapeseed yellow") names_de # Decision: Simplify names: <- c("de_black", "de_red", "de_gold") simple_names # Define color palette: <- newpal(col = col_flag, flag_de names = simple_names) seecol(flag_de, title = "Defining a flag_de color palette", mar_note = "Colors based on <https://en.wikipedia.org/wiki/Flag_of_Germany>" # credit source )
Note that different sources often provide different colors (and certainly different names) for the same color schemes. Thus, it always makes sense to double-check definitions and acknowledge one’s sources.
grepal()function addresses a common problem: We typically know that we want some shade of some color (e.g., orange), but do not know which corresponding colors exist in our environment. The
grepal()function searches color names for a pattern:
grepal(pattern = "orange") # returns colors() with "orange" in their name #>  "darkorange" "darkorange1" "darkorange2" "darkorange3" "darkorange4" #>  "orange" "orange1" "orange2" "orange3" "orange4" #>  "orangered" "orangered1" "orangered2" "orangered3" "orangered4" seecol(pal = grepal("orange"), title = "See all colors() with 'orange' in their name")
grepal(pattern, x) searches
x = colors() (i.e., the 657 named colors provided by the grDevices package), but
x can be set to other named color palettes (including data frames). As
pattern can be a regular expression (see Appendix E now provides a primer on using regular expressions), we can easily answer more complex questions:
Which color names end on
violet? How do these colors look?
How many shades of gray or grey are there (in R)?
Both these questions can easily be answered by combining two calls to the
grepal() and the
- Which color names end on
violet? How do these colors look?
<- grepal(pattern = "pink$|purple$|violet$") cols_ppv seecol(pal = cols_ppv, title = "See all colors() with names ending on 'pink', 'purple' or 'violet'")
- How many shades of gray or grey are there (in R)?
length(grepal("gr(a|e)y")) # shades of "gray" or "grey" #>  224 length(grepal("^gr(a|e)y")) # shades starting with "gray" or "grey" #>  204 length(grepal("^gr(a|e)y$")) # shades starting and ending with "gray" or "grey" #>  2
seecol() also allows comparing long color palettes containing certain keywords:
<- grepal("red") pal_r <- grepal("green") pal_g <- grepal("blue") pal_b seecol(list(pal_r, pal_g, pal_b), title = "See all colors() with 'red', 'green', 'blue' in their name")
- When using the pipe operator
%>%from the magrittr package (Bache & Wickham, 2022), we can use multiple unikn functions to create and evaluate colorful chains of commands:
library(magrittr) <- c("#FAAB18", "#1380A1","#990000", "#588300") cols %>% cols newpal(names = c("orangy", "bluish", "redish", "greeny")) %>% # usecol(n = 10) %>% seecol(title = "My new custom color palette")