Search code examples
rplotheatmappheatmap

pheatmap discrete colormap placement of tick labels


I have a matrix with thousands of cells, with values range from 0-5. I want to use a discrete color palette to indicate the value of the respective cell. This code already works pretty well, but the position of the colormap labels is off. I simply want, that each tick is in the center for the corresponding color..

library("pheatmap")
library("RColorBrewer")

matrix <- round(matrix(rexp(200, rate=.1), ncol=20)/10)
color <- brewer.pal(max(matrix)+1,"Blues")
pheatmap(matrix,color=color,cluster_rows = F,cluster_cols = F)

The example produces a heatmap like this: enter image description here

I want to move the colorbar labels, so it looks more like this: enter image description here

If anyone has an idea how to do this, Id be very thankful!


Solution

  • You can work on the text grob of legend labels (p$gtable$grobs[[2]]$children[[2]]).
    The y-positions of labels are defined as follows:

    library("pheatmap")
    library("RColorBrewer")
    
    set.seed(123)
    matrix <- round(matrix(rexp(200, rate=.1), ncol=20)/10)
    color <- brewer.pal(max(matrix)+1,"Blues")
    p <- pheatmap(matrix, color=color,cluster_rows = F,
                  cluster_cols = F, silent=T)
    
    p$gtable$grobs[[2]]$children[[2]]$y
    
    [1] sum(0*min(1npc, 150bigpts), 1npc, -1*min(1npc, 150bigpts))
    [2] sum(0.142857142857143*min(1npc, 150bigpts), 1npc, -1*min(1npc, 150bigpts))
        ....
    [8] sum(min(1npc, 150bigpts), 1npc, -1*min(1npc, 150bigpts))
    

    Label positions can be modified by changing the multiplicative constants placed before the first min (0, 0.1428, ..., 1).

    # Sometimes the number of colored areas in the legend is not 
    # equal to the number of labels    
    N_col_areas <- length(p$gtable$grobs[[2]]$children[[1]]$y)
    N_labels <- length(p$gtable$grobs[[2]]$children[[2]]$label)
    yseq1 <- seq(0, 1, length.out=N_col_areas)
    center <- yseq1[2]/2
    yseq2 <- seq(center, 1-center, length.out=N_labels)
    
    for (k in 1:(N_labels)) {
      p$gtable$grobs[[2]]$children[[2]]$y[[k]] <- 
              sum(yseq2[k]*min(unit(1,"npc"), unit(150,"bigpts")), 
                  unit(1,"npc"), 
                  -1*min(unit(1,"npc"), unit(150,"bigpts")))
    }
    plot.new()
    print(p)
    

    enter image description here