Search code examples
rheatmapnamescomplexheatmap

Change the names of a HeatmapAnnotation object


I am doing a ComplexHeatmap as per normal, the only difference now is that I have it inside a function that takes as input the variable name that I want to study (in the MWE below: Species).

See the my_var variable in the MWE. Literally the only thing I want to do, is to be able to assign this variable as name to the HeatmapAnnotation object (that defines the column annotations).

I cannot do the following since the name of the variable (in this case Species) is stored in my_var:

column_ha <- ComplexHeatmap::HeatmapAnnotation(
  Species = meta_df$Species,
  col = list(Species = col_vector))

Instead, what I try to do is to use a placeholder name, and then try to change column_ha name with my_var, like this:

col_list <- list(VAR = col_vector)
names(col_list) <- my_var
column_ha <- ComplexHeatmap::HeatmapAnnotation(
  VAR = meta_df[,my_var],
  col = col_list)
names(column_ha) <- my_var

This does nothing. I can see VAR in the heatmap and the colors for the Species are all messed up.

This is my MWE:

data(iris)
my_var <- 'Species'
iris_sub <- rbind(iris[iris[,my_var]=='setosa',][1:5,],
                  iris[iris[,my_var]=='versicolor',][1:5,],
                  iris[iris[,my_var]=='virginica',][1:5,])
heat_mat <- t(as.matrix(iris_sub[,-ncol(iris_sub)]))
#
meta_df <- data.frame(ID=paste0("id",rownames(iris_sub)), VAR=iris_sub[,ncol(iris_sub)])
names(meta_df)[2] <- my_var
colnames(heat_mat) <- meta_df$ID
#
palette1 <- RColorBrewer::brewer.pal(n=9, name="RdYlGn")
col_vector <- RColorBrewer::brewer.pal(3, 'Set1')
col_vector <- stats::setNames(col_vector, levels(meta_df[,my_var]))
#
col_list <- list(VAR = col_vector)
names(col_list) <- my_var
column_ha <- ComplexHeatmap::HeatmapAnnotation(
  VAR = meta_df[,my_var],
  col = col_list)
names(column_ha) <- my_var
#
complex_heat <- ComplexHeatmap::Heatmap(heat_mat, name = "value", cluster_columns = FALSE,
                                        col = palette1,
                                        top_annotation = column_ha,
                                        border = TRUE)
grDevices::png(filename="test.png", height=400, width=600)
ComplexHeatmap::draw(complex_heat)
grDevices::dev.off()

Which produces the following heatmap:

test1

... which is all wrong. See that the placeholder name VAR is still there, and the Species colors in the column annotation on top are all wrong (not col_vector which should be Set1 red, blue, green).

So the question is: How to assign new names to a HeatmapAnnotation object?

Please note that if I don't have the name Species stored in the my_var variable, it works well, so I don't see the problems in my code.

See this MWE for how the final heatmap should look like (here it works cause I don't have the name Species stored in the my_var variable):

data(iris)
iris_sub <- rbind(iris[iris[,'Species']=='setosa',][1:5,],
                  iris[iris[,'Species']=='versicolor',][1:5,],
                  iris[iris[,'Species']=='virginica',][1:5,])
heat_mat <- t(as.matrix(iris_sub[,-ncol(iris_sub)]))
#
meta_df <- data.frame(ID=paste0("id",rownames(iris_sub)), Species=iris_sub[,ncol(iris_sub)])
colnames(heat_mat) <- meta_df$ID
#
palette1 <- RColorBrewer::brewer.pal(n=9, name="RdYlGn")
col_vector <- RColorBrewer::brewer.pal(3, 'Set1')
col_vector <- stats::setNames(col_vector, levels(meta_df$Species))
#
column_ha <- ComplexHeatmap::HeatmapAnnotation(
  Species = meta_df$Species,
  col = list(Species = col_vector))
#
complex_heat <- ComplexHeatmap::Heatmap(heat_mat, name = "value", cluster_columns = FALSE,
                                        col = palette1,
                                        top_annotation = column_ha,
                                        border = TRUE)
grDevices::png(filename="test.png", height=400, width=600)
ComplexHeatmap::draw(complex_heat)
grDevices::dev.off()

This produces the following correct heatmap that I want to reproduce when I have the name Species stored in the my_var variable:

test2


Solution

  • You were very close. You can pass a dataframe to HeatmapAnnotation, and for the dataframe it is very easy to change the column name to my_var.

    library(ComplexHeatmap)
    data(iris)
    my_var <- 'Species'
    iris_sub <- rbind(iris[iris[,my_var]=='setosa',][1:5,],
                      iris[iris[,my_var]=='versicolor',][1:5,],
                      iris[iris[,my_var]=='virginica',][1:5,])
    heat_mat <- t(as.matrix(iris_sub[,-ncol(iris_sub)]))
    #
    meta_df <- data.frame(ID=paste0("id",rownames(iris_sub)), VAR=iris_sub[,ncol(iris_sub)])
    names(meta_df)[2] <- my_var
    colnames(heat_mat) <- meta_df$ID
    #
    palette1 <- RColorBrewer::brewer.pal(n=9, name="RdYlGn")
    col_vector <- RColorBrewer::brewer.pal(3, 'Set1')
    col_vector <- stats::setNames(col_vector, levels(meta_df[,my_var]))
    #
    col_list <- list(VAR = col_vector)
    names(col_list) <- my_var
    column_ha_df <- data.frame("place_holder" = meta_df[,my_var])
    colnames(column_ha_df) <- my_var
    column_ha <- ComplexHeatmap::HeatmapAnnotation(
      df = column_ha_df,
      col = col_list
    )
    
    complex_heat <- ComplexHeatmap::Heatmap(heat_mat, name = "value", cluster_columns = FALSE,
                                            col = palette1,
                                            top_annotation = column_ha,
                                            border = TRUE)
    
    draw(complex_heat)