jokergoo / EnrichedHeatmap

make enriched heatmap which visualizes the enrichment of genomic signals to specific target regions.
http://jokergoo.github.io/EnrichedHeatmap/
Other
187 stars 25 forks source link

question on color scale on multiple heatmaps #7

Closed crazyhottommy closed 8 years ago

crazyhottommy commented 8 years ago

Hi,

It is a more general question on ComplexHeatmaps as well. If I am plotting multiple matrix on a single figure. The color scale is the same across all heatmaps by default?

in the help page

It seems one can map color to values differently in different heatmaps:

f1 = colorRamp2(seq(min(mat), max(mat), length = 3), c("blue", "#EEEEEE", "red"))
f2 = colorRamp2(seq(min(mat), max(mat), length = 3), c("blue", "#EEEEEE", "red"), space = "RGB")
Heatmap(mat, col = f1, column_title = "LAB color space") +
Heatmap(mat, col = f2, column_title = "RGB color space")

For EnrichedHeatmap, I usually do only specify col=c("white","red"), how does this exactly mapped to the numeric values in the matrix? and the value to color mapping will be the same across all the heatmaps?

A side question would be if I want to add a line annotation in one heatmap, I can add top_annotation = HeatmapAnnotation(lines = anno_enriched())

or if I do a clustering (k-means) on the same heatmap (matrix), I can

top_annotation = HeatmapAnnotation(lines = anno_enriched(gp = gpar(col = 2:4)))

However, I want to add 2 lines for the same line graph from two different matrix (heatmap), so I can compare, how can I do it? I have a way to get around something like:

plot(colMeans(mat1))
plot(colMeans(mat2))

I can then use ggplot2 to make the two lines together...

Is there a way to do it inside EnrichedHeatmaps and I can put the line graph side by side the heatmaps?, now it has one line graph on top of each heatmap. Thanks for making such a useful package and being very responsive.

Best, Ming

jokergoo commented 8 years ago

Hi Ming,

Actually all heatmaps are independent to each other and each heatmap has its own settings.

By default blue-white-red are mapped to min-mean-max and colors are linearly interpolated for other values. If you specify col=c("white","red"), minimal value is mapped to white and maximal value is mapped to red. If the matrix have different ranges, the color mapping is not identical across heatmaps.

If you want colors in parallel heatmaps comparable, I would suggest to use a color mapping function. E.g.

common_min = min(c(mat1, mat2))
common_max = max(c(mat1, mat2))
col_fun = circlize::colorRamp2(c(common_min, common_max), c("white", "red"))
Heatmap(..., col = col_fun) + Heatmap(..., col = col_fun)

I am not quite sure for your second question. "add 2 lines for the same line graph from two different matrix", do you mean you have two heatmaps and you want to put line annotations for the both two heatmaps? If so, you can specify column annotation in both heatmaps:

EnrichedHeatmap(mat1, ..., top_annotation = HeatmapAnnotation(e1 = anno_enriched())) +
EnrichedHeatmap(mat2, ..., top_annotation = HeatmapAnnotation(e2 = anno_enriched()))

Maybe you can check the second plot in the section in this link: http://www.bioconductor.org/packages/devel/bioc/vignettes/EnrichedHeatmap/inst/doc/EnrichedHeatmap.html#toc_12

Cheers, Zuguang

crazyhottommy commented 8 years ago

Thanks! I am pretty clear on the first question now.

for the second question,

EnrichedHeatmap(mat1, col= c("white","red"), name = "A", 
                axis_name = c("-5kb", "peak center", "5kb"), pos_line = FALSE)  +
        EnrichedHeatmap(mat2, col= c("white","red"), name = "B",
                axis_name = c("-5kb", "peak center", "5kb"),
                axis_name_rot = 0, pos_line = FALSE)

I can add a line graph on EACH of the heatmap by what you did:

EnrichedHeatmap(mat1, col= c("white","red"), name = "A", 
                axis_name = c("-5kb", "peak center", "5kb"), pos_line = FALSE,
                top_annotation = HeatmapAnnotation(e1 = anno_enriched()),
                top_annotation_height = unit(2, "cm"))  +
        EnrichedHeatmap(mat2, col= c("white","red"), name = "B",
                axis_name = c("-5kb", "peak center", "5kb"),
                axis_name_rot = 0, pos_line = FALSE,
                top_annotation = HeatmapAnnotation(e2 = anno_enriched()),
                top_annotation_height = unit(2, "cm"))

but I want to merge the two lines in to one line graph. Hope I made myself clear this time.

Thanks! Ming

jokergoo commented 8 years ago

OK, in this case, you need to write your own annotation function. I can give you a simple example.

First construct an annotation function which add two lines into one annotation area. This function should accepts index as the only argument which is the index of columns in the matrix.

anno_col_means = function(index) {
    col_means_1 = colMeans(mat1, na.rm = TRUE)[index]
    col_means_2 = colMeans(mat2, na.rm = TRUE)[index]

    n = length(index)
    rg = range(c(col_mean_1, col_mean_2))

    pushViewport(viewport(xscale = c(0.5, n + 0.5), yscale = rg))
    grid.rect(gp = gpar(fill = "transparent"))
    grid.lines(1:n, col_means_1, default.units = "native")
    grid.lines(1:n, col_means_2, default.units = "native")
    grid.yaxis(gp = gpar(fontsize = 8))
    upViewport()
}

Then send it to the top_annotation option:

EnrichedHeatmap(..., top_annotation = HeatmapAnnotation(col_means = anno_col_means))
crazyhottommy commented 8 years ago

great. The prototype works. I might need to learn some grid to make full usage of Complexheatmaps.

Thanks, Ming

FirasSadiyah commented 6 years ago

What if I do not want to merge the two lines into one line graph, but rather, I would like to have the same y-axis for top annotation of all heatmaps?

jokergoo commented 6 years ago

You can use ylim argument in in anno_enriched() function to set to the same value for all heatmaps.

FirasSadiyah commented 6 years ago

Many thanks. It worked great.

For completeness, I passed the min and max values to ylim as follow: top_annotation = HeatmapAnnotation(lines = anno_enriched(ylim = c(1,15) ))

Jome0169 commented 5 years ago

How is the ylim value calculated? I'm attempting to do something similar to @FirasSadiyah , but i'm passing in two normalized matrix objects into a function, and plotting them together. However, I'm unsure how the Y axis value corresponds to the legend, as the documentation only states Ranges on y-axis. By default it is inferred from the data.

How is it inferred from the data? Is there an easy way to retrieve the 'max' of the largest Y axis?

Jome0169 commented 5 years ago

Actually, I just figured this out. Found from code at line 86 here https://github.com/jokergoo/epik/blob/bb7d34f7fc46f3d49337c90264c17df1282e2b6b/roadmap/scripts/unused/correlated_regions_general_heatmap.R

So, given multiple matrices, just take the mean of all columns, and take the max value. Then use ylim as indicated above by https://github.com/FirasSadiyah y_max_val <- round(max(colMeans(TES_matrix, na.rm = TRUE), colMeans(TSS_matrix, na.rm = TRUE))) + 2

jokergoo commented 5 years ago

@Jome0169 You are right. The lines on the top of the heatmap show the mean trend for each position among matrix rows (colMeans(mat)).