Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: use named vectors for discrete palettes in tiles #113

Closed
drejom opened this issue Apr 5, 2023 · 10 comments · Fixed by #131
Closed

Feature request: use named vectors for discrete palettes in tiles #113

drejom opened this issue Apr 5, 2023 · 10 comments · Fixed by #131

Comments

@drejom
Copy link

drejom commented Apr 5, 2023

When using a custom palette for example with tiles, annotation_tile() expects a vector of colours, but it would be good if it could accept a named vector, so that colours can be applied to the levels of a factor in a predictable way.

Eg:

tidyHeatmap::pasilla |>
    heatmap(
        .column = sample,
        .row = symbol,
        .value = `count normalised adjusted`,
        scale = "row",
        show_heatmap_legend = FALSE,
    ) |>
    add_tile(type, palette = c("paired-end" = "red", "single-read" = "blue"))

Gives unexpected results:
plot

@stemangiola
Copy link
Owner

Hello @drejom,

it is a good idea. For now, I believe you can control the colour pairing, ordering the levels of the factors type as you desired colour vector.

Please try and let me know. If that works, you could add this example to the README of tidyHeatmap to share this example with the community.

@drejom
Copy link
Author

drejom commented Apr 6, 2023

I'd love to contribute however I can - this (like your others) is a fantastic package, and so useful!

I've tried a few different approaches trying to understand how colours are allocated but was left a bit baffled. Maybe another eg would help: I couldn't work out why when reversing the factor mol.bio, the colours are still allocated to the same levels, and for both tiles, not in the order given from the Spectral palette.

library(RColorBrewer)
library(ALL)
library(tidyverse)
library(tidyHeatmap)
#> tidyHeatmap version 1.10.0

# Use the ALL data from Bioconductor
data(ALL)

# Make a tidy expression table with metadata
exprs(ALL)[sample(12625, 20, FALSE), ] |>
  as_tibble(rownames = "affy_id") |>
  pivot_longer(-affy_id, names_to = "cod", values_to = "exprs") |>
  mutate(cod = sub("^0*", "", cod)) |>
  left_join(pData(ALL), by = join_by(cod)) |>

# Reverse the factor levels for `mol.biol`
  mutate(mol.biol_rev = factor(mol.biol, levels = rev(levels(mol.biol)))) |>

# Plot a heatmap with some tiles
  heatmap(affy_id, cod, exprs) |>
  annotation_tile(mol.biol, palette = brewer.pal(6, "Spectral")) |>
  annotation_tile(mol.biol_rev, palette = brewer.pal(6, "Spectral"))

display.brewer.pal(6, "Spectral")

Created on 2023-04-05 with reprex v2.0.2

Session info
sessioninfo::session_info()
#> ─ Session info ───────────────────────────────────────────────────────────────
#>  setting  value
#>  version  R version 4.2.2 (2022-10-31)
#>  os       macOS Ventura 13.3
#>  system   aarch64, darwin20
#>  ui       X11
#>  language (EN)
#>  collate  en_US.UTF-8
#>  ctype    en_US.UTF-8
#>  tz       America/Los_Angeles
#>  date     2023-04-05
#>  pandoc   2.19.2 @ /Applications/RStudio.app/Contents/Resources/app/quarto/bin/tools/ (via rmarkdown)
#> 
#> ─ Packages ───────────────────────────────────────────────────────────────────
#>  package        * version date (UTC) lib source
#>  ALL            * 1.40.0  2022-11-03 [1] Bioconductor
#>  Biobase        * 2.58.0  2022-11-07 [1] Bioconductor
#>  BiocGenerics   * 0.42.0  2022-04-26 [1] Bioconductor
#>  Cairo            1.6-0   2022-07-05 [1] CRAN (R 4.2.0)
#>  circlize         0.4.15  2022-05-10 [1] CRAN (R 4.2.0)
#>  cli              3.6.1   2023-03-23 [1] CRAN (R 4.2.0)
#>  clue             0.3-64  2023-01-31 [1] CRAN (R 4.2.0)
#>  cluster          2.1.4   2022-08-22 [1] CRAN (R 4.2.2)
#>  codetools        0.2-19  2023-02-01 [1] CRAN (R 4.2.0)
#>  colorspace       2.1-0   2023-01-23 [1] CRAN (R 4.2.0)
#>  ComplexHeatmap   2.12.1  2022-08-09 [1] Bioconductor
#>  crayon           1.5.2   2022-09-29 [1] CRAN (R 4.2.0)
#>  curl             5.0.0   2023-01-12 [1] CRAN (R 4.2.0)
#>  dendextend       1.17.1  2023-03-25 [1] CRAN (R 4.2.2)
#>  digest           0.6.31  2022-12-11 [1] CRAN (R 4.2.0)
#>  doParallel       1.0.17  2022-02-07 [1] CRAN (R 4.2.0)
#>  dplyr          * 1.1.1   2023-03-22 [1] CRAN (R 4.2.0)
#>  evaluate         0.20    2023-01-17 [1] CRAN (R 4.2.0)
#>  fansi            1.0.4   2023-01-22 [1] CRAN (R 4.2.0)
#>  fastmap          1.1.1   2023-02-24 [1] CRAN (R 4.2.0)
#>  forcats        * 1.0.0   2023-01-29 [1] CRAN (R 4.2.0)
#>  foreach          1.5.2   2022-02-02 [1] CRAN (R 4.2.0)
#>  fs               1.6.1   2023-02-06 [1] CRAN (R 4.2.0)
#>  generics         0.1.3   2022-07-05 [1] CRAN (R 4.2.0)
#>  GetoptLong       1.0.5   2020-12-15 [1] CRAN (R 4.2.0)
#>  ggplot2        * 3.4.2   2023-04-03 [1] CRAN (R 4.2.2)
#>  GlobalOptions    0.1.2   2020-06-10 [1] CRAN (R 4.2.0)
#>  glue             1.6.2   2022-02-24 [1] CRAN (R 4.2.0)
#>  gridExtra        2.3     2017-09-09 [1] CRAN (R 4.2.0)
#>  gtable           0.3.3   2023-03-21 [1] CRAN (R 4.2.0)
#>  highr            0.10    2022-12-22 [1] CRAN (R 4.2.0)
#>  hms              1.1.3   2023-03-21 [1] CRAN (R 4.2.0)
#>  htmltools        0.5.5   2023-03-23 [1] CRAN (R 4.2.0)
#>  httr             1.4.5   2023-02-24 [1] CRAN (R 4.2.0)
#>  IRanges          2.32.0  2022-11-07 [1] Bioconductor
#>  iterators        1.0.14  2022-02-05 [1] CRAN (R 4.2.0)
#>  knitr            1.42    2023-01-25 [1] CRAN (R 4.2.0)
#>  lifecycle        1.0.3   2022-10-07 [1] CRAN (R 4.2.0)
#>  lubridate      * 1.9.2   2023-02-10 [1] CRAN (R 4.2.0)
#>  magick           2.7.4   2023-03-09 [1] CRAN (R 4.2.0)
#>  magrittr         2.0.3   2022-03-30 [1] CRAN (R 4.2.0)
#>  matrixStats      0.63.0  2022-11-18 [1] CRAN (R 4.2.0)
#>  mime             0.12    2021-09-28 [1] CRAN (R 4.2.0)
#>  munsell          0.5.0   2018-06-12 [1] CRAN (R 4.2.0)
#>  patchwork        1.1.2   2022-08-19 [1] CRAN (R 4.2.0)
#>  pillar           1.9.0   2023-03-22 [1] CRAN (R 4.2.0)
#>  pkgconfig        2.0.3   2019-09-22 [1] CRAN (R 4.2.0)
#>  png              0.1-8   2022-11-29 [1] CRAN (R 4.2.0)
#>  purrr          * 1.0.1   2023-01-10 [1] CRAN (R 4.2.0)
#>  R.cache          0.16.0  2022-07-21 [1] CRAN (R 4.2.0)
#>  R.methodsS3      1.8.2   2022-06-13 [1] CRAN (R 4.2.0)
#>  R.oo             1.25.0  2022-06-12 [1] CRAN (R 4.2.0)
#>  R.utils          2.12.2  2022-11-11 [1] CRAN (R 4.2.0)
#>  R6               2.5.1   2021-08-19 [1] CRAN (R 4.2.0)
#>  RColorBrewer   * 1.1-3   2022-04-03 [1] CRAN (R 4.2.0)
#>  Rcpp             1.0.10  2023-01-22 [1] CRAN (R 4.2.0)
#>  readr          * 2.1.4   2023-02-10 [1] CRAN (R 4.2.0)
#>  reprex           2.0.2   2022-08-17 [1] CRAN (R 4.2.0)
#>  rjson            0.2.21  2022-01-09 [1] CRAN (R 4.2.0)
#>  rlang            1.1.0   2023-03-14 [1] CRAN (R 4.2.0)
#>  rmarkdown        2.21    2023-03-26 [1] CRAN (R 4.2.2)
#>  rstudioapi       0.14    2022-08-22 [1] CRAN (R 4.2.0)
#>  S4Vectors        0.34.0  2022-04-26 [1] Bioconductor
#>  scales           1.2.1   2022-08-20 [1] CRAN (R 4.2.0)
#>  sessioninfo      1.2.2   2021-12-06 [1] CRAN (R 4.2.0)
#>  shape            1.4.6   2021-05-19 [1] CRAN (R 4.2.0)
#>  stringi          1.7.12  2023-01-11 [1] CRAN (R 4.2.0)
#>  stringr        * 1.5.0   2022-12-02 [1] CRAN (R 4.2.0)
#>  styler           1.9.1   2023-03-04 [1] CRAN (R 4.2.1)
#>  tibble         * 3.2.1   2023-03-20 [1] CRAN (R 4.2.0)
#>  tidyHeatmap    * 1.10.0  2023-04-03 [1] Github (stemangiola/tidyHeatmap@849bf51)
#>  tidyr          * 1.3.0   2023-01-24 [1] CRAN (R 4.2.0)
#>  tidyselect       1.2.0   2022-10-10 [1] CRAN (R 4.2.0)
#>  tidyverse      * 2.0.0   2023-02-22 [1] CRAN (R 4.2.0)
#>  timechange       0.2.0   2023-01-11 [1] CRAN (R 4.2.0)
#>  tzdb             0.3.0   2022-03-28 [1] CRAN (R 4.2.0)
#>  utf8             1.2.3   2023-01-31 [1] CRAN (R 4.2.0)
#>  vctrs            0.6.1   2023-03-22 [1] CRAN (R 4.2.0)
#>  viridis          0.6.2   2021-10-13 [1] CRAN (R 4.2.0)
#>  viridisLite      0.4.1   2022-08-22 [1] CRAN (R 4.2.0)
#>  withr            2.5.0   2022-03-03 [1] CRAN (R 4.2.0)
#>  xfun             0.38    2023-03-24 [1] CRAN (R 4.2.0)
#>  xml2             1.3.3   2021-11-30 [1] CRAN (R 4.2.0)
#>  yaml             2.3.7   2023-01-23 [1] CRAN (R 4.2.0)
#> 
#>  [1] /Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/library
#> 
#> ──────────────────────────────────────────────────────────────────────────────

@stemangiola
Copy link
Owner

stemangiola commented Apr 6, 2023

Thanks for the enthusiasm.

I see; this means that while I keep factors for vertical and horizontal labels (heatmap rows and columns), I do not for annotations.

I should not convert to a character (if possible) and, in doing so, lose user control.

If you have some throughput (it could be a good experience becoming a co-developer), try to see when in the "journey" of the mol.biol column, it stops being a factor and starts to be a character. That point is when the order you impose is lost.

Fixing this would elegantly address your customisation need (and we can, in the future, also consider named character vectors, although that might have bigger implications and edge cases we are not seeing now).

[EDIT]

I see that the order is maintained in the legend. This means that

  1. we just need to impose the same order as the factor levels when naming the colours, or
  2. that using a continuous palette on a categorical variable messed things up (in this case we need a warning)

@drejom
Copy link
Author

drejom commented Apr 7, 2023

OK great! I see the annotation_tiles() function in methods.R:

#' Adds a tile annotation layer to a `InputHeatmap`, that on evaluation creates a `ComplexHeatmap`

Looks like it should be straightforward. I'll have a go and get back to you!

@stemangiola
Copy link
Owner

Great, it is not always straightforward, but once you understand the logic, you will be able to change all sorts of things ;)

Looking forward to receiving your pull request!

@ConYel
Copy link

ConYel commented May 4, 2023

Hello @stemangiola ,
thank you for this amazing package, it is very helpful and straightforward!

I was trying to use factors for discrete palettes as @drejom tried but I didn't get any robust results regarding the mapping of colors to the vector of interest.
on this line:

https://github.com/stemangiola/tidyHeatmap/blob/849bf51f0bd6f10086dcbae86d3cdfbbc20d4d1a/R/methods.R#LL434C4-L434C99

you make the palette a list : list(palette), which neither changes the order nor the names.

then in the function add_annotation

my_input_heatmap@palette_discrete = my_input_heatmap@palette_discrete %>% when(how_many_discrete>0 ~ tail(., -how_many_discrete) , ~ (.))

when(how_many_discrete>0 ~ tail(., -how_many_discrete) , ~ (.))
you drop some colors from a vector?
Is it just one vector of palette_discrete that has all the inserted custom annotations?

@stemangiola
Copy link
Owner

stemangiola commented May 4, 2023

my_input_heatmap@palette_discrete is a list of palettes list(palette1 = c(color2, color2, color3, ..), palette2 = c(.., .., .., ))

every annotation gets a palette, that then is eliminated from the available pool.

Any contribution on this issue would be much appreciated!

@SoManyPepople
Copy link

It's quite odd.
I thought annotation_* functions mapping color palette by treating factor variables as transformed character vectors that sorted by alphabetical order (such as function sort() ).
Hence, you need to manually resort your palette order by the alphabetical order of factor levels.

@stemangiola
Copy link
Owner

If things are as planned, the order should reflect the factor levels, or alphabetical order if the columns in not a factor.

@SoManyPepople
Copy link

If things are as planned, the order should reflect the factor levels, or alphabetical order if the columns in not a factor.

Not actually.
I have two factor variable for annotation, one (factor with eight levels) for row annotation, which is transformed as character vectors and sorted by alphabetical order; another (factor with three levels) for col annotation, which is neither sorted by alphabetical order (decreasing order or increasing order) nor factor order (decreasing order or increasing order), which seems somehow just random. It's quite ood and confusing.

@stemangiola stemangiola linked a pull request Aug 2, 2024 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants