I am interested in having a \"good\" divergent color pallette. One could obviously use just red, white, and blue:
img <- function(obj, nam) {
image(1:le
The scico package (Palettes for R based on the Scientific Colour-Maps ) has several good diverging palettes that are perceptually uniform and colorblind safe (e.g., vik, roma, berlin).
Also available for Python, MatLab, GMT, QGIS, Plotly, Paraview, VisIt, Mathematica, Surfer, d3, etc. here
Paper: Crameri, F. (2018), Geodynamic diagnostics, scientific visualisation and StagLab 3.0, Geosci. Model Dev., 11, 2541-2562, doi:10.5194/gmd-11-2541-2018
Blog: The Rainbow Colour Map (repeatedly) considered harmful
# install.packages('scico')
# or
# install.packages("devtools")
# devtools::install_github("thomasp85/scico")
library(scico)
scico_palette_show(palettes = c("broc", "cork", "vik",
"lisbon", "tofino", "berlin",
"batlow", "roma"))
Another great package is cmocean. Its colormaps are available in R via the pals package or the oce package.
Paper: Thyng, K. M., Greene, C. A., Hetland, R. D., Zimmerle, H. M., & DiMarco, S. F. (2016). True colors of oceanography. Oceanography, 29(3), 10, http://dx.doi.org/10.5670/oceanog.2016.66.
Talk: PLOTCON 2016: Kristen Thyng, Custom Colormaps for Your Field.
### install.packages("devtools")
### devtools::install_github("kwstat/pals")
library(pals)
pal.bands(ocean.balance, ocean.delta, ocean.curl, main = "cmocean")
Edit: add seven levels max colorblind-friendly palettes from the rcartocolor package
library(rcartocolor)
display_carto_all(type = 'diverging', colorblind_friendly = TRUE)
Library RColorBrewer
provides beautiful palettes for =<13 colors. For example, palette BrBG
shows diverging colors from brown to green.
library(RColorBrewer)
display.brewer.pal(11, "BrBG")
Which can be expanded to a less informative palette by creating palettes to and from a mid-point color.
brbg <- brewer.pal(11, "BrBG")
cols <- c(colorRampPalette(c(brbg[1], brbg[6]))(51),
colorRampPalette(c(brbg[6], brbg[11]))(51)[-1])
Analogically, using your choice of viridis
and magma
palettes, you can try finding a similarity between them. This could be a point, where to join the palettes back to back.
select.col <- function(cols1, cols2){
x <- col2rgb(cols1)
y <- col2rgb(cols2)
sim <- which.min(colSums(abs(x[,ncol(x)] - y)))
message(paste("Your palette will be", sim, "colors shorter."))
cols.x <- apply(x, 2, function(temp) rgb(t(temp)/255))
cols.y <- apply(y[,sim:ncol(y)], 2, function(temp) rgb(t(temp)/255))
return(c(cols.x,cols.y))
}
img(select.col(rev(viridis(100,0)),magma(100,0)), "")
# Your palette will be 16 colors shorter.
There have been some good and useful suggestions already but let me add a few remarks:
Therefore, combining magma and viridis does not work well. You could let them diverge from a similar yellowish color but you would diverge to similar blueish colors. Also with the changing hues it would just become more difficult to judge in which arm of the palette you are.
As mentioned by others, ColorBrewer.org provides good diverging palettes. Moreland's approach is also useful. Yet another general solution is our diverging_hcl()
function in the colorspace
package. In the accompanying paper at https://arxiv.org/abs/1903.06490 (forthcoming in JSS) the construction principles are described and also how the general HCL-based strategy can approximate numerous palettes from ColorBrewer.org, CARTO, etc.
(Earlier references include our initial work in CSDA at http://dx.doi.org/10.1016/j.csda.2008.11.033 and further recommendations geared towards meteorology, but applicable beyond, in a BAMS paper at http://dx.doi.org/10.1175/BAMS-D-13-00155.1.)
The advantage of our solution in HCL space (hue-chroma-luminance) is that you can interpret the coordinates relatively easily. It does take some practice but isn't as opaque as other solutions. Also we provide a GUI hclwizard()
(see below) that helps understanding the importance of the different coordinates.
Most of the palettes in the question and the other answers can be matched rather closely by diverging_hcl()
provided that the two hues (argument h
), the maximum chroma (c
), and minimal/maximal luminance (l
) are chosen appropriately. Furthermore, one may have to tweak the power
argument which controls how quickly chroma and luminance are increased, respectively. Typically, chroma is added rather quickly (power[1] < 1
) whereas luminance is increased more slowly (power[2] > 1
).
Moreland's "cool-warm" palette for example uses a blue (h = 250
) and red (h = 10
) hue but with a relatively small luminance contrast(l = 37
vs. l = 88
):
coolwarm_hcl <- colorspace::diverging_hcl(11,
h = c(250, 10), c = 100, l = c(37, 88), power = c(0.7, 1.7))
which looks rather similar (see below) to:
coolwarm <- Rgnuplot:::GpdivergingColormap(seq(0, 1, length.out = 11),
rgb1 = colorspace::sRGB( 0.230, 0.299, 0.754),
rgb2 = colorspace::sRGB( 0.706, 0.016, 0.150),
outColorspace = "sRGB")
coolwarm[coolwarm > 1] <- 1
coolwarm <- rgb(coolwarm[, 1], coolwarm[, 2], coolwarm[, 3])
In contrast, ColorBrewer.org's BrBG palette a much higher luminance contrast (l = 20
vs. l = 95
):
brbg <- rev(RColorBrewer::brewer.pal(11, "BrBG"))
brbg_hcl <- colorspace::diverging_hcl(11,
h = c(180, 50), c = 80, l = c(20, 95), power = c(0.7, 1.3))
The resulting palettes are compared below with the HCL-based version below the original. You see that these are not identical but rather close. On the right-hand side I've also matched viridis and plasma with HCL-based palettes.
Whether you prefer the cool-warm or BrBG palette may depend on your personal taste but also - more importantly - what you want to bring out in your visualization. The low luminance contrast in cool-warm will be more useful if the sign of the deviation matters most. A high luminance contrast will be more useful if you want to bring out the size of the (extreme) deviations. More practical guidance is provided in the papers above.
The rest of the replication code for the figure above is:
viridis <- viridis::viridis(11)
viridis_hcl <- colorspace::sequential_hcl(11,
h = c(300, 75), c = c(35, 95), l = c(15, 90), power = c(0.8, 1.2))
plasma <- viridis::plasma(11)
plasma_hcl <- colorspace::sequential_hcl(11,
h = c(-100, 100), c = c(60, 100), l = c(15, 95), power = c(2, 0.9))
pal <- function(col, border = "transparent") {
n <- length(col)
plot(0, 0, type="n", xlim = c(0, 1), ylim = c(0, 1),
axes = FALSE, xlab = "", ylab = "")
rect(0:(n-1)/n, 0, 1:n/n, 1, col = col, border = border)
}
par(mar = rep(0, 4), mfrow = c(4, 2))
pal(coolwarm)
pal(viridis)
pal(coolwarm_hcl)
pal(viridis_hcl)
pal(brbg)
pal(plasma)
pal(brbg_hcl)
pal(plasma_hcl)
Update: These HCL-based approximations of colors from other tools (ColorBrewer.org, viridis, scico, CARTO, ...) are now also available as named palettes in both the colorspace
package and the hcl.colors()
function from the basic grDevices
package (starting from 3.6.0). Thus, you can now also say easily:
colorspace::sequential_hcl(11, "viridis")
grDevices::hcl.colors(11, "viridis")
Finally, you can explore our proposed colors interactively in a shiny app: http://hclwizard.org:64230/hclwizard/. For users of R, you can also start the shiny app locally on your computer (which runs somewhat faster than from our server) or you can run a Tcl/Tk version of it (which is even faster):
colorspace::hclwizard(gui = "shiny")
colorspace::hclwizard(gui = "tcltk")
If you want to understand what the paths of the palettes look like in RGB and HCL coordinates, the colorspace::specplot()
is useful. See for example colorspace::specplot(coolwarm)
.
I find Kenneth Moreland's proposal quite useful.
It is implemented in the Rgnuplot
package (install.packages("Rgnuplot")
is enough, you don't need to install GNU plot). To use it like the usual color maps, you need to convert it like this:
cool_warm <- function(n) {
colormap <- Rgnuplot:::GpdivergingColormap(seq(0,1,length.out=n),
rgb1 = colorspace::sRGB( 0.230, 0.299, 0.754),
rgb2 = colorspace::sRGB( 0.706, 0.016, 0.150),
outColorspace = "sRGB")
colormap[colormap>1] <- 1 # sometimes values are slightly larger than 1
colormap <- grDevices::rgb(colormap[,1], colormap[,2], colormap[,3])
colormap
}
img(red_blue_diverging_colormap(500), "Cool-warm, (Moreland 2009)")
This it how it looks like in action compared to an interpolated RColorBrewer "RdBu":