D.2 Essentials of color in R

Issues of colors are complicated — even when only considering those in R. As our ways of perceiving colors are based on biology, experience, and language, a theoretical understanding of color is an ambitious inter-disciplinary endeavor at the intersection of aesthetics, humanities, and science. (See the Wikipedia articles on color vision and color theory to get started.)

From a practical point of view, most people using R for creating beautiful visualizations never need to worry about the theoretical underpinnings of color systems.61 Fortunately, R comes loaded with tools for dealing with color and a range of packages offer an abundance of pre-defined color palettes.

When looking for nice colors, most people’s needs fall into 1 of 2 categories:

  1. Find a color or color palette that suits my current goals.

  2. Define a new color or color palette that suits my current goals.

We will discuss ways of addressing both needs in the following sections.

D.2.1 Basic R colors

R base colors

If you want to specify your own colors, you need to name them or select a color scale. R comes with 657 predefined colors, whose names can be viewed by evaluating colors() in the console, or running demo("colors"). Figure D.1 shows a random sample of 100 colors (from all 657 colors, but excluding over 200 shades of grey and gray):

100 random (non-gray) colors and their names in R.

Figure D.1: 100 random (non-gray) colors and their names in R.

This figure shows that there is no shortage of vibrant colors in R. However, choosing and combining colors from the list of colors() resembles a lottery: We can get lucky, but in most cases the outcome will be disappointing. A more promising approach is using functions that generate color palettes that follow the same principles and thus are more likely to fit together.

R base color palettes

The grDevices package that is included in R comes with a range of functions that allow defining color palettes. To obtain continuous color palettes, the grDevices package of R traditionally offers several functions to define vectors of n colors:

The color palettes returned as the output of these color functions are vibrant and bright:

However, obtaining truly beautiful color palettes requires more than just automatically drawing colors from some function. The following color palettes have in common that they include an element of design.

HCL color palettes

Starting with R 3.6.0 (released on 2019-04-26), the hcl.colors() function of the grDevices package provides a basic and frugal implementation of the prespecified palettes in the colorspace package (Ihaka et al., 2019) (see this blog post for details). From this version onwards, the default colors for image() and filled.contour() are based on hcl.colors(). In addition, palette-generating functions (like rainbow() and gray.colors()) feature a new rev argument to facilitate reversing the order of colors (which can also be done by using rev() to reverse the output vector of a color function).

Evaluate hcl.pals() to obtain the names of 110 pre-defined HCL palettes. Here are some examples of palettes included in hcl.colors():

As hcl.colors() incorporates an immense range of color palettes from other packages (e.g., ColorBrewer, viridis, scico), this powerful functionality renders many other color packages obsolete. Nevertheless, the following color packages provide additional support for special purposes.

D.2.2 Color packages

Most packages that primarily deal with visualizations — like ggplot2, lattice, or plotly — load or provide predefined 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.

RColorBrewer

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, Chang, et al., 2020).

Actually, unless you happen to need very special colors, RColorBrewer provides nice and useful color palettes that are sufficient for most purposes.

The following command prints all color palettes included in RColorBrewer:

Designing for color vision deficiencies

When using color, we must keep in mind that about 10% of the population is color vision impaired or color blind. Here are some ways of coping with this fact and still using color palettes that look visually friendly and beautiful for people with color vision.

A simple way to define a palette of colors that can still be distinguished by most color-blind people is discussed in the R Graphics Cookbook in this link:

Note that the cbf_1 and cbf_2 color palettes were simply defined as vectors (with the colors specified as characters of HEX code) and only differ in the 1st color, which is either grey or black:

In Section D.2.3 (below) we will show how to use RGB values to define a palette that implements Color Universal Design (CUD) recommendations (Okabe & Ito, 2008). But besides defining your own color palettes, we can also benefit from the designs of other people by using dedicated packages that target this issue.

viridis/viridisLite

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 viridis, magma, plasma, and 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.

In recent versions of ggplot2, the viridis scales are integrated and can be used by specifying scale_color_viridis_c() and scale_color_viridis_c() (for continuous color scales) and scale_fill_viridis_d() 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:

The following functions each define a color scale of n colors:

Check out ?viridisLite::viridis for additional information.

Another option for obtaining perceptually ordered and uniform color palettes are the Scientific colour maps by Fabio Crameri (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 also focuses on palettes for color-impaired viewers.

unikn

The unikn package (Neth & Gradwohl, 2020) implements the color schemes of the University of Konstanz and is used throughout this book. Besides providing a range of pre-defined color palettes, the package provides some color functions that are generally useful:

  1. The package provides the seecol() function that allows either seeing (or printing the details of) a particular color palette:

or comparing multiple color palettes:

  1. The unikn package also provides a usecol() function that makes creating new and modifying existing color palettes very easy:

The usecol() function also provides a wrapper for using and modifying (pre-defined or newly created) color palettes in graphs:

Even when not using the color palettes of the University of Konstanz, the usecol() and seecol() functions can be 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. The following code creates 4 palettes from hcl.pals() of grDevices (R Core Team, 2020), 4 palettes from RColorBrewer (Neuwirth, 2014), and 4 palettes from yarrr (Phillips, 2017), and then uses the seecol() function to view and compare these color palettes:

Similarly, we can use the usecol() function to mix and modify color palettes from various sources and then inspect the results with seecol():

D.2.3 Defining colors and color palettes

Defining individual colors

As there are many different ways to describe a color, there are many different ways to define a color. Here, we will only discuss 3 common ways of defining a color in R:

  1. by color name (e.g., col = c("black", "white"))

See colors() for the list of 657 color names available in base R — and note that every color is represented in character type.

  1. by HEX (hexadecimal) code (e.g., col = c("#000000", "#FFFFFF"))

Such HEX codes essentially specify a triplet of RGB values in hexadecimal notation. The 3 bytes represent a color’s red, green and blue components by a number in the range 00 to FF (in hexadecimal notation), corresponding to 0 to 255 (in decimal notation). As this way of representing color is popular online (in HTML), they are also known as web colors. Note that, in R, each HEX code is represented in character type, with the hash tag # as a prefix.

  1. by RGB (red-green-blue) values (e.g., col = c(rgb(red = 0, green = 0, blue = 0, maxColorValue = 255), rgb(255, 255, 255, maxColorValue = 255)))

Such RGB values are more traditional and can be entered and converted in most computer systems. In R, we can use the rgb() function to enter the red, green, and blue value of a color, as well as an optional transparency value alpha.
Note that we need to specify the maxColorValue = 255 to scale these values in the most common fashion (from 0 to 255).

Importantly, any particular color can be expressed in any system. For instance, the following graph shows the visual representation, color name, HEX codes, and RGB values of a vector my_cols that describes 4 colors:

The 3 ways of expressing each individual color are interchangeable. In the graph above, we can see that the color palette my_cols could have been defined in the following ways:

and these 4 ways all result in exactly the same color palette, as the following comparison graph shows:

Knowing that colors can be described by their names, HEX codes, and RGB values is perfectly sufficient for most R users. Nevertheless, there are many additional ways to define and express colors. For instance, the HSV (hue-saturation-value) system is a simple transformation of the RGB color space and is used in many software systems (see ?hsv for corresponding R functions). By contrast, the HCL (hue-chroma-luminance) system is much more suitable for describing human color perception (see ?hcl, and the hcl.colors() function available in grDevices from R 3.6.0 onwards).

Converting colors

R also comes with powerful color conversion functions that allow translating color values between the different systems. For instance, we can use the col2rgb() function of grDevices to obtain the RGB values that correspond to specific R color names. As col2rgb() requires a matrix-like object (rather than a vector) as its input to its col argument, we use the newpal() function of unikn with as_df = TRUE to define a color palette new_cols as a data frame:

To obtain the RGB values of new_cols, we can either use the col2rgb() function (to obtain a matrix of RGB values) or the seecol() function of unikn (for visual inspection):

When frequently needing to convert colors between different color spaces, consider using the colorspace package, which defines color-class objects that can be converted into a variety of color spaces (including RGB, sRGB, HSV, HLS, XYZ, LUV, LAB, polarLUV, and polarLAB).

Defining color palettes

In Section D.1.1, we distinguished between individual colors and color palettes, which are sets of colors to be used together. Defining our own color palettes is a great way to maintain a consistent color scheme for multiple graphs in a report or thesis.

It is easy to define our own color palettes. Corresponding to the 3 common ways of defining a color in R, we can define new color palettes in 3 ways. To illustrate them, we will use the newpal() and seecol() functions of unikn.

  1. Starting from R color names:

  1. Starting from HEX values:

  1. Starting from RGB values, we can implement the Color Universal Design (CUD) recommendations of https://jfly.uni-koeln.de/color/ (see Figure 16 of Okabe & Ito, 2008):

By creating a list of our new color palettes, we can print and compare them using the seecol() function:

By seecol() and usecol() functions also allow specifying n for extending color palettes:

or modifying color palettes further (e.g., by adding transparency values alpha):

Using custom palettes in ggplot2

  1. To use a particular base R color in a ggplot() command, we can pass its name (as a character string) to functions that includes a color argument:

Note that placing the color = "steelblue" specification outside of the aes() function changed all points of our plot to this particular color.

  1. To define and use a new color palette my_colors in a ggplot() command, we need to add the scale_color_manual() function that instructs ggplot to use a custom color scale for the current plot. Note that scale_color_manual() expects to receive color values, rather than mere color names. For base R colors, providing their names (as character strings) works just fine, but for a more general solution — which also works when using colors defined by hexadecimal names, rgb() codes, or colors provided by other packages (see above) — it is safer to first define a color palette (e.g., by using the usecol() function of the unikn package):

This plot illustrates the grouping function of color, which is why we defined my_pal as a qualitative color palette (see Sections D.1.2 and D.1.3).

References

Brewer, C. (2019). ColorBrewer 2.0: Color advice for cartography. Retrieved from http://www.colorbrewer2.org

Crameri, F. (2018). Scientific colour-maps. Zenodo. https://doi.org/10.5281/zenodo.1243862

Garnier, S. (2018a). viridis: Default color maps from ’matplotlib’. Retrieved from https://CRAN.R-project.org/package=viridis

Garnier, S. (2018b). viridisLite: Default color maps from ’matplotlib’ (lite version). Retrieved from https://CRAN.R-project.org/package=viridisLite

Ihaka, R., Murrell, P., Hornik, K., Fisher, J. C., Stauffer, R., Wilke, C. O., … Zeileis, A. (2019). colorspace: A toolbox for manipulating and assessing colors and palettes. Retrieved from https://CRAN.R-project.org/package=colorspace

Neth, H., & Gradwohl, N. (2020). unikn: Graphical elements of the University of Konstanz’s corporate design. Retrieved from https://CRAN.R-project.org/package=unikn

Neuwirth, E. (2014). RColorBrewer: ColorBrewer palettes. Retrieved from https://CRAN.R-project.org/package=RColorBrewer

Okabe, M., & Ito, K. (2008). Color universal design (CUD): How to make figures and presentations that are friendly to colorblind people. J*Fly: Data Depository for Drosophila Researchers. Retrieved from https://jfly.uni-koeln.de/color/

Phillips, N. (2017). yarrr: A companion to the e-book "yarrr!: The pirate’s guide to R". Retrieved from https://CRAN.R-project.org/package=yarrr

R Core Team. (2020). R: A language and environment for statistical computing. Retrieved from https://www.R-project.org

Wickham, H., Chang, W., Henry, L., Pedersen, T. L., Takahashi, K., Wilke, C., … Dunnington, D. (2020). ggplot2: Create elegant data visualisations using the grammar of graphics. Retrieved from https://CRAN.R-project.org/package=ggplot2


  1. A basic understanding of color perception typically certainly helps in choosing better color palettes, but understanding the details of color theory is not a necessary prerequisite for creating beautiful visualizations.