Contents


Most of the pipeline and visualizations presented herein were adapted from Nowicka et al. (2017)’s “CyTOF workflow: differential discovery in high-throughput high-dimensional cytometry datasets”. For the complete workflow, go here.

# load required packages
library(CATALYST)
library(cowplot)
library(flowCore)
library(diffcyt)
library(scater)
library(SingleCellExperiment)

1 Example data

# load example data
data(PBMC_fs, PBMC_panel, PBMC_md)
PBMC_fs
## A flowSet with 8 experiments.
## 
##   column names:
##   CD3(110:114)Dd CD45(In115)Dd pNFkB(Nd142)Dd pp38(Nd144)Dd CD4(Nd145)Dd CD20(Sm147)Dd CD33(Nd148)Dd pStat5(Nd150)Dd CD123(Eu151)Dd pAkt(Sm152)Dd pStat1(Eu153)Dd pSHP2(Sm154)Dd pZap70(Gd156)Dd pStat3(Gd158)Dd CD14(Gd160)Dd pSlp76(Dy164)Dd pBtk(Er166)Dd pPlcg2(Er167)Dd pErk(Er168)Dd pLat(Er170)Dd IgM(Yb171)Dd pS6(Yb172)Dd HLA-DR(Yb174)Dd CD7(Yb176)Dd
head(PBMC_panel)
##      fcs_colname antigen marker_class
## 1 CD3(110:114)Dd     CD3         type
## 2  CD45(In115)Dd    CD45         type
## 3 pNFkB(Nd142)Dd   pNFkB        state
## 4  pp38(Nd144)Dd    pp38        state
## 5   CD4(Nd145)Dd     CD4         type
## 6  CD20(Sm147)Dd    CD20         type
head(PBMC_md)
##                 file_name sample_id condition patient_id
## 1 PBMC_patient1_BCRXL.fcs    BCRXL1     BCRXL   Patient1
## 2   PBMC_patient1_Ref.fcs      Ref1       Ref   Patient1
## 3 PBMC_patient2_BCRXL.fcs    BCRXL2     BCRXL   Patient2
## 4   PBMC_patient2_Ref.fcs      Ref2       Ref   Patient2
## 5 PBMC_patient3_BCRXL.fcs    BCRXL3     BCRXL   Patient3
## 6   PBMC_patient3_Ref.fcs      Ref3       Ref   Patient3

The code snippet below demonstrates how to construct a flowSet from a set of FCS files. However, we also give the option to directly specify the path to a set of FCS files (see next section).

# download exemplary set of FCS files
url <- "http://imlspenticton.uzh.ch/robinson_lab/cytofWorkflow"
fcs_zip <- "PBMC8_fcs_files.zip"
download.file(paste0(url, "/", fcs_zip), destfile = fcs_zip, mode = "wb")
unzip(fcs_zip)

# read in FCS files as flowSet
fcs_files <- list.files(pattern = ".fcs$")
fs <- read.flowSet(fcs_files, transformation = FALSE, truncate_max_range = FALSE)

2 Data preparation

Data used and returned throughout differential analysis are held in objects of the SingleCellExperiment class. To bring the data into the appropriate format, prepData() requires the following inputs:

Optionally, features will specify which columns (channels) to keep from the input data. Here, we keep all measurement parameters (default value features = NULL).

(sce <- prepData(PBMC_fs, PBMC_panel, PBMC_md))
## class: SingleCellExperiment 
## dim: 24 5428 
## metadata(2): experiment_info cofactor
## assays(1): exprs
## rownames(24): CD3 CD45 ... HLA_DR CD7
## rowData names(3): channel_name marker_name marker_class
## colnames: NULL
## colData names(3): sample_id condition patient_id
## reducedDimNames(0):
## spikeNames(0):
## altExpNames(0):

We provide flexibility in the way the panel and metadata table can be set up. Specifically, column names are allowed to differ from the example above, and multiple factors (patient ID, conditions, batch etc.) can be specified. Arguments panel_cols and md_cols should then be used to specify which columns hold the required information. An example is given below:

# alter panel column names
panel2 <- PBMC_panel
colnames(panel2)[1:2] <- c("channel_name", "marker")

# alter metadata column names & add 2nd condition
md2 <- PBMC_md
colnames(md2) <- c("file", "sampleID", "cond1", "patientID")
md2$cond2 <- rep(c("A", "B"), 4)

# construct SCE
prepData(PBMC_fs, panel2, md2, 
    panel_cols = list(channel = "channel_name", antigen = "marker"),
    md_cols = list(file = "file", id = "sampleID", 
        factors = c("cond1", "cond2", "patientID")))

Note that, independent of the input panel and metadata tables, the constructor will fix the names of mandatory slots for latter data accession (sample_id in the rowData, channel_name and marker_name in the colData). The md table will be stored under experiment_info inside the metadata.

3 Diagnostic plots

3.1 plotCounts: Number of cells measured per sample

The number of cells measured per sample may be plotted with plotCounts, or directly accessed via n_cells(). This plot should be used as a guide together with other readouts to identify samples where not enough cells were assayed.

n_cells(sce)
## BCRXL1   Ref1 BCRXL2   Ref2 BCRXL3   Ref3 BCRXL4   Ref4 
##    528    881    665    438    563    660    934    759
plotCounts(sce, color_by = "condition")

3.2 plotMDS: Multi-dimensional scaling plot

A multi-dimensional scaling (MDS) plot on median expresion values may be rendered with plotMDS. Such a plot will give a sense of similarities between samples in an unsupervised way and of key difference in expression before conducting any formal testing. In our example, we can see a clear separation between reference (REF) and stimulation condition (BCRXL).

plotMDS(sce, color_by = "condition")

3.3 plotExprHeatmap: Heatmap of (scaled) median marker expressions

plotExprHeatmap will show a heatmap on median marker intensities with hierarchically clustered rows (samples) and columns (markers). This plot should give an idea of which markers will drive sample clustering, and how similiar samples are in their expression profile. We specify bin_anno = TRUE to display expression values inside each bin, and row_anno = TRUE to include row annotations for each factor in metadata(daf).

plotExprHeatmap(sce, bin_anno = TRUE, row_anno = TRUE)

4 Clustering

4.1 cluster: FlowSOM clustering & ConsensusClusterPlus metaclustering

CATALYST provides a simple wrapper to perform high resolution FlowSOM clustering and lower resolution ConsensusClusterPlus metaclustering. By default, the data will be initially clustered into xdim = 10 x ydim = 10 = 100 groups. Secondly, the function will metacluster populations into 2 through maxK (default 20) clusters. To make analyses reproducible, the random seed may be set via seed. By default, if the colData()$marker_class column is specified, the set of markers with marker class “type” will be used for clustering. Alternatively, the markers that should be used for clustering can be specified with argument cols_to_use.

# specify markers to use for clustering
lineage_markers <- c("CD3", "CD45", "CD4", "CD20", 
    "CD33", "CD123", "CD14", "IgM", "HLA_DR", "CD7")
sce <- cluster(sce, features = lineage_markers, 
    xdim = 10, ydim = 10, maxK = 20, verbose = FALSE, seed = 1)       

Let K = xdim x ydim be the number of FlowSOM clusters. cluster will add information to the following slots of the input SingleCellExperiment:

  • rowData:
    • cluster_id: cluster ID as inferred by FlowSOM. One of 1, …, K.
  • colData:
    • marker_class: factor "type" or "state". Specifyies whether a marker has been used for clustering or not, respectively.
  • metadata:
    • SOM_codes: a table with dimensions K x (# type markers). Contains the SOM codes.
    • cluster_codes: a table with dimensions K x (maxK + 1). Contains the cluster codes for all metaclusterings.
    • delta_area: a ggplot object (see below for details).

4.2 Delta area plot

The delta area represents the amount of extra cluster stability gained when clustering into k groups as compared to k-1 groups. It can be expected that high stability of clusters can be reached when clustering into the number of groups that best fits the data. The “natural” number of clusters present in the data should thus corresponds to the value of k where there is no longer a considerable increase in stability (pleateau onset). For more details, the user can refer to the original description of the consensus clustering method (Monti et al. 2003).

# access & render delta area plot
metadata(sce)$delta_area

4.3 plotMedExprs: Median marker-expressions by cluster

A combined boxplot and jitter of median marker intensitied can be generated via plotMedExprs. In order to compare medians for each cluster, and potentially identify changes across conditions early on, we specify facet = "cluster_id".

p <- plotMedExprs(sce, k = "meta8", facet = "cluster_id", 
  group_by = "condition", shape_by = "patient_id")
p$facet$params$ncol <- 4
p

Alternatively, we can facet the above plot by antigen in order to compare marker expressions calculated over all cells across conditions:

p <- plotMedExprs(sce, facet = "antigen", 
    group_by = "condition", shape_by = "patient_id")
p$facet$params$ncol <- 6
p

4.4 plotClusterExprs: Marker-densities by cluster

Distributions of marker intensities (arcsinh-transformed) across cell populations of interest can be plotted with plotClusterExprs. We specify features = "type" (equivalent to type_markers(sce)), to include type-markers only. Here, blue densities are calculated over all cells and serve as a reference.

plotClusterExprs(sce, k = "meta8", features = "type")

4.5 mergeClusters: Manual cluster merging

Provided with a 2 column data.frame containing old_cluster and new_cluster IDs, mergeClusters allows for manual cluster merging of any clustering available within the input SingleCellExperiment (i.e. the xdim x ydim FlowSOM clusters, and any of the 2-maxK ConsensusClusterPlus metaclusters). For latter accession (visualization, differential testing), the function will assign a unique ID (specified with id) to each merging, and add a column to the cluster_codes inside the metadata slot of the input SingleCellExperiment.

data(merging_table)
head(merging_table)
## # A tibble: 6 x 2
##   old_cluster new_cluster 
##         <dbl> <chr>       
## 1           1 B-cells IgM+
## 2           2 surface-    
## 3           3 NK cells    
## 4           4 CD8 T-cells 
## 5           5 B-cells IgM-
## 6           6 monocytes
sce <- mergeClusters(sce, k = "meta20", table = merging_table, id = "merging1")
head(cluster_codes(sce))
##   som100 meta2 meta3 meta4 meta5 meta6 meta7 meta8 meta9 meta10 meta11 meta12
## 1      1     1     1     1     1     1     1     1     1      1      1      1
## 2      2     1     1     1     1     1     1     1     1      1      1      1
## 3      3     1     1     1     2     2     2     2     2      2      2      2
## 4      4     1     2     1     2     2     2     2     2      2      2      2
## 5      5     1     2     2     2     2     2     2     2      2      2      2
## 6      6     1     2     2     3     3     3     3     3      3      3      3
##   meta13 meta14 meta15 meta16 meta17 meta18 meta19 meta20     merging1
## 1      1      1      1      1      1      1      1      1 B-cells IgM+
## 2      1      1      1      1      1      1      1      1 B-cells IgM+
## 3      2      2      2      2      2      2      2      2     surface-
## 4      2      2      2      2      2      2      2      3     NK cells
## 5      3      3      3      3      3      3      3      4  CD8 T-cells
## 6      4      4      4      4      4      4      4      5 B-cells IgM-

4.6 plotClusterHeatmap: Heatmap of (meta)clustering results

Clusterings and metaclusters maybe be viewing with the plotClusterHeatmap. In its 1st panel, the function will display median (arcsinh-transformed and optionally scaled) cell-type marker expressions (across all samples). Depending on argument hm2, the 2nd panel will vary as follows:

  • "abundances": cluster frequencies by sample;
  • "state_markers": median cell state marker expressions across clusters (analogous to the left-hand side heatmap);
  • a character string/vector corresponding to one/multiple marker(s): median marker expressions by sample.

Argument scale (default TRUE) specifies whether scaled values should be plotted. These correspond to arcsinh-transformed expression values scaled between 0 and 1 using low (1%) and high (99%) percentiles as boundaries. Note that, in any case, hierarchical clustering is performed on the unscaled data.
While it is only used here for visualization, this additional transformation of the arcsinh-transformed data can sometimes give a better representation of relative differences in marker expression between cell populations.

# median pS6 expression by sample as 2nd heatmap
plotClusterHeatmap(sce, hm2 = "pS6", k = "meta12", m = "meta6")

# population frequencies by sample as 2nd heatmap
plotClusterHeatmap(sce, hm2 = "abundances", 
    draw_freqs = TRUE, cluster_anno = FALSE)

4.7 plotAbundances: Relative population abundances

Relative population abundances for any clustering of interest can be plotted with plotAbundances. Argument by will specify whether to plot proportions for each sample or cluster.
If by = "sample_id", the function displays each sample’s cell type composition, and the size of a given stripe reflects the proportion of the corresponding cell type the given sample. Argument group then specifies the facetting. If by = "cluster_id", argument group then specifies the grouping and color coding.

plotAbundances(sce, k = "meta12", by = "sample_id", group_by = "condition")

plotAbundances(sce, k = "merging1", by = "cluster_id", 
  group_by = "condition", shape_by = "patient_id")

5 Dimensionality reduction

Dimension reductions (DRs) can be computed using one of scater’s runX functions (X = "TSNE", "UMAP", ...). Note that, by default, scater expects expression values to be stored in the logcounts assay of the SCE; specification of exprs_values = "exprs" is thus required. To make results reproducible, the random seed should be set via set.seed prior to computing reduced dimensions.

set.seed(1601)
sce <- runUMAP(sce, exprs_values = "exprs")

DRs available within the SCE can be viewed via reducedDimNames and accessed with reducedDim(s):

# view & access DRs
reducedDimNames(sce)
## [1] "UMAP"
head(reducedDim(sce, "UMAP"))
##            [,1]      [,2]
## [1,]  0.6971504 -1.868102
## [2,]  0.6413146 -2.553464
## [3,] -6.9212380  1.186260
## [4,]  0.1162500 -2.341456
## [5,]  1.5299314  3.564078
## [6,] -1.5480760 -1.832847

While scater’s plotReducedDim function can be used to visualize DRs, CATALYST provides the plotDR wrapper, specifically to allow for coloring cells by the various clusterings available, and to support facetting by metadata factors (e.g., experimental condition, sample IDs):

# color by marker expression & split by condition
plotDR(sce, color_by = "pS6") + facet_wrap("condition")

# color by 8 metaclusters & split by sample ID
plotDR(sce, color_by = "meta8") + facet_wrap("sample_id", ncol = 4)

6 Filtering

SCEs constructed with prepData can be filtered using the filterSCE function, which allows for filtering of both cells and markers according to conditional statements in dplyr-style. When filtering on cluster_ids, argument k specifies which clustering to use (the default NULL uses colData column "cluster_id"). Two examples are given below:

u <- filterSCE(sce, patient_id == "Patient1")
table(u$sample_id)
## 
##   Ref1 BCRXL1 
##    881    528
u <- filterSCE(sce, k = "meta8",
    cluster_id %in% c(1, 3, 8))
plot_grid(
    plotDR(sce, color_by = "meta8"),
    plotDR(u, color_by = "meta8"))

7 Differental testing with diffcyt

CATALYST has been designed to be compatible with the diffcyt package (Weber 2018), which implements statistical methods for differential discovery in high-dimensional cytometry (including flow cytometry, mass cytometry or CyTOF, and oligonucleotide-tagged cytometry) using high-resolution clustering and moderated tests. The input to the diffcyt pipeline can either be raw data, or a SingleCellExperiment object. We give an example of the latter below.
Please refer to the diffcyt vignette and R documentation (??diffcyt) for more detailed information.

# create design & constrast matrix
design <- createDesignMatrix(ei(sce), cols_design = "condition")
contrast <- createContrast(c(0, 1))

# test for
# - differential abundance (DA) of clusters
# - differential states (DS) within clusters
res_DA <- diffcyt(sce, clustering_to_use = "meta10",
    analysis_type = "DA", method_DA = "diffcyt-DA-edgeR",
    design = design, contrast = contrast)
res_DS <- diffcyt(sce, clustering_to_use = "meta10",
    analysis_type = "DS", method_DS = "diffcyt-DS-limma",
    design = design, contrast = contrast)

7.1 plotDiffHeatmap: Heatmap of differential testing results

Differential testing results returned by diffcyt can be displayed with the plotDiffHeatmap function.

For differential abundance (DA) tests, plotDiffHeatmap will display

  • median (arcsinh-transformed) cell-type marker expressions (across all samples), and
  • relative cluster abundances by samples

For differential state (DS) tests, plotDiffHeatmap will display

  • median (arcsinh-transformed) cell-type marker expressions (across all samples)
  • median (arcsinh-transformed) cell-state marker expressions by sample

Clusters (DA) and cluster-marker combinations (DS), respectively, will be marked as significant if their adjusted p-value falls below the threshold value specified with th (default 0.1), and will be ordered by significance if order = TRUE (the default). The number of top findings to display can be specified with top_n (default 20). When normalize = TRUE, the right-hand side heatmap will display Z-score normalized values. For DA, cluster frequencies will be arcsine-square-root scaled prior to normalization.

plotDiffHeatmap(sce, res_DA, all = TRUE, th = 0.05)

plotDiffHeatmap(sce, res_DS, hm1 = FALSE, top_n = 20)

8 Session Information

sessionInfo()
## R version 3.6.3 (2020-02-29)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 18.04.4 LTS
## 
## Matrix products: default
## BLAS:   /home/biocbuild/bbs-3.10-bioc/R/lib/libRblas.so
## LAPACK: /home/biocbuild/bbs-3.10-bioc/R/lib/libRlapack.so
## 
## locale:
##  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
##  [3] LC_TIME=en_US.UTF-8        LC_COLLATE=C              
##  [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       
## 
## attached base packages:
## [1] parallel  stats4    stats     graphics  grDevices utils     datasets 
## [8] methods   base     
## 
## other attached packages:
##  [1] scater_1.14.6               ggplot2_3.3.0              
##  [3] SingleCellExperiment_1.8.0  SummarizedExperiment_1.16.1
##  [5] DelayedArray_0.12.2         BiocParallel_1.20.1        
##  [7] matrixStats_0.56.0          Biobase_2.46.0             
##  [9] GenomicRanges_1.38.0        GenomeInfoDb_1.22.1        
## [11] IRanges_2.20.2              S4Vectors_0.24.3           
## [13] BiocGenerics_0.32.0         diffcyt_1.6.4              
## [15] flowCore_1.52.1             cowplot_1.0.0              
## [17] CATALYST_1.10.3             BiocStyle_2.14.4           
## 
## loaded via a namespace (and not attached):
##   [1] utf8_1.1.4                  shinydashboard_0.7.1       
##   [3] R.utils_2.9.2               ks_1.11.7                  
##   [5] lme4_1.1-21                 tidyselect_1.0.0           
##   [7] htmlwidgets_1.5.1           grid_3.6.3                 
##   [9] Rtsne_0.15                  munsell_0.5.0              
##  [11] codetools_0.2-16            DT_0.13                    
##  [13] withr_2.1.2                 colorspace_1.4-1           
##  [15] flowViz_1.50.0              knitr_1.28                 
##  [17] flowClust_3.24.0            robustbase_0.93-6          
##  [19] openCyto_1.24.0             labeling_0.3               
##  [21] GenomeInfoDbData_1.2.2      mnormt_1.5-6               
##  [23] farver_2.0.3                flowWorkspace_3.34.1       
##  [25] vctrs_0.2.4                 TH.data_1.0-10             
##  [27] xfun_0.12                   R6_2.4.1                   
##  [29] ggbeeswarm_0.6.0            clue_0.3-57                
##  [31] rsvd_1.0.3                  locfit_1.5-9.4             
##  [33] bitops_1.0-6                assertthat_0.2.1           
##  [35] promises_1.1.0              scales_1.1.0               
##  [37] multcomp_1.4-12             beeswarm_0.2.3             
##  [39] gtable_0.3.0                sandwich_2.5-1             
##  [41] rlang_0.4.5                 GlobalOptions_0.1.1        
##  [43] splines_3.6.3               lazyeval_0.2.2             
##  [45] hexbin_1.28.1               shinyBS_0.61               
##  [47] BiocManager_1.30.10         yaml_2.2.1                 
##  [49] reshape2_1.4.3              abind_1.4-5                
##  [51] httpuv_1.5.2                IDPmisc_1.1.20             
##  [53] RBGL_1.62.1                 tools_3.6.3                
##  [55] bookdown_0.18               ellipsis_0.3.0             
##  [57] RColorBrewer_1.1-2          ggridges_0.5.2             
##  [59] Rcpp_1.0.4                  plyr_1.8.6                 
##  [61] base64enc_0.1-3             zlibbioc_1.32.0            
##  [63] purrr_0.3.3                 RCurl_1.98-1.1             
##  [65] FlowSOM_1.18.0              GetoptLong_0.1.8           
##  [67] viridis_0.5.1               zoo_1.8-7                  
##  [69] haven_2.2.0                 ggrepel_0.8.2              
##  [71] cluster_2.1.0               fda_2.4.8.1                
##  [73] magrittr_1.5                RSpectra_0.16-0            
##  [75] magick_2.3                  ncdfFlow_2.32.0            
##  [77] data.table_1.12.8           openxlsx_4.1.4             
##  [79] circlize_0.4.8              mvtnorm_1.1-0              
##  [81] shinyjs_1.1                 xtable_1.8-4               
##  [83] mime_0.9                    hms_0.5.3                  
##  [85] evaluate_0.14               XML_3.99-0.3               
##  [87] rio_0.5.16                  jpeg_0.1-8.1               
##  [89] mclust_5.4.5                readxl_1.3.1               
##  [91] gridExtra_2.3               shape_1.4.4                
##  [93] ggcyto_1.14.1               compiler_3.6.3             
##  [95] ellipse_0.4.1               tibble_3.0.0               
##  [97] flowStats_3.44.0            KernSmooth_2.23-16         
##  [99] crayon_1.3.4                minqa_1.2.4                
## [101] R.oo_1.23.0                 htmltools_0.4.0            
## [103] corpcor_1.6.9               pcaPP_1.9-73               
## [105] later_1.0.0                 tidyr_1.0.2                
## [107] rrcov_1.5-2                 RcppParallel_5.0.0         
## [109] ComplexHeatmap_2.2.0        MASS_7.3-51.5              
## [111] boot_1.3-24                 Matrix_1.2-18              
## [113] car_3.0-7                   cli_2.0.2                  
## [115] R.methodsS3_1.8.0           igraph_1.2.5               
## [117] forcats_0.5.0               pkgconfig_2.0.3            
## [119] foreign_0.8-76              plotly_4.9.2               
## [121] vipor_0.4.5                 XVector_0.26.0             
## [123] drc_3.0-1                   stringr_1.4.0              
## [125] digest_0.6.25               RcppAnnoy_0.0.16           
## [127] tsne_0.1-3                  ConsensusClusterPlus_1.50.0
## [129] graph_1.64.0                rmarkdown_2.1              
## [131] cellranger_1.1.0            uwot_0.1.8                 
## [133] edgeR_3.28.1                DelayedMatrixStats_1.8.0   
## [135] curl_4.3                    shiny_1.4.0.2              
## [137] gtools_3.8.2                nloptr_1.2.2.1             
## [139] rjson_0.2.20                nlme_3.1-145               
## [141] lifecycle_0.2.0             jsonlite_1.6.1             
## [143] carData_3.0-3               BiocNeighbors_1.4.2        
## [145] viridisLite_0.3.0           limma_3.42.2               
## [147] fansi_0.4.1                 pillar_1.4.3               
## [149] lattice_0.20-41             fastmap_1.0.1              
## [151] httr_1.4.1                  plotrix_3.7-7              
## [153] DEoptimR_1.0-8              survival_3.1-11            
## [155] glue_1.3.2                  zip_2.0.4                  
## [157] png_0.1-7                   Rgraphviz_2.30.0           
## [159] stringi_1.4.6               nnls_1.4                   
## [161] BiocSingular_1.2.2          CytoML_1.12.1              
## [163] latticeExtra_0.6-29         dplyr_0.8.5                
## [165] irlba_2.3.3

References

Bodenmiller, Bernd, Eli R Zunder, Rachel Finck, Tiffany J Chen, Erica S Savig, Robert V Bruggner, Erin F Simonds, et al. 2012. “Multiplexed Mass Cytometry Profiling of Cellular States Perturbed by Small-Molecule Regulators.” Nature Biotechnology 30 (9):858–67. https://doi.org/10.1038/nbt.2317.

Bruggner, Robert V, Bernd Bodenmiller, David L Dill, Robert J Tibshirani, and Garry P Nolan. 2014. “Automated Identification of Stratifying Signatures in Cellular Subpopulations.” Proceedings of the National Academy of Sciences of the United States of America 111 (26). National Academy of Sciences:E2770–E2777. https://doi.org/10.1073/pnas.1408792111.

Monti, Stefano, Pablo Tamayo, Jill Mesirov, and Todd Golub. 2003. “Consensus Clustering: A Resampling-Based Method for Class Discovery and Visualization of Gene Expression Microarray Data.” Machine Learning 52 (1):91–118. https://doi.org/10.1023/A:1023949509487.

Nowicka, M, C Krieg, LM Weber, FJ Hartmann, S Guglietta, B Becher, MP Levesque, and MD Robinson. 2017. “CyTOF Workflow: Differential Discovery in High-Throughput High-Dimensional Cytometry Datasets [Version 2; Referees: 2 Approved].” F1000Research 6 (748). https://doi.org/10.12688/f1000research.11622.2.

Weber, LM. 2018. “Diffcyt: Differential Discovery in High-Dimensional Cytometry via High-Resolution Clustering.” R Package Version 1.0.0. https://github.com/lmweber/diffcyt.