Search code examples
rheatmaplevelplot

filled.contour() in R: nonlinear key range


I am using filled.contour() to plot data stored in a matrix. The data is generated by a (highly) non-linear function, hence its distribution is not uniform at all and the range is very large.

Consequently, I have to use the option "levels" to fine tune the plot. However, filled.contour() does not use these custom levels to make an appropriate color key for the heat map, which I find quite surprising.

Here is a simple example of what I mean:

    x = c(20:200/100)
    y = c(20:200/100)
    z = as.matrix(exp(x^2)) %*% exp(y^2)
    filled.contour(x=x,y=y,z=z,color.palette=colorRampPalette(c('green','yellow','red')),levels=c(1:60/3,30,50,150,250,1000,3000))

As you can see, the color key produced with the code above is pretty much useless. I would like to use some sort of projection (perhaps sin(x) or tanh(x)?), so that the upper range is not over-represented in the key (in a linear way).

At this point, I would like to:

1) know if there is something very simple/obvious I am missing, e.g.: an option to make this "key range adapting" automagically; 2) seek suggestions/help on how to do it myself, should the answer to 1) be negative.

Thanks a lot!

PS: I apologize for my English, which is far from perfect. Please let me know if you need me to clarify anything.


Solution

  • I feel your frustration. I never found a way to do this with filled contour, so have usually reverted to using image and then adding my own scale as a separate plot. I wrote the function image.scale to help out with this (link). Below is an example of how you can supply a log-transform to your scale in order to stretch out the small values - then label the scale with the non-log-transformed values as labels:

    Example:

    source("image.scale.R") # http://menugget.blogspot.de/2011/08/adding-scale-to-image-plot.html
    
    x = c(20:200/100)
    y = c(20:200/100)
    z = as.matrix(exp(x^2)) %*% exp(y^2)
    
    pal <- colorRampPalette(c('green','yellow','red'))
    breaks <- c(1:60/3,30,50,150,250,1000,3000)
    ncolors <- length(breaks)-1
    labs <- c(0.5, 1, 3,30,50,150,250,1000,3000)
    
    #x11(width=6, height=6)
    layout(matrix(1:2, nrow=1, ncol=2), widths=c(5,1), heights=c(6))
    layout.show(2)
    
    par(mar=c(5,5,1,1))
    image(x=x,y=y,z=log(z), col=pal(ncolors), breaks=log(breaks))
    box()
    
    par(mar=c(5,0,1,4))
    image.scale(log(z), col=pal(ncolors), breaks=log(breaks), horiz=FALSE, xlab="", ylab="", xaxt="n", yaxt="n")
    axis(4, at=log(labs), labels=labs)
    box()
    

    Result:

    enter image description here