Describing the ExperimentColorMap class
Kevin Rue-Albrecht
MRC WIMM Centre for Computational Biology, University of Oxford, Oxford, OX3 9DS, UKkevinrue67@gmail.com
Federico Marini
Institute of Medical Biostatistics, Epidemiology and Informatics (IMBEI), MainzCenter for Thrombosis and Hemostasis (CTH), Mainzmarinif@uni-mainz.de
Charlotte Soneson
Friedrich Miescher Institute for Biomedical Research, Basel, SwitzerlandSIB Swiss Institute of Bioinformaticscharlottesoneson@gmail.com
Aaron Lun
infinite.monkeys.with.keyboards@gmail.com7 October 2024
Source:vignettes/ecm.Rmd
ecm.Rmd
Compiled date: 2024-10-07
Last edited: 2018-03-08
License: MIT + file LICENSE
Background
iSEE
coordinates the coloration in every plot via the
ExperimentColorMap
class (Rue-Albrecht et al. 2018). Colors for samples
or features are defined from column or row metadata or assay values
using “colormaps”. Each colormap is a function that takes a single
integer argument and returns that number of distinct colors. The
ExperimentColorMap
is a container that stores these
functions for use within the iSEE()
function. Users can
define their own colormaps to customize coloration for specific assays
or covariates.
Defining colormaps
Colormaps for continuous variables
For continuous variables, the function will be asked to generate a
number of colors (21, by default). Interpolation will then be performed
internally to generate a color gradient. Users can use existing color
scales like viridis::viridis
or
heat.colors
:
# Coloring for log-counts:
logcounts_color_fun <- viridis::viridis
It is also possible to use a function that completely ignores any arguments, and simply returns a fixed number of interpolation points:
# Coloring for FPKMs:
fpkm_color_fun <- function(n){
c("black","brown","red","orange","yellow")
}
Colormaps for categorical variables
For categorical variables, the function should accept the number of levels and return a color per level. Colors are automatically assigned to factor levels in the specified order of the levels.
# Coloring for the 'driver' metadata variable.
driver_color_fun <- function(n){
RColorBrewer::brewer.pal(n, "Set2")
}
Alternatively, the function can ignore its arguments and simply
return a named vector of colors if users want to specify the color for
each level explicitly It is the user’s responsibility to ensure that all
levels are accounted for1. For instance, the following colormap
function will only be compatible with factors of two levels, namely
"Y"
and "N"
:
The colormap hierarchy
Specific and shared colormaps
Colormaps can be defined by users at three different levels:
- Each individual assay, column data field, and row data field can be
assigned its own distinct colormap. Those colormaps are stored as named
lists of functions in the
assays
,colData
, androwData
slots, respectively, of theExperimentColorMap
. This can be useful to easily remember which assay is currently shown; to apply different color scale limits to assays that vary on different ranges of values; or display boolean information in an intuitive way, among many other scenarios. -
Shared colormaps can be defined for all assays, all column
data, and all row data. These colormaps are stored in the
all_discrete
andall_continuous
slots of theExperimentColorMap
, as lists of functions namedassays
,colData
, androwData
. -
Global colormaps can be defined for all categorical or
continuous data. Those two colormaps are stored in the
global_discrete
andglobal_continuous
slots of theExperimentColorMap
.
Searching for colors
When queried for a specific colormap of any type (assay, column data, or row data), the following process takes place:
- A specific individual colormap is looked up in the
appropriate slot of the
ExperimentColorMap
. - If it is not found, the shared colormap of the appropriate slot is looked up, according to whether the data are categorical or continuous.
- If it is not found, the global colormap is looked up, according to whether the data are categorical or continuous.
- If none of the above colormaps were defined, the
ExperimentColorMap
will revert to the default colormaps.
By default, viridis
is used as the default continuous
colormap, and hcl
is used as the default categorical
colormap.
Creating the ExperimentColorMap
We store the set of colormap functions in an instance of the
ExperimentColorMap
class. Named functions passed as
assays
, colData
, or rowData
arguments will be used for coloring data in those slots,
respectively.
library(iSEE)
ecm <- ExperimentColorMap(
assays = list(
counts = heat.colors,
logcounts = logcounts_color_fun,
cufflinks_fpkm = fpkm_color_fun
),
colData = list(
passes_qc_checks_s = qc_color_fun,
driver_1_s = driver_color_fun
),
all_continuous = list(
assays = viridis::plasma
)
)
ecm
#> Class: ExperimentColorMap
#> assays(3): counts logcounts cufflinks_fpkm
#> colData(2): passes_qc_checks_s driver_1_s
#> rowData(0):
#> all_discrete(0):
#> all_continuous(1): assays
Users can change the defaults for all assays or column data by modifying the shared colormaps. Similarly, users can modify the defaults for all continuous or categorical data by modifying the global colormaps. This is demonstrated below for the continuous variables:
ExperimentColorMap(
all_continuous=list( # shared
assays=viridis::plasma,
colData=viridis::inferno
),
global_continuous=viridis::magma # global
)
#> Class: ExperimentColorMap
#> assays(0):
#> colData(0):
#> rowData(0):
#> all_discrete(0):
#> all_continuous(2): assays colData
#> global_continuous(1)
Benefits
The ExperimentColorMap
class offers the following major
features:
- A single place to define flexible and lightweight sets of colormaps, that may be saved and reused across sessions and projects outside the app, to apply consistent coloring schemes across entire projects
- A simple interface through accessors
colDataColorMap(colormap, "coldata_name")
and settersassayColorMap(colormap, "assay_name") <- colormap_function
- An elegant fallback mechanism to consistently return a colormap, even for undefined covariates, including a default categorical and continuous colormap, respectively.
- Three levels of colormaps override: individual, shared within slot
(i.e.,
assays
,colData
,rowData
), or shared globally between all categorical or continuous data scales.
Detailed examples on the use of ExperimentColorMap
objects are available in the documentation
?ExperimentColorMap
, as well as below.
Demonstration
Here, we use the allen
single-cell RNA-seq data set to
demonstrate the use of the ExperimentColorMap
class. Using
the sce
object that we created previously,
we create an iSEE
app with the
SingleCellExperiment
object and the colormap generated
above.
app <- iSEE(sce, colormap = ecm)
We run this using runApp
to open the app on our
browser.
shiny::runApp(app)
Now, choose to color cells by Column data
and select
passes_qc_checks_s
. We will see that all cells that passed
QC (Y
) are colored “forestgreen”, while the ones that
didn’t pass are colored firebrick.
If we color any plot by gene expression, we see that use of counts
follows the heat.colors
coloring scheme; use of log-counts
follows the viridis
coloring scheme; and use of FPKMs
follows the black-to-yellow scheme we defined in
fpkm_color_fun
.
Session Info
sessionInfo()
#> R version 4.4.1 (2024-06-14)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 22.04.5 LTS
#>
#> Matrix products: default
#> BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
#> LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.20.so; LAPACK version 3.10.0
#>
#> locale:
#> [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
#> [3] LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
#> [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
#> [7] LC_PAPER=en_US.UTF-8 LC_NAME=C
#> [9] LC_ADDRESS=C LC_TELEPHONE=C
#> [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
#>
#> time zone: UTC
#> tzcode source: system (glibc)
#>
#> attached base packages:
#> [1] stats4 stats graphics grDevices utils datasets methods
#> [8] base
#>
#> other attached packages:
#> [1] iSEE_2.17.4 SingleCellExperiment_1.27.2
#> [3] SummarizedExperiment_1.35.3 Biobase_2.65.1
#> [5] GenomicRanges_1.57.1 GenomeInfoDb_1.41.2
#> [7] IRanges_2.39.2 S4Vectors_0.43.2
#> [9] BiocGenerics_0.51.3 MatrixGenerics_1.17.0
#> [11] matrixStats_1.4.1 BiocStyle_2.33.1
#>
#> loaded via a namespace (and not attached):
#> [1] gridExtra_2.3 rlang_1.1.4 magrittr_2.0.3
#> [4] shinydashboard_0.7.2 clue_0.3-65 GetoptLong_1.0.5
#> [7] compiler_4.4.1 mgcv_1.9-1 png_0.1-8
#> [10] systemfonts_1.1.0 vctrs_0.6.5 pkgconfig_2.0.3
#> [13] shape_1.4.6.1 crayon_1.5.3 fastmap_1.2.0
#> [16] XVector_0.45.0 fontawesome_0.5.2 utf8_1.2.4
#> [19] promises_1.3.0 rmarkdown_2.28 shinyAce_0.4.2
#> [22] UCSC.utils_1.1.0 ragg_1.3.3 xfun_0.48
#> [25] zlibbioc_1.51.1 cachem_1.1.0 jsonlite_1.8.9
#> [28] listviewer_4.0.0 highr_0.11 later_1.3.2
#> [31] DelayedArray_0.31.14 parallel_4.4.1 cluster_2.1.6
#> [34] R6_2.5.1 bslib_0.8.0 RColorBrewer_1.1-3
#> [37] jquerylib_0.1.4 Rcpp_1.0.13 bookdown_0.40
#> [40] iterators_1.0.14 knitr_1.48 httpuv_1.6.15
#> [43] Matrix_1.7-0 splines_4.4.1 igraph_2.0.3
#> [46] tidyselect_1.2.1 abind_1.4-8 yaml_2.3.10
#> [49] viridis_0.6.5 doParallel_1.0.17 codetools_0.2-20
#> [52] miniUI_0.1.1.1 lattice_0.22-6 tibble_3.2.1
#> [55] shiny_1.9.1 evaluate_1.0.0 desc_1.4.3
#> [58] circlize_0.4.16 pillar_1.9.0 BiocManager_1.30.25
#> [61] DT_0.33 foreach_1.5.2 shinyjs_2.1.0
#> [64] generics_0.1.3 ggplot2_3.5.1 munsell_0.5.1
#> [67] scales_1.3.0 xtable_1.8-4 glue_1.8.0
#> [70] tools_4.4.1 colourpicker_1.3.0 fs_1.6.4
#> [73] grid_4.4.1 colorspace_2.1-1 nlme_3.1-166
#> [76] GenomeInfoDbData_1.2.13 vipor_0.4.7 cli_3.6.3
#> [79] textshaping_0.4.0 fansi_1.0.6 S4Arrays_1.5.10
#> [82] viridisLite_0.4.2 ComplexHeatmap_2.21.1 dplyr_1.1.4
#> [85] gtable_0.3.5 rintrojs_0.3.4 sass_0.4.9
#> [88] digest_0.6.37 SparseArray_1.5.43 ggrepel_0.9.6
#> [91] rjson_0.2.23 htmlwidgets_1.6.4 memoise_2.0.1
#> [94] htmltools_0.5.8.1 pkgdown_2.1.1 lifecycle_1.0.4
#> [97] shinyWidgets_0.8.7 httr_1.4.7 GlobalOptions_0.1.2
#> [100] mime_0.12
# devtools::session_info()