0

I would like to create a heat map showing the highest value in a colour maybe light blue and the lowest value in dark blue and different shades throughout the column. This should be on a column by column basis not on the full table.

How would I get about doing this?

Sample code:

library(gtable)
library(grid)
library(gridExtra)

g <- tableGrob(iris[1:4, 1:3])
g <- gtable_add_grob(g,
    grobs = rectGrob(gp = gpar(fill = NA, lwd = 2)),
    t = 2, b = nrow(g), l = 1, r = ncol(g))
g <- gtable_add_grob(g,
    grobs = rectGrob(gp = gpar(fill = NA, lwd = 2)),
    t = 1, l = 1, r = ncol(g))
grid.draw(g)
AkselA
  • 8,153
  • 2
  • 21
  • 34
user2946746
  • 1,740
  • 3
  • 21
  • 36
  • I'm thinking you could use a formula based on the value in the cell and the max of the column. With grobs g$grobs[2][[1]][["gp"]] My problem is i"m not sure how the grobs are structured. What does the 2, 1, and "gp" stand for? – user2946746 May 18 '17 at 19:27
  • Any luck? It took me some time figure out what you were looking for, but I think I'm about there. Can't know for certain though, unless you give some feed-back. – AkselA May 21 '17 at 19:52
  • this should be close enough: http://stackoverflow.com/a/32711620/471093 – baptiste May 22 '17 at 00:10

2 Answers2

1

You can do it by defining a theme

library(gtable)
library(grid)
library(gridExtra)

iris <- as.matrix(iris[1:4, 1:3])

# a simple function to scale each column to the range [0, 1]
norm <- function(x) {
    apply(x, 2, function(y){(y-min(y))/(max(y)-min(y))})
}

bluecol <- colorRamp(c("#3366EE", "#AABBFF", "#DDDDFF"))(norm(iris))
bluecol <- rgb(bluecol[, 1], bluecol[, 2], bluecol[, 3], max=255)

tt <- ttheme_default(core=list(bg_params=list(fill=bluecol)))

g <- tableGrob(iris, theme=tt)
g <- gtable_add_grob(g,
    grobs = rectGrob(gp = gpar(fill = NA, lwd = 2)),
    t = 2, b = nrow(g), l = 1, r = ncol(g))
g <- gtable_add_grob(g,
    grobs = rectGrob(gp = gpar(fill = NA, lwd = 2)),
    t = 1, l = 1, r = ncol(g))
grid.draw(g)

enter image description here

AkselA
  • 8,153
  • 2
  • 21
  • 34
  • @user2946746: Good to hear. When an answer is found to be helpful, it is also customary to [accept](https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work) it. – AkselA May 23 '17 at 20:06
0

There's a little-known feature in grid.table that lets you overwrite the function responsible for creating the textGrob for each cell with an arbitrary grob. So it is theoretically possible to process the value of each cell and turn it in a coloured rectangle, for instance, or a sparkline, etc. It's a bit awkward though, and very slow. Here's an illustration with a common scale for the whole table, but it should be easy to adapt to the problem (but I don't think grid.table is the right approach to start with).

enter image description here

d <- as.matrix(iris[1:4, 1:3])

colourise <- function(d, colours = blues9){
  new <- scales::colour_ramp(colours)(scales::rescale(d))
  dim(new) <- dim(d)
  new
}

library(grid)
library(gridExtra)

my_fun <- function(label, ...){

  g <- rectGrob( gp=gpar(fill=label,col="white",lwd=2))
  grobTree(g,cl="cell") # wrapper to give a size
}

# cells need an absolute size
widthDetails.cell <- function(x)
  unit(1,"lines")
heightDetails.cell <- function(x)
  unit(1,"lines")


tt <- ttheme_minimal(12, core=list(fg_fun = my_fun), 
                     colhead=list(fg_params=list(fontface="bold")))

grid.newpage()
grid.arrange(tableGrob(colourise(d), cols=colnames(d), theme = tt), tableGrob(d,rows=NULL))
baptiste
  • 75,767
  • 19
  • 198
  • 294