Search code examples
rgraphicscolorsggplot2palette

how to calculate the gradient with multiple dimensions of colors in R


this is related to this question but perhaps a simpler example. i'm curious if there's a reasonable way to calculate a multi-dimensional color gradient given three or four arbitrary colors the way that the r rgb() function does with red, green, blue? the one-dimensional gradient is easy (fig 1) but then it's unclear to me how to compute the two-dimensional gradient (fig 2) inside the triangle. edges are easy. it's what inside that counts

# one dimensional color gradient
one.dimensions <- colorRampPalette( c( "orange" , "blue" ) )( 100 )

plot( 1:100 , rep( 1 , 100 ) , col = one.dimensions , cex = 3 , pch = 16 , main  = 'one dimensional gradient' )

enter image description here

# here are the edges of a three-colored triangle
dimensions13 <- colorRampPalette( c( "orange" , "blue" ) )( 100 )
dimensions12 <- colorRampPalette( c( "orange" , "red" ) )( 100 )
dimensions23 <- colorRampPalette( c( "blue" , "red" ) )( 100 )

plot( 1:100 , c( 1:50 , 50:1 ) , type = 'n' , main = 'two dimensional gradient' )
points( 1:100 , rep( 1 , 100 ) , col = dimensions12 , cex = 3 , pch = 16 )
points( seq( 1 , 50 , length = 100 ) , seq( 1 , 50 , length = 100 ) , col = dimensions13 , cex = 3 , pch = 16 )
points( seq( 50 , 100 , length = 100 ) , seq( 50 , 1 , length = 100 ) , col = dimensions23 , cex = 3 , pch = 16 )

enter image description here


Solution

  • you could consider three basic colour mixing strategies:

    1- subtractive, using the alpha transparency blending of R graphics. Basically, superimpose multiple layers with their own gradient.

    library(grid)
    
    grid.newpage()
    grid.raster(scales::alpha(colorRampPalette(c("white","blue"))(10), 0.3),
                width=1,height=1)
    grid.raster(t(scales::alpha(colorRampPalette(c("white","red"))(10), 0.3)),
                width=1,height=1)
    

    One drawback is that the final colour depends on the order of the layers.

    enter image description here

    The CMYK colour model could be another source of inspiration.

    2- additive. I came up with a naive implementation as follows. Consider your N basic colours (say yellow, green, orange). Assign them a wavelength of the visible spectrum (570nm, 520nm, 600nm). Each colour is given a weight according to the position in the triangle (think of N lasers with tunable intensity). Now to get the colour associated with this mixture of N laser sources, you need to convolve with CIE colour matching functions. It's a physically sound mixing, mapping numbers to a visual perception. However, there's clearly an issue of uniqueness: several combinations will likely produce the same colour. The eye has only three different types of receptors after all, so N>3 is never going to result in a bijection.

    3- pixelated (halftoning). Divide the image into small adjacent regions, like LCD screens, and every pixel is divided into N subpixels, each with its own colour. From far away and/or sufficient screen/print resolution, the eye won't see the details and will blur the adjacent colours for you.