rplottriplot

three-way color gradient fill in r


How can I fill three way color gradient (heatmap) to a triplot (triangle plot), like this.

plot(NA,NA,xlim=c(0,1),ylim=c(0,sqrt(3)/2),asp=1,bty="n",axes=F,xlab="",ylab="")
segments(0,0,0.5,sqrt(3)/2)
segments(0.5,sqrt(3)/2,1,0)
segments(1,0,0,0)

enter image description here

Color should run in parallel to triplot.


Solution

  • Here is one way to do it - it's a bit of a hack, using points to plot the gradient piece by piece:

    plot(NA,NA,xlim=c(0,1),ylim=c(0,1),asp=1,bty="n",axes=F,xlab="",ylab="")
    segments(0,0,0.5,sqrt(3)/2)
    segments(0.5,sqrt(3)/2,1,0)
    segments(1,0,0,0)
    # sm - how smooth the plot is. Higher values will plot very slowly
    sm <- 500
    for (y in 1:(sm*sqrt(3)/2)/sm){
        for (x in (y*sm/sqrt(3)):(sm-y*sm/sqrt(3))/sm){
            ## distance from base line:
            d.red = y
            ## distance from line y = sqrt(3) * x:
            d.green = abs(sqrt(3) * x - y) / sqrt(3 + 1)
            ## distance from line y = - sqrt(3) * x + sqrt(3):
            d.blue = abs(- sqrt(3) * x - y + sqrt(3)) / sqrt(3 + 1)
            points(x, y, col=rgb(1-d.red,1 - d.green,1 - d.blue), pch=19)
        }
    }
    

    And the output:

    enter image description here

    Did you want to use these gradients to represent data? If so, it may be possible to alter d.red, d.green, and d.blue to do it - I haven't tested anything like that yet though. I hope this is somewhat helpful, but a proper solution using colorRamp, for example, will probably be better.

    EDIT: As per baptiste's suggestion, this is how you would store the information in vectors and plot it all at once. It is considerably faster (especially with sm set to 500, for example):

    plot(NA,NA,xlim=c(0,1),ylim=c(0,1),asp=1,bty="n",axes=F,xlab="",ylab="")
    sm <- 500
    x <- do.call(c, sapply(1:(sm*sqrt(3)/2)/sm, 
                           function(i) (i*sm/sqrt(3)):(sm-i*sm/sqrt(3))/sm))
    y <- do.call(c, sapply(1:(sm*sqrt(3)/2)/sm, 
                           function(i) rep(i, length((i*sm/sqrt(3)):(sm-i*sm/sqrt(3))))))
    d.red = y
    d.green = abs(sqrt(3) * x - y) / sqrt(3 + 1)
    d.blue = abs(- sqrt(3) * x - y + sqrt(3)) / sqrt(3 + 1)
    points(x, y, col=rgb(1-d.red,1 - d.green,1 - d.blue), pch=19)