Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Colours across Plots / Heatmaps in R

I am creating a number of heatmaps in R, but I am having problems when it comes to keeping the colour scale consistent across graphs.

I find that the colours are scaled within a graph, is there a way to make colours consistent across graphs? Ie. So that that colour difference between a value of 0.4 and 0.5 is always the same?

Code Example:

set.seed(123)

d1 = matrix(rnorm(9, mean = 0.2, sd = 0.1), ncol = 3)
d2 = matrix(rnorm(9, mean = 0.8, sd = 0.1), ncol = 3)

mat = list(d1, d2)

for(m in mat)
  heatmap(m, Rowv = NA ,Colv = NA)

You'll note in the example that cell (2,3) the first graph is similar to cell (1,3) in the second, despite being ~0.8 different

like image 393
SamPassmore Avatar asked Dec 29 '25 13:12

SamPassmore


2 Answers

Here's a way to do it with ggplot2, if you're open to not using base graphics:

library(reshape2)
library(ggplot2)

# Set common limits for color scale
limits = range(unlist(mat))

Here's the code for two separate graphs. The last line of code for each graph ensures that they use the same z limits for setting the colors:

ggplot(melt(mat[[1]]), aes(Var1, Var2, fill=value)) +
  geom_tile() + 
  scale_fill_continuous(limits=limits)

ggplot(melt(mat[[2]]), aes(Var1, Var2, fill=value)) +
  geom_tile() + 
  scale_fill_continuous(limits=limits)

enter image description here

Another option is to plot both heatmaps in a single graph using facetting, which automatically ensures both graphs are on the same color scale:

ggplot(melt(mat), aes(Var1, Var2, fill=value))   +
  geom_tile() + 
  facet_grid(. ~ L1)

enter image description here

I've used the default colors here, but for either approach you can set the color scale to be anything you wish. For example:

ggplot(melt(mat), aes(Var1, Var2, fill=value))   +
  geom_tile() + 
  facet_grid(. ~ L1) +
  scale_fill_gradient(low="red", high="green")

enter image description here

like image 183
eipi10 Avatar answered Dec 31 '25 05:12

eipi10


You could use the image function directly (heatmap uses image), though it will require some extra formatting to match the output of heatmap. You can use zlim to set the color range. Quoting from the ?image page:

the minimum and maximum z values for which colors should be plotted, defaulting to the range of the finite values of z. Each of the given colors will be used to color an equispaced interval of this range. The midpoints of the intervals cover the range, so that values just outside the range will be plotted.

# define zlim min and max for all the plots
minz = Reduce(min, mat)
maxz = Reduce(max, mat)

for(m in mat) {
  image( m, zlim = c(minz, maxz), col = heat.colors(20))
}

To get closer to the formatting produced by heatmap, you can just reuse some code from the heatmap function:

for(m in mat) {
  labCol = dim(m)[2]
  labRow = dim(m)[1]
  image(seq_len(labCol), seq_len(labRow), m, zlim = c(minz, maxz),
    col = heat.colors(20), axes = FALSE, xlab = "", ylab = "",
    xlim = 0.5 + c(0, labCol), ylim = 0.5 + c(0, labRow))
  axis(1, 1L:labCol, labels = seq_len(labCol), las = 2, line = -0.5, tick = 0)
  axis(4, 1L:labRow, labels = seq_len(labRow), las = 2, line = -0.5, tick = 0)
}

enter image description here

Using the breaks argument to image is another option. It allows more flexibility than zlim in setting the breakpoints for colors. Quoting from the help page, breaks is

a set of finite numeric breakpoints for the colours: must have one more breakpoint than colour and be in increasing order. Unsorted vectors will be sorted, with a warning.

like image 21
Jota Avatar answered Dec 31 '25 03:12

Jota



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!