Problem trying to decorate a heatmap inside a function
3
0
Entering edit mode
AR3513 • 0
@ar3513-11025
Last seen 13 months ago

Hello,

I'm trying to write a function that creates and decorates a heatmap based on a given input data. The code works well, but not when it's written within a function. I'll simplify what I mean by using a very simple example from one of the vignettes of the package:

library(ComplexHeatmap)

## Generate data

mat = matrix(rnorm(80, 2), 8, 10)
mat = rbind(mat, matrix(rnorm(40, -2), 4, 10))
rownames(mat) = paste0("R", 1:12)
colnames(mat) = paste0("C", 1:10)

## Create and decorate the heatmap: this works well

Heatmap(mat, name = "ht1", km = 2)

decorate_column_dend("ht1", {
tree = column_dend(ht1)
ind = cutree(as.hclust(tree), k = 2)[order.dendrogram(tree)]

first_index = function(l) which(l)[1]
last_index = function(l) { x = which(l); x[length(x)] }
x1 = c(first_index(ind == 1), first_index(ind == 2)) - 1
x2 = c(last_index(ind == 1), last_index(ind == 2))
grid.rect(x = x1/length(ind), width = (x2 - x1)/length(ind), just = "left",
default.units = "npc", gp = gpar(fill = c("#FF000040", "#00FF0040"), col = NA))
})

##  Create and decorate heatmap inside of a function: ERROR!

do_heatmap = function (mat) {
Heatmap(mat, name = "ht1", km = 2)

decorate_column_dend("ht1", {
tree = column_dend(ht1)
ind = cutree(as.hclust(tree), k = 2)[order.dendrogram(tree)]

first_index = function(l) which(l)[1]
last_index = function(l) { x = which(l); x[length(x)] }
x1 = c(first_index(ind == 1), first_index(ind == 2)) - 1
x2 = c(last_index(ind == 1), last_index(ind == 2))
grid.rect(x = x1/length(ind), width = (x2 - x1)/length(ind), just = "left",
default.units = "npc", gp = gpar(fill = c("#FF000040", "#00FF0040"), col = NA))
})
}

## Test the function

do_heatmap(mat)

Error in grid.Call.graphics(C_downviewport, name\$name, strict) :

Any idea about how to solve this??

Best wishes,

Andrea

complexheatmap • 925 views
0
Entering edit mode
@james-w-macdonald-5106
Last seen 3 hours ago
United States

You have to make sure the heatmap is plotted before you can make any changes to it.

do_heatmap = function (mat) {
draw(Heatmap(mat, name = "ht1", km = 2))

decorate_column_dend("ht1", {
tree = column_dend(ht1)
ind = cutree(as.hclust(tree), k = 2)[order.dendrogram(tree)]

first_index = function(l) which(l)[1]
last_index = function(l) { x = which(l); x[length(x)] }
x1 = c(first_index(ind == 1), first_index(ind == 2)) - 1
x2 = c(last_index(ind == 1), last_index(ind == 2))
grid.rect(x = x1/length(ind), width = (x2 - x1)/length(ind), just = "left",
default.units = "npc", gp = gpar(fill = c("#FF000040", "#00FF0040"), col = NA))
})
}
0
Entering edit mode
Great!! Thanks so much!! Best regards, Andrea ________________________________ From: James W. MacDonald [bioc] <noreply@bioconductor.org> Sent: 26 April 2017 17:17:28 To: Rodriguez Martinez, Andrea Subject: [bioc] A: Problem trying to decorate a heatmap inside a function Activity on a post you are following on support.bioconductor.org<https: support.bioconductor.org=""> User James W. MacDonald<https: support.bioconductor.org="" u="" 5106=""/> wrote Answer: Problem trying to decorate a heatmap inside a function<https: support.bioconductor.org="" p="" 95294="" #95298="">: You have to make sure the heatmap is plotted before you can make any changes to it. do_heatmap = function (mat) { draw(Heatmap(mat, name = "ht1", km = 2)) decorate_column_dend("ht1", { tree = column_dend(ht1) ind = cutree(as.hclust(tree), k = 2)[order.dendrogram(tree)] first_index = function(l) which(l)[1] last_index = function(l) { x = which(l); x[length(x)] } x1 = c(first_index(ind == 1), first_index(ind == 2)) - 1 x2 = c(last_index(ind == 1), last_index(ind == 2)) grid.rect(x = x1/length(ind), width = (x2 - x1)/length(ind), just = "left", default.units = "npc", gp = gpar(fill = c("#FF000040", "#00FF0040"), col = NA)) }) } ________________________________ Post tags: complexheatmap You may reply via email or visit A: Problem trying to decorate a heatmap inside a function
0
Entering edit mode
AR3513 • 0
@ar3513-11025
Last seen 13 months ago

Hello,

I have now another question regarding this. As you can see below, in this small toy function I generate a variable called ht1, that then should be used by "decorate_column_dend()", however, when when I run the function I get an error message saying that ht1 was not found. Any help??

Thanks very much,

Andrea

## Generate data

mat = matrix(rnorm(80, 2), 8, 10)
mat = rbind(mat, matrix(rnorm(40, -2), 4, 10))
rownames(mat) = paste0("R", 1:12)
colnames(mat) = paste0("C", 1:10)

## Function

do_heatmap = function (mat) {

ht1 = Heatmap(mat, name = "ht1", km = 2)
draw(Heatmap(mat, name = "ht1", km = 2))
decorate_column_dend("ht1", {
tree = column_dend(ht1)
ind = cutree(as.hclust(tree), k = 2)[order.dendrogram(tree)]
first_index = function(l) which(l)[1]
last_index = function(l) { x = which(l); x[length(x)] }
x1 = c(first_index(ind == 1), first_index(ind == 2)) - 1
x2 = c(last_index(ind == 1), last_index(ind == 2))
grid.rect(x = x1/length(ind), width = (x2 - x1)/length(ind), just = "left",
default.units = "npc", gp = gpar(fill = c("#FF000040", "#00FF0040"), col = NA))
})
}

do_heatmap(mat)

0
Entering edit mode

The problem you see has to do with how R separates things into different environments. It's beyond the scope of this question to get too deep, but let's try to get to the point without going too deep into the details.

The decorate_* functions in ComplexHeatmap are intended to parse the code between { }, based on variables in a particular environment. The function itself specifies an environment, and there is a parent.env that is 'above' the function environment. By default the decorate_* functions assume that the objects that you are trying to use between the { } are in the parent.env, rather than the function's environment.

For example if you look at the vignette for decorating heatmaps, the heatmap is drawn, then the decorate_dend function is called, so in that case R has to look to the parent.env to get the objects. But in your case, you are creating the heatmap within the function itself, so you can't look to the parent.env for ht1, because it's not there -  it's in the function's environment! You have to specifically say that you want to look at the current environment, rather than the parent:

do_heatmap = function (mat) {
ht1 <- Heatmap(mat, name = "ht1", km = 2)
draw(ht1)
decorate_dend("ht1", {
tree = column_dend(ht1)
ind = cutree(as.hclust(tree), k = 2)[order.dendrogram(tree)]
first_index = function(l) which(l)[1]
last_index = function(l) { x = which(l); x[length(x)] }
x1 = c(first_index(ind == 1), first_index(ind == 2)) - 1
x2 = c(last_index(ind == 1), last_index(ind == 2))
grid.rect(x = x1/length(ind), width = (x2 - x1)/length(ind), just = "left",
default.units = "npc", gp = gpar(fill = c("#FF000040", "#00FF0040"), col = NA))
}, envir = as.environment(1L))
}

Also note that I am using decorate_dend rather than decorate_column_dend

0
Entering edit mode
AR3513 • 0
@ar3513-11025
Last seen 13 months ago

Hi again,

Thanks very much for your very detailed response. That is extremely helpful.

Best wishes,

Andrea