4

The Problem

As I experiment with heatmaps, here's a circular question, with a probably frustratingly obvious answer...

I answered a question on plotting a heatmap with dissimilar data using the fields and ggplot2 packages. It basically allows very differently scaled x and y axes to be interpolated with the akima package ready for plotting.

Unfortunately, I can't work out a way to relabel the axes so they refer back to the original values. I know it will involve the use of breaks and labels parameters in ggplot2 but I have been unable to produce anything but mistakes. Solutions for both the plotting packages would be much appreciated...

Updated with solution

For convenience, here is my code using ggplot2:

library("akima")
library("ggplot2")

x.orig <- rnorm(20, 4, 3)
y.orig <- rnorm(20, 5e-5, 1e-5)
x <- scale(x.orig)  
y <- scale(y.orig) 
z <- rnorm(20)

t. <- interp(x,y,z)
t.df <- data.frame(t.)

gt <- data.frame( expand.grid(x=t.$x, 
                              y=t.$y), 
                  z=c(t.$z), 
                  value=cut(c(t.$z), 
                            breaks=seq(min(z),max(z),0.25)))

p <- ggplot(gt) + geom_tile(aes(x,y,fill=value)) + 
    geom_contour(aes(x=x,y=y,z=z), colour="black") 

# --------------------------------------------------------------
# Solution below prompted by X. He's answer:

get.labels <- function(break.points, orig.data, scaled.data, digits) { 
    labels <- as.character(lapply(break.points,      
            function(i) round(i * min(orig.data) 
                              / min(scaled.data),
                              digits)
                                  )
                           )
    labels
}

x.break.points <- seq(min(x), max(x), 0.5)
x.labels <- get.labels(x.break.points, x.orig, x, digits=2)
p <- p + scale_x_continuous(breaks=x.break.points, 
                            labels=x.labels)

y.break.points <- seq(min(y), max(y), 0.5)
y.labels <- get.labels(y.break.points, y.orig, y, digits=8)
p <- p + scale_y_continuous(breaks=y.break.points, 
                            labels=y.labels)

p

The Result

Correctly labeled heat map

Still to be solved

There remains one issue: when the code is first run, it generates the labels in reverse, on the second and subsequent runs, the labels are correctly labeled. Maybe another question?...

Community
  • 1
  • 1
daedalus
  • 10,873
  • 5
  • 50
  • 71

1 Answers1

5

I did something like this:

library("akima")
library("ggplot2")

x.orig <- rnorm(20, 4, 3)
y.orig <- rnorm(20, 5e-5, 1e-5)
x <- scale(x.orig)  
y <- scale(y.orig) 
z <- rnorm(20)

t. <- interp(x,y,z)
t.df <- data.frame(t.)

gt <- data.frame( expand.grid(x=t.$x, 
                              y=t.$y), 
                  z=c(t.$z), 
                  value=cut(c(t.$z), 
                            breaks=seq(min(z),max(z),0.25)))

p <- ggplot(gt) + geom_tile(aes(x,y,fill=value)) + 
    geom_contour(aes(x=x,y=y,z=z), colour="black") 

get.labels <- function(break.points, orig.data, scaled.data, digits) { 
    labels <- as.character(lapply(break.points,      
            function(i) round(i * min(orig.data) 
                              / min(scaled.data),
                              digits)
                                  )
                           )
    labels
}

x.break.points <- seq(min(x), max(x), 0.5)
x.labels <- get.labels(x.break.points, x.orig, x, digits=2)
p <- p + scale_x_continuous(breaks=x.break.points, 
                            labels=x.labels)

y.break.points <- seq(min(y), max(y), 0.5)
y.labels <- get.labels(y.break.points, y.orig, y, digits=8)
p <- p + scale_y_continuous(breaks=y.break.points, 
                            labels=y.labels)

p

Heat map with properly labeled axes

daedalus
  • 10,873
  • 5
  • 50
  • 71
Alex
  • 4,030
  • 8
  • 40
  • 62
  • Thanks @x-he, we are almost there it seems. I have updated the question to clarify that the labels L1-L4 should refer back to the original scales. Kindly have a look at the updated code in the question? – daedalus Jun 02 '12 at 13:45
  • +1 for pointing me in the right direction. I have completed the solution and updated the question. I will suggest an edit for your answer. If you accept, then this gets the tick :) – daedalus Jun 02 '12 at 14:25
  • I have a question about the scale. You said you wanted the ticks to refer to the original scale. But don't the ticks in the plot in your updated question refer to the scale after centering(?) ? – Alex Jun 02 '12 at 15:17
  • Oh, never mind :) I guess the updated plot in my answer has the original scale. – Alex Jun 02 '12 at 15:19
  • The problem was that x.orig and y.orig were too dissimilar for interpolation. I wanted to rescale them for plotting, but then map the labels back to the original values. This is achieved with your break.points idea. Thanks again :) – daedalus Jun 02 '12 at 15:20