alanocallaghan/scater

Feature request: allow specification of row annotation colours in `plotHeatmap()`

Closed this issue · 7 comments

We have column_annotation_colors but no row_annotation_colors in plotHeatmap().
I've had uses for row annotation colours and had to revert to using pheatmap() directly to create the plot, so it seems like it could be useful to support it in plotHeatmap().

Rather than add another argument, I wonder if it'd be better to re-consider the implementation of #119 and simply use annotation_colors to cover both column_annotation_colors and row_annotation_colors (i.e. deprecate the former) and also match the argument name in the underlying call to pheatmap()?
I realise this might be attempting to shut the gate after the horse has well and truly bolted.

reprex

# Mock up some data
suppressPackageStartupMessages(library(scater))
example_sce <- mockSCE()
example_sce <- logNormCounts(example_sce)

Can specify colours for column annotations via column_annotation_colors.

plotHeatmap(
  example_sce, 
  features=rownames(example_sce)[1:10], 
  colour_columns_by = "Cell_Cycle",
  column_annotation_colors = list(
    Cell_Cycle = c("G0" = "red", "G1" = "blue", "G2M" = "black", "S" = "pink")))

However, there's no equivalent for row annotations i.e. row_annotation_colors is ignored because it's passed via ... to pheatmap() and it does not have a row_annotation_colors argument.

plotHeatmap(
  example_sce,
  features=rownames(example_sce)[1:10], 
  annotation_row = data.frame(
    class = sample(1:2, 10, replace = TRUE),
    row.names = rownames(example_sce)[1:10]),
  row_annotation_colors = list(class = c("A" = "blue", "B" = "red")))

If instead we attempt to supply row annotation colours via pheatmap()'s annotation_colors but there is a clash and its errors out.

plotHeatmap(
  example_sce,
  features=rownames(example_sce)[1:10], 
  annotation_row = data.frame(
    class = sample(c("A", "B"), 10, replace = TRUE),
    row.names = rownames(example_sce)[1:10]),
  annotation_colors = list(class = c("A" = "blue", "B" = "red")))
#> Error in pheatmap::pheatmap(heat.vals, color = color, breaks = color.breaks, : formal argument "annotation_colors" matched by multiple actual arguments

Created on 2021-05-04 by the reprex package (v2.0.0)

Session info
sessioninfo::session_info()
#> ─ Session info ───────────────────────────────────────────────────────────────
#>  setting  value                       
#>  version  R version 4.0.0 (2020-04-24)
#>  os       Ubuntu 18.04.5 LTS          
#>  system   x86_64, linux-gnu           
#>  ui       X11                         
#>  language en_AU:en                    
#>  collate  en_AU.UTF-8                 
#>  ctype    en_AU.UTF-8                 
#>  tz       Australia/Melbourne         
#>  date     2021-05-04                  
#> 
#> ─ Packages ───────────────────────────────────────────────────────────────────
#>  package              * version  date       lib source        
#>  assertthat             0.2.1    2019-03-21 [1] CRAN (R 4.0.0)
#>  backports              1.2.1    2020-12-09 [1] CRAN (R 4.0.0)
#>  beachmat               2.6.4    2020-12-20 [1] Bioconductor  
#>  beeswarm               0.3.1    2021-03-07 [1] CRAN (R 4.0.0)
#>  Biobase              * 2.50.0   2020-10-27 [1] Bioconductor  
#>  BiocGenerics         * 0.36.1   2021-04-16 [1] Bioconductor  
#>  BiocNeighbors          1.8.2    2020-12-07 [1] Bioconductor  
#>  BiocParallel           1.24.1   2020-11-06 [1] Bioconductor  
#>  BiocSingular           1.6.0    2020-10-27 [1] Bioconductor  
#>  bitops                 1.0-7    2021-04-24 [1] CRAN (R 4.0.0)
#>  cli                    2.5.0    2021-04-26 [1] CRAN (R 4.0.0)
#>  colorspace             2.0-0    2020-11-11 [1] CRAN (R 4.0.0)
#>  crayon                 1.4.1    2021-02-08 [1] CRAN (R 4.0.0)
#>  curl                   4.3      2019-12-02 [1] CRAN (R 4.0.0)
#>  DBI                    1.1.1    2021-01-15 [1] CRAN (R 4.0.0)
#>  DelayedArray           0.16.3   2021-03-24 [1] Bioconductor  
#>  DelayedMatrixStats     1.12.3   2021-02-03 [1] Bioconductor  
#>  digest                 0.6.27   2020-10-24 [1] CRAN (R 4.0.0)
#>  dplyr                  1.0.5    2021-03-05 [1] CRAN (R 4.0.0)
#>  ellipsis               0.3.1    2020-05-15 [1] CRAN (R 4.0.0)
#>  evaluate               0.14     2019-05-28 [1] CRAN (R 4.0.0)
#>  fansi                  0.4.2    2021-01-15 [1] CRAN (R 4.0.0)
#>  farver                 2.1.0    2021-02-28 [1] CRAN (R 4.0.0)
#>  fs                     1.5.0    2020-07-31 [1] CRAN (R 4.0.0)
#>  generics               0.1.0    2020-10-31 [1] CRAN (R 4.0.0)
#>  GenomeInfoDb         * 1.26.7   2021-04-08 [1] Bioconductor  
#>  GenomeInfoDbData       1.2.4    2020-10-28 [1] Bioconductor  
#>  GenomicRanges        * 1.42.0   2020-10-27 [1] Bioconductor  
#>  ggbeeswarm             0.6.0    2017-08-07 [1] CRAN (R 4.0.0)
#>  ggplot2              * 3.3.3    2020-12-30 [1] CRAN (R 4.0.0)
#>  glue                   1.4.2    2020-08-27 [1] CRAN (R 4.0.0)
#>  gridExtra              2.3      2017-09-09 [1] CRAN (R 4.0.0)
#>  gtable                 0.3.0    2019-03-25 [1] CRAN (R 4.0.0)
#>  highr                  0.9      2021-04-16 [1] CRAN (R 4.0.0)
#>  htmltools              0.5.1.1  2021-01-22 [1] CRAN (R 4.0.0)
#>  httr                   1.4.2    2020-07-20 [1] CRAN (R 4.0.0)
#>  IRanges              * 2.24.1   2020-12-12 [1] Bioconductor  
#>  irlba                  2.3.3    2019-02-05 [1] CRAN (R 4.0.0)
#>  knitr                  1.33     2021-04-24 [1] CRAN (R 4.0.0)
#>  lattice                0.20-41  2020-04-02 [4] CRAN (R 4.0.0)
#>  lifecycle              1.0.0    2021-02-15 [1] CRAN (R 4.0.0)
#>  magrittr               2.0.1    2020-11-17 [1] CRAN (R 4.0.0)
#>  Matrix                 1.3-2    2021-01-06 [4] CRAN (R 4.0.3)
#>  MatrixGenerics       * 1.2.1    2021-01-30 [1] Bioconductor  
#>  matrixStats          * 0.58.0   2021-01-29 [1] CRAN (R 4.0.0)
#>  mime                   0.10     2021-02-13 [1] CRAN (R 4.0.0)
#>  munsell                0.5.0    2018-06-12 [1] CRAN (R 4.0.0)
#>  pheatmap               1.0.12   2019-01-04 [1] CRAN (R 4.0.0)
#>  pillar                 1.6.0    2021-04-13 [1] CRAN (R 4.0.0)
#>  pkgconfig              2.0.3    2019-09-22 [1] CRAN (R 4.0.0)
#>  purrr                  0.3.4    2020-04-17 [1] CRAN (R 4.0.0)
#>  R6                     2.5.0    2020-10-28 [1] CRAN (R 4.0.0)
#>  RColorBrewer           1.1-2    2014-12-07 [1] CRAN (R 4.0.0)
#>  Rcpp                   1.0.6    2021-01-15 [1] CRAN (R 4.0.0)
#>  RCurl                  1.98-1.3 2021-03-16 [1] CRAN (R 4.0.0)
#>  reprex                 2.0.0    2021-04-02 [1] CRAN (R 4.0.0)
#>  rlang                  0.4.10   2020-12-30 [1] CRAN (R 4.0.0)
#>  rmarkdown              2.7      2021-02-19 [1] CRAN (R 4.0.0)
#>  rsvd                   1.0.5    2021-04-16 [1] CRAN (R 4.0.0)
#>  S4Vectors            * 0.28.1   2020-12-09 [1] Bioconductor  
#>  scales                 1.1.1    2020-05-11 [1] CRAN (R 4.0.0)
#>  scater               * 1.18.6   2021-02-26 [1] Bioconductor  
#>  scuttle                1.0.4    2020-12-17 [1] Bioconductor  
#>  sessioninfo            1.1.1    2018-11-05 [1] CRAN (R 4.0.0)
#>  SingleCellExperiment * 1.12.0   2020-10-27 [1] Bioconductor  
#>  sparseMatrixStats      1.2.1    2021-02-02 [1] Bioconductor  
#>  stringi                1.5.3    2020-09-09 [1] CRAN (R 4.0.0)
#>  stringr                1.4.0    2019-02-10 [1] CRAN (R 4.0.0)
#>  styler                 1.4.1    2021-03-30 [1] CRAN (R 4.0.0)
#>  SummarizedExperiment * 1.20.0   2020-10-27 [1] Bioconductor  
#>  tibble                 3.1.1    2021-04-18 [1] CRAN (R 4.0.0)
#>  tidyselect             1.1.0    2020-05-11 [1] CRAN (R 4.0.0)
#>  utf8                   1.2.1    2021-03-12 [1] CRAN (R 4.0.0)
#>  vctrs                  0.3.7    2021-03-29 [1] CRAN (R 4.0.0)
#>  vipor                  0.4.5    2017-03-22 [1] CRAN (R 4.0.0)
#>  viridis                0.6.0    2021-04-15 [1] CRAN (R 4.0.0)
#>  viridisLite            0.4.0    2021-04-13 [1] CRAN (R 4.0.0)
#>  withr                  2.4.2    2021-04-18 [1] CRAN (R 4.0.0)
#>  xfun                   0.22     2021-03-11 [1] CRAN (R 4.0.0)
#>  xml2                   1.3.2    2020-04-23 [1] CRAN (R 4.0.0)
#>  XVector                0.30.0   2020-10-27 [1] Bioconductor  
#>  yaml                   2.2.1    2020-02-01 [1] CRAN (R 4.0.0)
#>  zlibbioc               1.36.0   2020-10-27 [1] Bioconductor  
#> 
#> [1] /home/peter/R/x86_64-pc-linux-gnu-library/4.0
#> [2] /usr/local/lib/R/site-library
#> [3] /usr/lib/R/site-library
#> [4] /usr/lib/R/library

Sorry, somehow blanked this when I saw it. Can probably add both *_annotation_colorss and then c them

Not a reprex but runs on master

suppressPackageStartupMessages(library(scater))
example_sce <- mockSCE()
example_sce <- logNormCounts(example_sce)
rowData(example_sce)$class <- sample(c("A", "B"), nrow(example_sce), replace = TRUE)

plotHeatmap(
  example_sce,
  features=rownames(example_sce)[1:10], 
  color_rows_by = "class",
  row_annotation_colors = list(class = c("A" = "blue", "B" = "red")))

Thanks for following up, @alanocallaghan.
A couple of questions/comments:

  1. What happens if a user supplies row_annotation_colors and col_annotation_colors for an annotation that is common to both rows and columns? The example I have in mind is when making a heatmap of cluster marker genes where I may want to annotate rows by which cluster the gene is a marker for and annotate columns by which cluster the sample is a member of. If I 'handcraft' the corresponding heatmap using pheatmap::pheatmap() then I just supply something like annotation_colors = list(cluster = cluster_colours) and both row and column 'cluster' annotations will use the same colour palette. Here, I'm guessing I need to do something like col_annotation_colors = list(cluster = cluster_colours), row_annotation_colors = list(cluster = cluster_colours), but https://github.com/Alanocallaghan/scater/blob/092703b2bd3dca6d97ca85b5dbe887a661388281/R/plotHeatmap.R#L217 will lead to 2 entries named cluster in annotation_colors. If the two colour palettes are identical then its safe to do something like annotation_colors <- unique(c(row_annotation_colors, column_annotation_colors)) or annotation_colors <- intersect(row_annotation_colors, column_annotation_colors), but what happens if the user (mistakenly) supplies incompatible colour palettes?
  2. Switching the spelling of 'colour' to 'color' in colour_columns_by to color_columns_by to match other function arguments should be documented in inst/NEWS.Rd since it's a (minor) breaking change.
  1. I considered this briefly, I think that having the same annotation name with a different key is a sufficiently bad idea that I don't want to support it. I might do make.names make.unique though*
  2. True

*also unique and intersect both drop names

  1. *True, I forgot these were lists and not vectors. I think same annotation name with same key would be good to support. What I meant by 'what happens if they are incompatible' is whether proposed code results in a warning or error message or just a weird looking plot or ... not that it should be supported

Going to add a warning that says basically "I assume these are both the same"