Skip to contents

# Data Visualization

Source: `vignettes/Data_Visualization.Rmd`
`Data_Visualization.Rmd`

Date: 24.06.2024

    library(cyCONDOR)

`cyCONDOR` provides several functions to visualize the results of `cyCONDOR`´s dimensionality reduction and clustering workflows.

## Load an example dataset

In this vignette, we will use a flow cytometry dataset of six PBMC samples taken from three patients and three control. The data was transformed and subjected to several dimensionality reduction methods as well as clustering and metaclustering using `cyCONDOR`(see vignettes: `Data loading and transformation`, `Dimensionality Reduction`, `Clustering and cell annotation`).

    condor <- readRDS("../.test_files/conodr_example_016.rds")

    #Let's checkout the content of the object
    str(condor[!names(condor) %in% "extras"])

    ## List of 6
    ##  $ expr      :List of 1
    ##   ..$ orig:'data.frame': 59049 obs. of  28 variables:
    ##   .. ..$ FSC-A        : num [1:59049] 4.38 4.22 4.27 4.18 4.08 ...
    ##   .. ..$ SSC-A        : num [1:59049] 3.91 3.24 3.42 3.62 3.7 ...
    ##   .. ..$ CD38         : num [1:59049] 3.61 3.12 3.71 2.9 2.06 ...
    ##   .. ..$ CD8          : num [1:59049] 0.869 2.118 3.802 2.748 3.868 ...
    ##   .. ..$ CD195 (CCR5) : num [1:59049] 2.281 1.199 0.816 1.5 3.303 ...
    ##   .. ..$ CD94 (KLRD1) : num [1:59049] 2.32 2.24 1.78 2.57 2.18 ...
    ##   .. ..$ CD45RA       : num [1:59049] 3.33 3.63 2.49 3.93 4.14 ...
    ##   .. ..$ HLA-DR       : num [1:59049] 3.173 1.595 3.066 0.973 0.62 ...
    ##   .. ..$ CD56         : num [1:59049] 1.43 2.25 1.72 3.28 1.48 ...
    ##   .. ..$ CD127 (IL7RA): num [1:59049] 1.03 3.16 1.17 1.58 3.1 ...
    ##   .. ..$ CD14         : num [1:59049] 3.96 2.14 1.47 1.21 1.92 ...
    ##   .. ..$ CD64         : num [1:59049] 2.475 0.462 0.85 1.075 0.981 ...
    ##   .. ..$ CD4          : num [1:59049] 2.658 3.886 0.209 1.135 0.499 ...
    ##   .. ..$ IgD          : num [1:59049] 0.932 0.438 1.488 0.694 1.486 ...
    ##   .. ..$ CD19         : num [1:59049] 1.822 1.583 0.813 1.703 0.357 ...
    ##   .. ..$ CD16         : num [1:59049] 1.658 0.863 0.838 2.828 1.325 ...
    ##   .. ..$ CD32         : num [1:59049] 2.476 0.743 1.056 0.887 0.756 ...
    ##   .. ..$ CD197 (CCR7) : num [1:59049] 1.4012 2.6245 0.0844 0.9996 1.2096 ...
    ##   .. ..$ CD20         : num [1:59049] 0.724 1.289 1.672 1.371 1.623 ...
    ##   .. ..$ CD27         : num [1:59049] 1.737 3.89 3.564 0.638 0.622 ...
    ##   .. ..$ CD15         : num [1:59049] 0.844 0.549 0.632 1.258 2.04 ...
    ##   .. ..$ PD-1         : num [1:59049] 0.0514 0.9102 0.9839 0.4781 1.7587 ...
    ##   .. ..$ CD3          : num [1:59049] 0.964 4.006 3.746 1.788 3.875 ...
    ##   .. ..$ CD57         : num [1:59049] 1.277 0.531 1.006 3.039 3.004 ...
    ##   .. ..$ CD25         : num [1:59049] 1.709 2.032 1.833 1.187 0.937 ...
    ##   .. ..$ CD123 (IL3RA): num [1:59049] 2.32 1.14 1.13 1.11 1.28 ...
    ##   .. ..$ CD13         : num [1:59049] 2.388 0.817 0.703 0.861 0.707 ...
    ##   .. ..$ CD11c        : num [1:59049] 3.792 0.645 2.025 0.668 1.946 ...
    ##  $ anno      :List of 1
    ##   ..$ cell_anno:'data.frame':    59049 obs. of  3 variables:
    ##   .. ..$ expfcs_filename: Factor w/ 6 levels "ID10.fcs","ID3.fcs",..: 1 1 1 1 1 1 1 1 1 1 ...
    ##   .. ..$ sample_ID      : chr [1:59049] "ID10" "ID10" "ID10" "ID10" ...
    ##   .. ..$ group          : chr [1:59049] "pat" "pat" "pat" "pat" ...
    ##  $ pca       :List of 1
    ##   ..$ orig: num [1:59049, 1:28] -4.593 2.011 0.741 0.601 1.685 ...
    ##   .. ..- attr(*, "dimnames")=List of 2
    ##   .. .. ..$ : chr [1:59049] "ID10.fcs_1" "ID10.fcs_2" "ID10.fcs_3" "ID10.fcs_4" ...
    ##   .. .. ..$ : chr [1:28] "PC1" "PC2" "PC3" "PC4" ...
    ##  $ umap      :List of 1
    ##   ..$ pca_orig: num [1:59049, 1:2] -9.19 1.6 5.45 3.97 2.5 ...
    ##   .. ..- attr(*, "scaled:center")= num [1:2] -0.126 -0.253
    ##   .. ..- attr(*, "dimnames")=List of 2
    ##   .. .. ..$ : chr [1:59049] "ID10.fcs_1" "ID10.fcs_2" "ID10.fcs_3" "ID10.fcs_4" ...
    ##   .. .. ..$ : chr [1:2] "UMAP1" "UMAP2"
    ##  $ tSNE      :List of 1
    ##   ..$ pca_orig: num [1:59049, 1:2] 18.26 -11.83 -24.09 5.71 -10.98 ...
    ##   .. ..- attr(*, "dimnames")=List of 2
    ##   .. .. ..$ : chr [1:59049] "ID10.fcs_1" "ID10.fcs_2" "ID10.fcs_3" "ID10.fcs_4" ...
    ##   .. .. ..$ : chr [1:2] "tSNE1" "tSNE2"
    ##  $ clustering:List of 2
    ##   ..$ phenograph_pca_orig_k_60:'data.frame': 59049 obs. of  3 variables:
    ##   .. ..$ Phenograph  : Factor w/ 25 levels "1","2","3","4",..: 1 2 3 4 5 5 6 1 1 5 ...
    ##   .. ..$ Description : chr [1:59049] "pca_orig_k60" "pca_orig_k60" "pca_orig_k60" "pca_orig_k60" ...
    ##   .. ..$ metaclusters: Factor w/ 16 levels "Classical Monocytes",..: 1 2 3 4 5 5 1 1 1 5 ...
    ##   ..$ FlowSOM_pca_orig_k_15   :'data.frame': 59049 obs. of  2 variables:
    ##   .. ..$ FlowSOM    : Factor w/ 15 levels "1","2","3","4",..: 12 11 4 2 3 3 12 12 12 3 ...
    ##   .. ..$ Description: chr [1:59049] "pca_orig_k15" "pca_orig_k15" "pca_orig_k15" "pca_orig_k15" ...

## Visualize the results of dimensionality reduction and clustering

`cyCONDOR` comes with several methods to perform dimensionality reduction. Two dimensional representations of each reduction method can be visualized using the `plot_dim_red()` function.

The function requires the user to specify a condor object, the reduction method (e.g. pca, umap or tSNE) and the name of the actual reduction_slot, e.g. “orig”. Further, a variable needs to be provided to the parameter `param`, which is used to color the dots.

### PCA

Let’s plot the first two Principle components of the PCA and color by the meta variable “group”.

    plot_dim_red(fcd = condor,
                 expr_slot = NULL,
                 reduction_method = "pca",
                 reduction_slot = "orig",
                 cluster_slot = NULL,
                 param = "group",
                 title = "PCA")

### tSNE

Changing `reduction_method = "tSNE"` and `reduction_slot = "pca_orig"`, results in a plot of the tSNE.

    plot_dim_red(fcd = condor,
                 expr_slot = NULL,
                 reduction_method = "tSNE",
                 reduction_slot = "pca_orig",
                 cluster_slot = NULL,
                 param = "group",
                 title = "tSNE")

### UMAP

Similiarly, `reduction_method = "umap"` and `reduction_slot = "pca_orig"`, gives us a the UMAP representation that was calculated on the PCA on the transformed expression data.

    plot_dim_red(fcd = condor,
                 expr_slot = NULL,
                 reduction_method = "umap",
                 reduction_slot = "pca_orig",
                 cluster_slot = NULL,
                 param = "group",
                 title = "UMAP")

### Colored by Phenograph, FlowSOM clustering or metaclusters

Instead of meta variables available in the `cell_anno` slot, it is also possible to overlay cell population identities, determined by `cyCONDOR's` clustering or cell label implementations. In this case, the function additionally requires the specification of a `cluster_slot` as input, to define were `param` should be taken from.

In the following example, we will visualize the cluster identities (`param = "Phenograph"`) and the related metaclustering annotation (`param = "metaclusters"`) in the `cluster_slot` “phenograph_pca_orig_k_60”.

    p1<-plot_dim_red(fcd = condor,
                     expr_slot = NULL,
                     reduction_method = "umap",
                     reduction_slot = "pca_orig",
                     cluster_slot = "phenograph_pca_orig_k_60",
                     param = "Phenograph",
                     title = "UMAP colored by Phenograph clusters")

    p2<-plot_dim_red(fcd = condor,
                     expr_slot = NULL,
                     reduction_method = "umap",
                     reduction_slot = "pca_orig",
                     cluster_slot = "phenograph_pca_orig_k_60",
                     param = "metaclusters",
                     title = "UMAP colored by metaclusters")

    cowplot::plot_grid(plotlist = list(p1,p2),align = "v")

In the same manner, FlowSOM results can be plotted on the dimensionality reduction.

    plot_dim_red(fcd = condor,
                 expr_slot = NULL,
                 reduction_method = "umap",
                 reduction_slot = "pca_orig",
                 cluster_slot = "FlowSOM_pca_orig_k_15",
                 param = "FlowSOM",
                 title = "UMAP colored by FlowSOM clusters")

### Split plot by a variable

Sometimes it comes in handy to split the dimensionality reduction by a variable, e.g. group, sample ID or experimental batches. In the `plot_dim_red()` function this can be achieved via the `facet_by_variable` parameter.

Setting `facet_by_variable = T`, will split the plot by the variable provided in `param`.

    plot_dim_red(fcd = condor,
                 expr_slot = NULL,
                 reduction_method = "umap",
                 reduction_slot = "pca_orig",
                 cluster_slot = NULL,
                 param = "group",
                 facet_by_variable = T,
                 title = "UMAP")

Providing `facet_by_variable` with a different variable than specified in `param`, will keep the coloring by the variable in `param`, but splits the plot by the faceting variable. Note, that in case clustering variables are used, a `cluster_slot` needs to be provided as well.

    plot_dim_red(fcd = condor,
                 expr_slot = NULL,
                 reduction_method = "umap",
                 reduction_slot = "pca_orig",
                 cluster_slot = "phenograph_pca_orig_k_60",
                 param = "metaclusters",
                 facet_by_variable = "group",
                 title = "UMAP colored by metaclusters")

### Export the plot as raster image

Visualizing hundred thousands of events can be demanding. Using `raster = T`, the function will generate a raster image, instead of plotting each event individually.

    plot_dim_red(fcd = condor,
                 expr_slot = NULL,
                 reduction_method = "umap",
                 reduction_slot = "pca_orig",
                 cluster_slot = "FlowSOM_pca_orig_k_15",
                 param = "FlowSOM",
                 raster = T,
                 title = "UMAP colored by FlowSOM clusters")

## Visualization of marker expression

In the next section, we will go through some examples of how marker expression can be visualized with `cyCONDOR`. Since this is most interesting, when the data are already clustered, almost all functions require cluster or cell label information obtained via `cyCONDOR's` clustering or cell label prediction workflows. Only the function, `plot_dim_red()`, can be used without any cell population labels.

### Marker expression overlayed on dimensionality reduction

To overlay marker expression values on the dimensionality reduction, we can use the `plot_dim_red()` function introduced in the section before. Instead of a `clustering_slot`, the `expression_slot` in which the expression values are stored needs to be specified and the marker to be visualized is given to the parameter `param`.

In large data sets, the dimensionality reduction can be “crowded” and it might be useful to order the cells by their expression. Setting `order = T`, will plot the cells with the highest expression at the top.

    p1<-plot_dim_red(fcd = condor,
                     expr_slot = "orig",
                     reduction_method = "umap",
                     reduction_slot = "pca_orig",
                     cluster_slot = NULL,
                     param = "CD3",
                     order = F, #default
                     title = "CD3 expression - random order")

    p2<-plot_dim_red(fcd = condor,
                     expr_slot = "orig",
                     reduction_method = "umap",
                     reduction_slot = "pca_orig",
                     cluster_slot = NULL,
                     param = "CD3",
                     order = T,
                     title = "CD3 expression - ordered")

    cowplot::plot_grid(plotlist = list(p1,p2),align = "v")

As above a `facet_by_variable` can be used to split the plot by another variable.

    plot_dim_red(fcd = condor,
                 expr_slot = "orig",
                 reduction_method = "umap",
                 reduction_slot = "pca_orig",
                 cluster_slot = NULL,
                 param = "CD3",
                 facet_by_variable = "group",
                 title = "CD3 expression split by group")

### Heatmap of marker expression

Heatmap visualizations are useful to get a fast overview across many markers and cell populations. The `plot_marker_HM()` function calculates the mean transformed expression for each cell population and marker combination. The means are centered and scaled for each marker and subsequently visualized as heatmap.

However, it should be mention that this comes with certain draw backs: 1) the distribution of the expression is not considered when looking at the mean and 2) the actual expression level is somewhat obscured by the row-wise scaling.

    plot_marker_HM(fcd = condor,
                   expr_slot = "orig",
                   marker_to_exclude = c("FSC-A","SSC-A"),
                   cluster_slot = "phenograph_pca_orig_k_60",
                   cluster_var = "metaclusters")

By setting `cluster_rows = T` and `cluster_cols`, rows and columns get clustered.

    plot_marker_HM(fcd = condor,
                   expr_slot = "orig",
                   marker_to_exclude = c("FSC-A","SSC-A"),
                   cluster_slot = "phenograph_pca_orig_k_60",
                   cluster_var = "metaclusters",
                   cluster_rows = T,
                   cluster_cols = T)

The function `plot_marker_group_HM` works very similarly with the addition that a meta variable available in `cell_anno` is provided and used to further split the columns by the levels of that meta variable. In the following example, we are interested whether mean expression of phenotaping markers like CD3 or CD19 is stable across the different samples by using `group_var = sample_ID`.

    plot_marker_group_HM(fcd = condor,
                         expr_slot = "orig",
                         marker_to_exclude = c("FSC-A","SSC-A"),
                         cluster_slot = "phenograph_pca_orig_k_60",
                         cluster_var = "metaclusters",
                         group_var = "sample_ID")

### Plot mean expression as boxplots

Instead of as a heatmap, the mean (or median) expression can be visualized as boxplots with each sample being represented by a dot. For this, the `plot_marker_boxplot` requires the user to specify a variable containing sample IDs in `sample_var` and a grouping variable in `group_var`. Each sample ID should be uniquely associated with one level in `group_var`. The grouping variable could for example be the disease status or the batch variable. Since the data has no batch and we are not yet interested in differences in our biological groups (see `vignette("Differential Analysis")`, we are using the variable “experiment_name” in the following chunk to get an overview about the expression in our samples.

    condor$anno$cell_anno$experiment_name <-"test_data"

    plot_marker_boxplot(fcd = condor,
                        expr_slot = "orig",
                        cluster_slot = "phenograph_pca_orig_k_60",
                        cluster_var = "metaclusters",
                        group_var = "experiment_name",
                        sample_var = "sample_ID",
                        marker = c("CD3","CD4","CD8","CD14","CD19","HLA-DR"),
                        fun = "mean",
                        facet_ncol = 3,
                        dot_size = 1)

By default the function will generate boxplots for all marker and cell population combinations, which depending on the panel size can be too much to inspect at once. With the parameters `marker` the user can select the markers of interest, while `cluster_to_show` allows to subset to certain cell populations present in the given `cluster_var`. Further, it is possible to calculate the median expression instead of mean by using `fun = "median"`.

### Distribution of expression

Besides visualizing aggregated expression, `cyCONDOR` also provides different visualization options to investigate the distribution of marker expression across all cells in a population.

`plot_marker_ridgeplot()` and `plot_marker_violinplot()`, both visualize the density distribution of a marker for each cell population in `cluster_var` and therefor provide insights whether a marker is homogeneously expressed in a certain cluster (or cell population) or whether only a part of the cells is expressing the marker highly or lowly. These plots can be very useful, when inspecting and annotating clusters, since they e.g. enable the detection of smaller subsets or contamination in a cluster of cells, which is not visible in a heatmap.

`plot_marker_density()` and (optionally) `plot_marker_violinplot()` further split the distributions by meta variables present in the `cell_anno` slot, which can help to investigate technical and/or bioligical influencing factors.

#### Ridgeline plot

`plot_marker_ridgeplot()` visualizes a density distribution of the expression for each cell population in `cluster_var` for a marker specified in `marker`.

    plot_marker_ridgeplot(fcd = condor,
                          expr_slot = "orig",
                          cluster_slot = "phenograph_pca_orig_k_60",
                          cluster_var = "metaclusters",
                          marker = "CD3")

    ## Warning: `expand_scale()` was deprecated in ggplot2 3.3.0.
    ## ℹ Please use `expansion()` instead.
    ## ℹ The deprecated feature was likely used in the cyCONDOR package.
    ##   Please report the issue to the authors.
    ## This warning is displayed once every 8 hours.
    ## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
    ## generated.

    ## Picking joint bandwidth of 0.0733

In case more than one marker are specified, the function returns a list of plots - one plot for each marker.

    plot.list<- plot_marker_ridgeplot(fcd = condor,
                          expr_slot = "orig",
                          cluster_slot = "phenograph_pca_orig_k_60",
                          cluster_var = "metaclusters",
                          marker = c("CD3","CD4"))

    cowplot::plot_grid(plotlist = plot.list,align = "v")

    ## Picking joint bandwidth of 0.0733

    ## Picking joint bandwidth of 0.0737

#### Violin plot

The `plot_marker_violinplot` requires the same input as `plot_marker_ridgeplot`. But the density distribution of marker expression is visualized as violins for each cell population and the populations are shown next to each other instead of being vertically stacked.

    plot_marker_violinplot(fcd = condor,
                           expr_slot = "orig",
                           cluster_slot = "phenograph_pca_orig_k_60",
                           cluster_var = "metaclusters",
                           marker = "CD56")

Again, provided with several marker names, the function returns a list of plots.

    plot.list<-plot_marker_violinplot(fcd = condor,
                                      expr_slot = "orig",
                                      cluster_slot = "phenograph_pca_orig_k_60",
                                      cluster_var = "metaclusters",
                                      marker = c("CD3","CD56","HLA-DR","CD19"))

    cowplot::plot_grid(plotlist = plot.list,align = "hv")

As a site note, `plot_marker_violinplot()` optionally can be given a grouping variable `group_var` which is used to split each violin plot by. This can be useful when looking at biological groups or batch variables.

#### Density plot

The `plot_marker_density()` can be used to compare expression distributions between different levels in a given `group_var`. This can for example be applied to investigate homogeneity of staining and measuring procedure between samples or experimental days.

    plot_marker_density(fcd = condor,
                        expr_slot = "orig",
                        cluster_slot = "phenograph_pca_orig_k_60",
                        cluster_var = "metaclusters",
                        group_var = "sample_ID",
                        marker = "CD57")

### Classical cytometry dotplot

Finally, using `plot_marker_dotplot()` a scatter plot of two markers can be generated to investigate the relation of their expression. The marker on the x-axis is specified in `marker_x`, while the marker on the y-axis is specified in `marker_y`.

    plot_marker_dotplot(fcd = condor,
                        expr_slot = "orig",
                        marker_x = "CD3",
                        marker_y = "CD19",
                        cluster_slot = "phenograph_pca_orig_k_60",
                        cluster_var = "metaclusters",
                        dot_size = 0.5)

## Inspection of cell counts

As always, it is important to consider how many cells are actually underlying visualizations that conceal the actual cells behind aggregated expression values (mean/median) or density distributions. `cyCONDOR` provides functions to quickly assess cell counts.

You can either look at the cell counts per sample and cell population in table format with the `getTable()` function setting `output_type = "counts"`, or visualize cell numbers with the `plot_counts_barplot()` function.

    # get counts as data frame
    counts<-getTable(fcd = condor,
                     output_type = "counts",
                     cluster_slot = "phenograph_pca_orig_k_60",
                     cluster_var = "metaclusters",
                     group_var = "sample_ID",
                     numeric = F)
    counts

    ##      group_var B cells Basophils CD16+ Monocytes CD4 CD127- CD4 CD25+
    ## ID10      ID10     111        13             342        365       101
    ## ID3        ID3     354        80             350        500       324
    ## ID5        ID5     493        35             219        485       202
    ## ID6        ID6     192        24             494        263       312
    ## ID7        ID7     171        59             143        875       126
    ## ID8        ID8      86        25             255        533       114
    ##      CD4 CD45RA- CD127+ CD4 CD45RA+ CD127+ CD8 CD45RA- CD127+
    ## ID10                564                569                461
    ## ID3                1837                993                472
    ## ID5                1614                933                727
    ## ID6                 535                191                500
    ## ID7                1572               1475                974
    ## ID8                 613               1498                333
    ##      CD8 CD45RA+ CD127- CD8 CD45RA+ CD127+ Classical Monocytes Mixed NK bright
    ## ID10               2123                682                3184     7       317
    ## ID3                 142               1165                2338    48       464
    ## ID5                 623                920                2372   248       512
    ## ID6                1085                894                2102    90       667
    ## ID7                  68                308                2151    10       515
    ## ID8                1829                697                3008    31       247
    ##      NK dim pDCs Unconventional T cells
    ## ID10    641   24                    496
    ## ID3     825   80                     28
    ## ID5     517   66                     34
    ## ID6    1242   30                    428
    ## ID7    1490   55                      8
    ## ID8      79   54                    598

    # get cells per cluster_var
    colSums(counts[,c(-1)])

    ##                B cells              Basophils        CD16+ Monocytes
    ##                   1407                    236                   1803
    ##             CD4 CD127-              CD4 CD25+     CD4 CD45RA- CD127+
    ##                   3021                   1179                   6735
    ##     CD4 CD45RA+ CD127+     CD8 CD45RA- CD127+     CD8 CD45RA+ CD127-
    ##                   5659                   3467                   5870
    ##     CD8 CD45RA+ CD127+    Classical Monocytes                  Mixed
    ##                   4666                  15155                    434
    ##              NK bright                 NK dim                   pDCs
    ##                   2722                   4794                    309
    ## Unconventional T cells
    ##                   1592

The `plot_counts_barplot()` function stacks absolute cell numbers of each cell population on top of each other for each group in the grouping variable, which can be set via the `group_var` parameter.

    # visualize counts as stacked bar plot, faceted by clustering
    plot_counts_barplot(fcd = condor,
                        cluster_slot = "phenograph_pca_orig_k_60",
                        cluster_var = "metaclusters",
                        group_var = "sample_ID",
                        facet_by_clustering = F,
                        facet_ncol = 5
    )

A faceting of the plot by cell population can be achieved by setting the parameter `facet_by_group = T`.

    # visualize counts as stacked bar plot, faceted by clustering
    plot_counts_barplot(fcd = condor,
                        cluster_slot = "phenograph_pca_orig_k_60",
                        cluster_var = "metaclusters",
                        group_var = "sample_ID",
                        facet_by_clustering = T,
                        facet_ncol = 5
    )

## Others

### Visualize the loadings of PCs

`PC_loadings()` can be used to visualize the loadings for each principle component.

    PC_loadings(fcd = condor, data_slot = "orig")

### Density plot

    plot_dim_density(fcd = condor,
                     reduction_method = "umap",
                     reduction_slot = "pca_orig",
                     group_var = "group",
                     color_density = c("Greys", "Reds"))

## MORE visualization?

In this vignette, we mostly focused on visualizations that are useful to investigate clusterings and support annotation of cell populations. However, biological questions often revolve around comparing different biological groups of samples. To get some inspirations how those can be visualized, check out the `vignette("Differential Analysis")`!

## Session Info

    info <- sessionInfo()
    info

    ## R version 4.4.2 (2024-10-31)
    ## Platform: x86_64-pc-linux-gnu
    ## Running under: Ubuntu 24.04.1 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.26.so;  LAPACK version 3.12.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: Etc/UTC
    ## tzcode source: system (glibc)
    ##
    ## attached base packages:
    ## [1] stats     graphics  grDevices utils     datasets  methods   base
    ##
    ## other attached packages:
    ## [1] cyCONDOR_0.3.1
    ##
    ## loaded via a namespace (and not attached):
    ##   [1] IRanges_2.40.1              Rmisc_1.5.1
    ##   [3] urlchecker_1.0.1            nnet_7.3-20
    ##   [5] CytoNorm_2.0.1              TH.data_1.1-3
    ##   [7] vctrs_0.6.5                 digest_0.6.37
    ##   [9] png_0.1-8                   shape_1.4.6.1
    ##  [11] proxy_0.4-27                slingshot_2.14.0
    ##  [13] ggrepel_0.9.6               corrplot_0.95
    ##  [15] parallelly_1.45.0           MASS_7.3-65
    ##  [17] pkgdown_2.1.3               reshape2_1.4.4
    ##  [19] httpuv_1.6.16               foreach_1.5.2
    ##  [21] BiocGenerics_0.52.0         withr_3.0.2
    ##  [23] ggrastr_1.0.2               xfun_0.52
    ##  [25] ggpubr_0.6.1                ellipsis_0.3.2
    ##  [27] survival_3.8-3              memoise_2.0.1
    ##  [29] hexbin_1.28.5               ggbeeswarm_0.7.2
    ##  [31] RProtoBufLib_2.18.0         princurve_2.1.6
    ##  [33] profvis_0.4.0               ggsci_3.2.0
    ##  [35] systemfonts_1.2.3           ragg_1.4.0
    ##  [37] zoo_1.8-14                  GlobalOptions_0.1.2
    ##  [39] DEoptimR_1.1-3-1            Formula_1.2-5
    ##  [41] promises_1.3.3              scatterplot3d_0.3-44
    ##  [43] httr_1.4.7                  rstatix_0.7.2
    ##  [45] globals_0.18.0              rstudioapi_0.17.1
    ##  [47] UCSC.utils_1.2.0            miniUI_0.1.2
    ##  [49] generics_0.1.4              ggcyto_1.34.0
    ##  [51] base64enc_0.1-3             curl_6.4.0
    ##  [53] S4Vectors_0.44.0            zlibbioc_1.52.0
    ##  [55] flowWorkspace_4.18.1        polyclip_1.10-7
    ##  [57] randomForest_4.7-1.2        GenomeInfoDbData_1.2.13
    ##  [59] SparseArray_1.6.2           RBGL_1.82.0
    ##  [61] ncdfFlow_2.52.1             RcppEigen_0.3.4.0.2
    ##  [63] xtable_1.8-4                stringr_1.5.1
    ##  [65] desc_1.4.3                  doParallel_1.0.17
    ##  [67] evaluate_1.0.4              S4Arrays_1.6.0
    ##  [69] hms_1.1.3                   glmnet_4.1-9
    ##  [71] GenomicRanges_1.58.0        irlba_2.3.5.1
    ##  [73] colorspace_2.1-1            isoband_0.2.7
    ##  [75] harmony_1.2.3               reticulate_1.42.0
    ##  [77] readxl_1.4.5                magrittr_2.0.3
    ##  [79] lmtest_0.9-40               readr_2.1.5
    ##  [81] Rgraphviz_2.50.0            later_1.4.2
    ##  [83] lattice_0.22-7              future.apply_1.20.0
    ##  [85] robustbase_0.99-4-1         XML_3.99-0.18
    ##  [87] cowplot_1.2.0               matrixStats_1.5.0
    ##  [89] xts_0.14.1                  class_7.3-23
    ##  [91] Hmisc_5.2-3                 pillar_1.11.0
    ##  [93] nlme_3.1-168                iterators_1.0.14
    ##  [95] compiler_4.4.2              RSpectra_0.16-2
    ##  [97] stringi_1.8.7               gower_1.0.2
    ##  [99] minqa_1.2.8                 SummarizedExperiment_1.36.0
    ## [101] lubridate_1.9.4             devtools_2.4.5
    ## [103] CytoML_2.18.3               plyr_1.8.9
    ## [105] crayon_1.5.3                abind_1.4-8
    ## [107] locfit_1.5-9.12             sp_2.2-0
    ## [109] sandwich_3.1-1              pcaMethods_1.98.0
    ## [111] dplyr_1.1.4                 codetools_0.2-20
    ## [113] multcomp_1.4-28             textshaping_1.0.1
    ## [115] recipes_1.3.1               openssl_2.3.3
    ## [117] Rphenograph_0.99.1          TTR_0.24.4
    ## [119] bslib_0.9.0                 e1071_1.7-16
    ## [121] destiny_3.20.0              GetoptLong_1.0.5
    ## [123] ggplot.multistats_1.0.1     mime_0.13
    ## [125] splines_4.4.2               circlize_0.4.16
    ## [127] Rcpp_1.1.0                  sparseMatrixStats_1.18.0
    ## [129] cellranger_1.1.0            knitr_1.50
    ## [131] clue_0.3-66                 lme4_1.1-37
    ## [133] fs_1.6.6                    listenv_0.9.1
    ## [135] checkmate_2.3.2             DelayedMatrixStats_1.28.1
    ## [137] Rdpack_2.6.4                pkgbuild_1.4.8
    ## [139] ggsignif_0.6.4              tibble_3.3.0
    ## [141] Matrix_1.7-3                rpart.plot_3.1.2
    ## [143] statmod_1.5.0               tzdb_0.5.0
    ## [145] tweenr_2.0.3                pkgconfig_2.0.3
    ## [147] pheatmap_1.0.13             tools_4.4.2
    ## [149] cachem_1.1.0                rbibutils_2.3
    ## [151] smoother_1.3                fastmap_1.2.0
    ## [153] rmarkdown_2.29              scales_1.4.0
    ## [155] grid_4.4.2                  usethis_3.1.0
    ## [157] broom_1.0.8                 sass_0.4.10
    ## [159] graph_1.84.1                carData_3.0-5
    ## [161] RANN_2.6.2                  rpart_4.1.24
    ## [163] farver_2.1.2                reformulas_0.4.1
    ## [165] yaml_2.3.10                 MatrixGenerics_1.18.1
    ## [167] foreign_0.8-90              ggthemes_5.1.0
    ## [169] cli_3.6.5                   purrr_1.1.0
    ## [171] stats4_4.4.2                lifecycle_1.0.4
    ## [173] uwot_0.2.3                  askpass_1.2.1
    ## [175] caret_7.0-1                 Biobase_2.66.0
    ## [177] mvtnorm_1.3-3               lava_1.8.1
    ## [179] sessioninfo_1.2.3           backports_1.5.0
    ## [181] cytolib_2.18.2              timechange_0.3.0
    ## [183] gtable_0.3.6                rjson_0.2.23
    ## [185] umap_0.2.10.0               ggridges_0.5.6
    ## [187] parallel_4.4.2              pROC_1.18.5
    ## [189] limma_3.62.2                jsonlite_2.0.0
    ## [191] edgeR_4.4.2                 RcppHNSW_0.6.0
    ## [193] ggplot2_3.5.2               Rtsne_0.17
    ## [195] FlowSOM_2.14.0              ranger_0.17.0
    ## [197] flowCore_2.18.0             jquerylib_0.1.4
    ## [199] timeDate_4041.110           shiny_1.11.1
    ## [201] ConsensusClusterPlus_1.70.0 htmltools_0.5.8.1
    ## [203] diffcyt_1.26.1              glue_1.8.0
    ## [205] XVector_0.46.0              VIM_6.2.2
    ## [207] gridExtra_2.3               boot_1.3-31
    ## [209] TrajectoryUtils_1.14.0      igraph_2.1.4
    ## [211] R6_2.6.1                    tidyr_1.3.1
    ## [213] SingleCellExperiment_1.28.1 labeling_0.4.3
    ## [215] vcd_1.4-13                  cluster_2.1.8.1
    ## [217] pkgload_1.4.0               GenomeInfoDb_1.42.3
    ## [219] ipred_0.9-15                nloptr_2.2.1
    ## [221] DelayedArray_0.32.0         tidyselect_1.2.1
    ## [223] vipor_0.4.7                 htmlTable_2.4.3
    ## [225] ggforce_0.5.0               CytoDx_1.26.0
    ## [227] car_3.1-3                   future_1.58.0
    ## [229] ModelMetrics_1.2.2.2        laeken_0.5.3
    ## [231] data.table_1.17.8           htmlwidgets_1.6.4
    ## [233] ComplexHeatmap_2.22.0       RColorBrewer_1.1-3
    ## [235] rlang_1.1.6                 remotes_2.5.0
    ## [237] colorRamps_2.3.4            Cairo_1.6-2
    ## [239] ggnewscale_0.5.2            hardhat_1.4.1
    ## [241] beeswarm_0.4.0              prodlim_2025.04.28