--- title: "A New palette() for R" author: "Achim Zeileis, Paul Murrell, Martin Maechler, Deepayan Sarkar" date: 2019-11-21 categories: ["User-visible Behavior"] tags: ["colors"] ---

UPDATE 2019-12-03: Following feedback, the new default palette has been tweaked so that the new “magenta” is a little redder and darker and the new “yellow” is a little lighter and brighter. The former is to improve the discriminability between “blue” and “magenta” for deuteranopes and the latter is to improve the discriminability between “green” and “yellow” for protanopes. We would like to thank those who provided feedback and suggestions on the new palette, in particular Antonio Camargo, Brenton Wiernik, Ken Knoblauch, and Jakub Nowosad.

In R, it is possible to specify a color in several ways: by name, col = "red"; by hex code, col = "#FF0000"; or by number, col = 2. The last of these, a numeric color specification, is a numeric index into a “color palette”, which is controlled via the palette() function. Without any arguments, this function returns the current set of palette colors; as we can see, the second color in the default palette is "red", so col = 2 corresponds to red.

palette()
## [1] "black"   "red"     "green3"  "blue"    "cyan"    "magenta" "yellow" 
## [8] "gray"

Unfortunately, there is a significant problem with this default color palette: it is horrible. The colors are highly saturated (garish, flashy) and vary enormously in terms of luminance (e.g., "yellow" is much lighter than "blue").

This post introduces a new default color palette for R, describes how it was chosen, and also demonstrates some new extensions to the color palette functionality. TL;DR, The new palette uses similar hues but is more balanced in terms of luminance and avoids extremely garish colors.

Choosing the new palette

The following criteria were used to select the new color palette:

We worked within the HCL (hue-chroma-luminance) color model, which tries to capture the perceptual dimensions of the human color vision system. This color model was also employed in the recent additition of the function grDevices::hcl.colors() which was inspired by the colorspace package and which brings a broad range of qualitative, sequential, and diverging palettes to base R. See the accompanying arXiv paper and http://colorspace.R-Forge.R-project.org/ for more details on employing the HCL color model for obtaining color palettes.

The criteria above limited the new palette to specific ranges of hue, chroma, and luminance and functions from the Polychrome package were used to generate potential sets of colors and to measure the visual differences between them. See the accompanying JSS paper for more details.

Some final manual tweaks were applied to balance the goals of the palette. Along with the new default palette, various other balanced color palettes are offered as alternatives (including colors from ggplot2, ColorBrewer, and Tableau, among others).

Demonstrating the new palette

Specifying colors by number is not particularly common, but it is an easy way to demonstrate use of color in examples, so it occurs a number of times in R documentation. Additionally, it is not uncommon to select colors by number when adding a few lines to an otherwise monochrome plot (e.g., the diagnostic scatter plots in plot.lm). The new predefined palettes also make the use of numeric color specifications a more sensible and effective option.

The following images show how poor the result was with the old palette and how much better it is with the new palette, using an example from the symbols() help page. This was selected as an example here because the thermometer symbol combines coloring lines with shading areas. Thus the plot below brings out both aspects (based on random input data).

In the old palette colors 5 and 7 were much lighter and hence the corresponding symbols are harder to read and blend in with the white background. In contrast, the new palette gives similar perceptual weight to all symbols.

Moreover, the following images simulate the appearance of the two palettes for deuteranomaly and protanomaly (using deutan() and protan() from the ‘colorspace’ package). Notice, for example, the improved discriminability between colors 1 and 2 and between colors 4 and 6 with the new palette.

New features

It is also possible to set up a new color palette with the palette() function. This can be achieved by specifying an argument to palette() that is either a character vector of colors (color names or hex colors) or a single character value that gives the name of a predefined palette.

Previously, the only predefined palette name that palette() accepted was "default"; that was one way to restore the default color palette. But along with the new default palette, various new predefined palette names are now supported. All of these are already well-established, widely used, and based on well-founded construction principles and/or thorough testing.

The color swatches below show the first eight colors from most of the predefined palettes (except a few of the ColorBrewer palettes). Note that some of these palettes provide more colors, especially "Polychrome 36" and "Alphabet", which provide 36 and 26 colors, respectively.

To facilitate the adoption of these new palettes, two new accompanying functions are provided:

The palette.colors() function complements the qualitative palettes provided by the hcl.colors() function. The hcl.colors() function provides a number of qualitative palettes that are very balanced by only varying hue and keeping chroma and luminance fixed. While this is desirable in many displays, it decreases distinguishability, in particular for viewers with color vision deficiencies. This is why the palettes in palette.colors() allow chroma and luminance differences within a limited range (as mentioned above).

Finally, another small improvement is to make sure that calling palette() does not open a new graphics device when no graphics devices are open.

Summary

The default palette() in R is no longer utterly horrible.

Several new predefined palettes, and a new palette.colors() function, provide a sensible and simple way to generate a set of distinguishable colors for representing qualitative changes in data.

Hopefully, the new palette does not muck up existing uses of numeric color specifications (especially in documentation), but we would be glad to hear of any issues (please email Paul.Murrell@R-project.org or Achim.Zeileis@R-project.org).