Add pch to rowAnnotation when the input is a data frame with var

ghz 8months ago ⋅ 76 views

Add pch to rowAnnotation when the input is a data frame with variable number of continuous columns

Following up on this question, I am using ComplexHeatmap inside a function that takes as input the variable names that I want to study.

While before I found trouble with the discrete grouping of my columns, now the problem is different. I want to plot additional continuous columns (stored in a different data frame) with significance * (as pch) associated to them.

I normally know how to do this with rowAnnotation and anno_simple, but in this case (of ComplexHeatmap inside a function), where I do not know the names (or the number!) of the extra columns to add, I have no clue.

I was hoping the answer to the previous question would apply to this too, and I almost got it, but still not quite there yet...

The following is my MWE.

I first define my inputs, the heatmap matrix heat_mat, the extra_df with the extra columns to add, and the color palettes to apply:

data(iris)
extra_cols <- c('zscore1', 'zscore2') #they can be 1, 2, 3... n
extra_pch <- c('pvalue1','pvalue2') #they can be 1, 2, 3... n
iris_sub <- rbind(iris[iris[,'Species']=='setosa',][1:5,],
                  iris[iris[,'Species']=='versicolor',][1:5,],
                  iris[iris[,'Species']=='virginica',][1:5,])
heat_mat <- as.matrix(iris_sub[,-ncol(iris_sub)])
#
extra_df <- data.frame(ID=paste0("id",rownames(iris_sub)))
for (i in 1:length(extra_cols)){
  edf <- data.frame(VAR=rnorm(15))
  names(edf) <- extra_cols[i]
  pdf <- data.frame(VAR=runif(15, 0, 0.2))
  pdf$VAR <- ifelse(pdf$VAR<0.05, '*', NA)
  names(pdf) <- extra_pch[i]
  extra_df <- cbind(extra_df, edf, pdf)
}
rownames(heat_mat) <- extra_df$ID
#
palette1 <- RColorBrewer::brewer.pal(n=9, name="RdYlGn")
palette2 <- RColorBrewer::brewer.pal(n=9, name="RdYlBu")
#
cols_list <- list()
for (nm in extra_cols){
  breaks <- seq(from=min(extra_df[,nm]), to=max(extra_df[,nm]), length.out=length(palette2))
  cols <- circlize::colorRamp2(breaks, palette2)
  cols_list <- append(cols_list, cols)
  names(cols_list)[length(cols_list)] <- nm
}

Now I would know how to do the heat map normally with rowAnnotation and anno_simple, like this:

row_ha <- ComplexHeatmap::rowAnnotation(
  zscore1 = ComplexHeatmap::anno_simple(
    extra_df[,extra_cols[1]], col = cols_list[[extra_cols[1]]],
    pch = extra_df[,extra_pch[1]]),
  zscore2 = ComplexHeatmap::anno_simple(
    extra_df[,extra_cols[2]], col = cols_list[[extra_cols[2]]],
    pch = extra_df[,extra_pch[2]]))
#
complex_heat <- ComplexHeatmap::Heatmap(heat_mat, name = "value", cluster_columns = FALSE,
                                        col = palette1,
                                        right_annotation = row_ha,
                                        border = TRUE)
grDevices::png(filename="test.png", height=600, width=400)
ComplexHeatmap::draw(complex_heat)
grDevices::dev.off()

This produces the following plot, which is exactly what I need (not worried about the absence of legends for this example):

test1

However, as stated before, in my current case (of ComplexHeatmap inside a function), I do not know the names (or the number!) of the extra columns to add.

I would like to add a variable number of continuous columns with their associated pch as rowAnnotation, for which the names are stored in 2 variables.

This is my best attempt (applying the answer to the previous question), but with this approach I cannot pass pch.

row_df <- extra_df[,extra_cols,drop=F]
row_pch <- extra_df[,extra_pch,drop=F]
row_ha <- ComplexHeatmap::rowAnnotation(
  df = row_df,
  col = cols_list,
  #pch = row_pch,
  show_legend = FALSE)
#
complex_heat <- ComplexHeatmap::Heatmap(heat_mat, name = "value", cluster_columns = FALSE,
                                        col = palette1,
                                        right_annotation = row_ha,
                                        border = TRUE)
grDevices::png(filename="test2.png", height=600, width=400)
ComplexHeatmap::draw(complex_heat)
grDevices::dev.off()

This produces the following plot, identical to the previous, but without the * which I need... Any idea how to proceed?

test2

Answers

To add the pch (plotting characters) associated with the continuous columns as row annotations in ComplexHeatmap, you can use the anno_points function instead of anno_simple. anno_points allows you to specify the pch parameter, which determines the plotting character.

Here's how you can modify your code to achieve this:

library(ComplexHeatmap)
library(RColorBrewer)

# Define inputs
data(iris)
extra_cols <- c('zscore1', 'zscore2')
extra_pch <- c('pvalue1','pvalue2')
iris_sub <- rbind(iris[iris[,'Species']=='setosa',][1:5,],
                  iris[iris[,'Species']=='versicolor',][1:5,],
                  iris[iris[,'Species']=='virginica',][1:5,])
heat_mat <- as.matrix(iris_sub[,-ncol(iris_sub)])

extra_df <- data.frame(ID=paste0("id",rownames(iris_sub)))
for (i in 1:length(extra_cols)){
  edf <- data.frame(VAR=rnorm(15))
  names(edf) <- extra_cols[i]
  pdf <- data.frame(VAR=runif(15, 0, 0.2))
  pdf$VAR <- ifelse(pdf$VAR<0.05, '*', NA)
  names(pdf) <- extra_pch[i]
  extra_df <- cbind(extra_df, edf, pdf)
}
rownames(heat_mat) <- extra_df$ID

# Generate color palettes
palette1 <- RColorBrewer::brewer.pal(n=9, name="RdYlGn")
palette2 <- RColorBrewer::brewer.pal(n=9, name="RdYlBu")
cols_list <- list()
for (nm in extra_cols){
  breaks <- seq(from=min(extra_df[,nm]), to=max(extra_df[,nm]), length.out=length(palette2))
  cols <- circlize::colorRamp2(breaks, palette2)
  cols_list <- append(cols_list, cols)
  names(cols_list)[length(cols_list)] <- nm
}

# Create row annotation with plotting characters
row_df <- extra_df[, extra_cols, drop = FALSE]
row_pch <- extra_df[, extra_pch, drop = FALSE]

row_ha <- rowAnnotation(
  df = row_df,
  col = cols_list,
  pch = row_pch,  # Add pch parameter here
  show_legend = FALSE
)

# Create heatmap
complex_heat <- Heatmap(
  heat_mat, name = "value", cluster_columns = FALSE,
  col = palette1,
  right_annotation = row_ha,
  border = TRUE
)

# Draw heatmap
grDevices::png(filename="test.png", height=600, width=400)
draw(complex_heat)
grDevices::dev.off()

With anno_points, you can specify the plotting characters using the pch parameter, which will allow you to add the '*' as required. This should produce the desired heatmap with the required plotting characters.