RGB, HSV, JCh… colorspace is three dimensional. In data visualization color is generally treated one-dimensionally, however. The typical color ramp is a line through 3D colorspace that encodes a single numeric variable. But we can take better advantage of color’s inherent dimensionality, using it to encode two or three numeric variables at once.
In the above visualization (created as part of the DS421 NRT program) for example, a 2D color ramp on the lefthand panel facilitates simultaneous mapping of both poverty and race. Or in the chart below (created as part of the California Phylodiversity Project), a 3D color mapping represents variation in the phylogenetic composition of plant communities across California (places with similar color have similar floristic communities; if it had a legend, it would be 3D point cloud filling RGB space).
I made these charts, as I generally do, in R. Having failed to find an existing package that implements color mappings like this, I packaged up some functions of my own in a library called colormap. You can access it via
The package includes two functions that map data to a 2D colorspace, and one for 3D colorspace. Each takes a table of input data as the only required parameter, and returns a vector of color values corresponding to every row of the table. These colors can then be fed to your plots, whether you’re using base graphics, ggplot2, rgl, etc.
A brief tutorial
Let’s reproduce the map above, which shows precipitation seasonality in Colorado by comparing precipitation in the wettest vs. driest months. In this plot, green and black places have average seasonality and are either wet or dry, respectively. Yellow places are highly seasonal with rain or snow concentrated in the wettest season, while blue places have the flattest, most aseasonal precipitation profiles. This example uses
colors2d, in which a palette is defined by specifying 4 corner colors. Here’s code to create this chart:
devtools::install_github("matthewkling/colormap") library(colormap) library(raster) # get some climate data clim <- getData('worldclim', var='bio', res=2.5) # select precip of the wettest and driest months clim <- subset(clim, c("bio13", "bio14")) # crop to colorado clim <- crop(clim, extent(-109, -102, 37, 41)) # convert to long-format matrix v <- values(clim) # map color to the climate variables colors <- colors2d(v, c("green", "yellow", "black", "blue")) # plot the data in climate space par(mfrow=c(1,2)) plot(v, col=colors, pch=16, xlab="precip of wettest month (mm)", ylab="precip of driest month (mm)") # and in geographic space col <- clim[[c(1,1,1)]] col <- t(col2rgb(colors)) plotRGB(col)
On perceptual uniformity
This treatment of colorspace leaves a couple things to be desired. First off there’s colorblindness, which shrinks and distorts visible colorspace. And then there’s perceptual non-uniformity, i.e. the notion that because humans’ ability to discern color differences varies across RGB colorspace, using color ramps that are linear in RGB space biases user interpretation of data visualizations. Both these issues prevent viewers from correctly perceiving the true patterns in the data.
In R, viridis overcomes both these problems for one-dimensional color ramps. That should be doable in 2D and 3D color mappings as well, building on tools like colorspacious… I’d like to look into implementing that at some point.