Problem trying to decorate a heatmap inside a function
3
0
Entering edit mode
AR3513 • 0
@ar3513-11025
Last seen 3.7 years 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) : 
  Viewport 'ht1_dend_column' was not found

Any idea about how to solve this??

Thanks very much in advance, 

Best wishes, 

Andrea

complexheatmap • 2.0k views
ADD COMMENT
0
Entering edit mode
@james-w-macdonald-5106
Last seen 9 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))
  })
}
ADD COMMENT
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
ADD REPLY
0
Entering edit mode
AR3513 • 0
@ar3513-11025
Last seen 3.7 years 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)

Error in column_dend(ht1) : object 'ht1' not found

 

ADD COMMENT
0
Entering edit mode

If you have more questions, use the ADD REPLY button, not the Add your answer box, which is for adding answers.

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

ADD REPLY
0
Entering edit mode
AR3513 • 0
@ar3513-11025
Last seen 3.7 years ago

Hi again, 

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

Best wishes, 

Andrea

ADD COMMENT

Login before adding your answer.

Traffic: 748 users visited in the last hour
Help About
FAQ
Access RSS
API
Stats

Use of this site constitutes acceptance of our User Agreement and Privacy Policy.

Powered by the version 2.3.6