Simple Colour Manipulation

Functions for easily manipulating colours, creating colour scales and calculating colour distances.

Build Status codecov

The shades package allows colours to be manipulated easily in R. Properties such as brightness and saturation can be quickly queried, changed or varied, and perceptually uniform colour gradients can be constructed. It plays nicely with the pipe operator from the popular magrittr package, and fits naturally into that paradigm.

The package is available on CRAN. You can also install the current development version from GitHub using devtools:

# install.packages("devtools")

Feedback on the package or suggestions are welcome, either by filing an issue or by email.


Colours are represented in R using CSS-style hex strings, but there is also a dictionary of predefined named colours such as "red" and "blue". Either of these may be passed to most graphics functions, but creating variations on a particular colour can be awkward.

The shades package defines a simple class, shade, which uses exactly this same convention and is entirely compatible with built-in colours, but it also stores information about the coordinates of the colours in a particular colour space.

red <- shade("red")
## [1] "red"
## attr(,"space")
## [1] "sRGB"
## attr(,"coords")
##      R G B
## [1,] 1 0 0

From here, the package switches between colour spaces as required, allowing various kinds of colour manipulation to be performed straightforwardly. For example, let's find the saturation level of a few built-in colours.

## [1] 0.1647100 0.0588200 0.7535287

Now let's consider a colour gradient stepping through two different colour spaces, which we might want to use as a palette or colour scale.

swatch(gradient(c("red","blue"), 5))

plot of chunk gradients

swatch(gradient(c("red","blue"), 5, space="Lab"))

plot of chunk gradients

Here, we are using the swatch function to visualise a set of colours as a series of squares. Notice the more uniform appearance of the gradient when it traverses through the Lab colour space.

Similarly, we can create a set of new colours by changing the brightness and saturation levels of some base colours, and make the code more readable by using the magrittr pipe operator.

library(shades); library(magrittr)
c("red","blue") %>% brightness(0.6) %>% saturation(seq(0,1,0.25)) %>% swatch

plot of chunk saturation

This operation takes the original two colours, reduces their brightness to 60%, assigns a whole series of saturation levels to the result, and then passes it to swatch for visualisation. Notice that the pipeline is combinative (like the base function outer), returning each combination of parameters in a multidimensional array. The final shades are arranged in two rows by swatch, for convenience.

Any of these gradients can be directly passed to a standard graphical function, to be used as a colour scale. However, when choosing a colour scale, it is helpful to bear in mind that some viewers may have a colour vision deficiency (colour blindness), making it harder for them to distinguish certain colours and therefore to see a continuous scale. The dichromat function can be used to simulate this.

rev(grDevices::rainbow(9)) %>% dichromat %>% swatch

plot of chunk dichromat

gradient("viridis",9) %>% dichromat %>% swatch

plot of chunk dichromat

Here we are using the built-in "viridis" colour map, developed for Python's matplotlib, which was specifically designed to appear continuous under as many conditions as possible. When shown with simulated red-blindness, the default for dichromat, it is clearly much more interpretable than a typical rainbow palette generated by R's built-in graphics functions.

The package also supports colour mixing, either additively (as with light) or subtractively (as with paint). For example, consider additive mixtures of the three primary RGB colours.

c("red", addmix("red","green"), "green", addmix("green","blue"), "blue") %>% swatch

plot of chunk addmix

Similarly, we can subtractively combine the three secondary colours.

c("cyan", submix("cyan","magenta"), "magenta", submix("magenta","yellow"), "yellow") %>% swatch

plot of chunk submix

A "light mixture" infix operator, %.)%, and a "paint mixture" infix operator, %_/%, are also available.

("red" %.)% "green") == "yellow"
## [1] TRUE
("cyan" %_/% "magenta") == "blue"
## [1] TRUE

Finally, you can calculate perceptual distances to a reference colour, as in

distance(c("red","green","blue"), "red")
## [1]  0.00000 86.52385 53.07649

Minimal ggplot2 example

Gradients from this package can be used as ggplot2 colour scales through the manual scale functions; for example,

library(shades); library(ggplot2)
mtcars$cyl<- factor(mtcars$cyl)
ggplot(mtcars, aes(mpg,qsec,col=cyl)) + geom_point() + scale_color_manual(values=gradient("viridis",3))

plot of chunk ggplot

ggplot(mtcars, aes(cyl,mpg,fill=cyl)) + geom_boxplot() + scale_fill_manual(values=gradient("viridis",3))

plot of chunk ggplot

Related packages

The shades package aims to bring together a range of colour manipulation tools and make them easy to use. However, there are several other packages available that can do similar things, sometimes in slightly different ways. These include

  • the grDevices package, which is shipped with R and used as the basis for shades;
  • the venerable colorspace package, which provides formal colour classes and transformations between spaces;
  • munsell, which interprets colours in Munsell notation and does some colour manipulation;
  • viridis and RColorBrewer, which provide the colour scales from matplotlib and ColorBrewer;
  • dichromat, which provides another implementation of the dichromat function (a duplication which I didn't discover until after writing this package's version!); and
  • colorblindr, which provides alternative tools for simulating colour blindness in figures.

This package was also partly influenced by Colors.jl, a colour manipulation package for Julia.


Significant changes to the shades package are laid out below for each release.



  • There is now support for transparency, which can be queried or modified through the new opacity() function, which functions just like the other colour property functions (#4). Opacity (alpha) values are stored as an attribute with shade objects, and reflected in the RGB hex representation only when less than 1.
  • The scalefac() functional has been added, which multiplies its argument just as delta() adds it. Both functions now accept, and concatenate, multiple arguments for convenience.
  • The usual behaviour of the colour property manipulation functions, which vectorise over both arguments, can be suppressed by wrapping replacement values with the recycle() function, which reverts to a standard R "recycling" scheme with final dimensions matching the original.



  • The dichromat() function now offers a pass-through (normal colour vision) option, and is also vectorised over its second argument (#3). Some of the coefficients it uses internally are now pre-calculated and cached for efficiency.
  • There is now a print method for vectors of class shade.
  • An empty shade vector is now explicitly an error.
  • The README now includes an example of using shades with ggplot2 (#2), as well as links to several related packages.



  • Support for two new colour spaces has been added: LMS, a direct representation of the response levels of each of the three colour receptor types in the eye; and LCh, a polar representation of Lab space.
  • The new dichromat() function can be used to simulate colour blindness.
  • The gradient() function now additionally supports predefined colour maps from matplotlib and ColorBrewer. Its second argument is now interpreted a little differently.
  • The hueshift() function has been removed, in favour of the more general combination of hue() and delta(). hue(x, delta(y)) is the equivalent of the old hueshift(x,y), and delta() can also be used with other colour properties.
  • New colour property functions lightness() and chroma() have been added.
  • Dimensions are now set when two or more colour properties are changed, and the swatch() visualisation function plots multidimensional shades in a grid.
  • There is now a rev() method for shades.
  • The all.equal() method for shades now passes on its ellipsis argument when checking colour coordinates.



  • The package has been reworked to use functions from base R to warp colour coordinates between spaces and so on. It therefore no longer depends on the "colorspace" package, but the list of supported colour spaces has changed somewhat as a result.
  • The warp() function has been added for colour space conversions.
  • New function complement() returns complementary colours, while addmix() and submix(), plus infix shorthands, implement additive and subtractive colour mixing.
  • The new distance() function can be used to calculate a standardised measure of the perceptual "distance" between colours.
  • The shade class gains indexing and equality operators, plus methods for c(), rep() and all.equal().
  • There are now accessor functions space() and coords(), for obtaining the current space and coordinates of colour vectors.
  • The swatch() function now draws grey borders around colour boxes, to make the delineation of near-white colours clearer.



  • First public release.


Reference manual

It appears you don't have a PDF plugin for this browser. You can click here to download the reference manual.


1.3.1 by Jon Clayden, 15 days ago

Report a bug at

Browse source code at

Authors: Jon Clayden

Documentation:   PDF Manual  

BSD_3_clause + file LICENCE license

Suggests testthat, covr, ggplot2

Enhances colorspace

Imported by tractor.base.

See at CRAN