Contents

# Load required packages
suppressPackageStartupMessages({
  library(treekoR)
  library(SingleCellExperiment)
  library(ggtree)
})

1 Installation

# Install the development version from GitHub:
# install.packages("devtools")
devtools::install_github("adam2o1o/treekoR")
library(treekoR)

2 Overview

treekoR is a novel framework that aims to utilise the hierarchical nature of single cell cytometry data, to find robust and interpretable associations between cell subsets and patient clinical end points. This is achieved by deriving the tree structure of cell clusters, followed by measuring the proportion to parent (proportions of each node in the tree relative to the number of cells belonging to the immediate parent node), in addition to the proportion to all (proportion of cells in each node relative to all cells). These proportions are then used in significance testing and classification models to determine which cell subpopulation proportions most correlated with the patient clinical outcome of interest. treekoR then provides an interactive visualisation which helps to highlight these results.

3 Usage

3.1 Example Data

  • DeBiasi_COVID_CD8_samp: A SingleCellExperiment containing samples of flow cytometry expression data from 39 patients. This data represents a subset of a dataset that was originally used by De Biasi et al. (2020) for the characterisation of CD8+ T cells, comparing between COVID-19 patients and healthy controls.
data(COVIDSampleData)

sce <- DeBiasi_COVID_CD8_samp

3.2 Set up

treekoR requires the following information in the variables:

  • exprs: Single cell expression data (\(n \times p\)), where \(p\) is the number of markers, and \(n\) is the number of cells
  • clusters: a vector of length \(n\) representing the cell type or cluster of each cell (can be character or numeric)
  • classes: a vector of length \(n\) containing the patient outcome/class each cell belongs to
  • samples: a vector of length \(n\) identifying the patient each cell belongs to

In this example: the clusters contain 100 clusters generated by FlowSOM; classes identify whether the cell belongs to a COVID-19 or healthy patient; and samples identify which cell the patient comes from.

exprs <- t(assay(sce, "exprs"))
clusters <- colData(sce)$cluster_id
classes <- colData(sce)$condition
samples <- colData(sce)$sample_id

3.3 Construction of Hierarchy of Clusters

The scaled median marker expression for each cluster is calculated which is used to construct a hierarchical tree.

In this step, the choice of hierarchical aggregation method (which determines the structure of the tree) is determined. By default the framework chooses HOPACH to construct the tree via the hierarchy_method argument, however any of the methods in hclust can be used (see 3.5.1).

clust_tree <- getClusterTree(exprs,
                             clusters,
                             hierarchy_method="hopach")

3.4 Significance testing of Cell Subpopulations

Proportions of each cell cluster in the tree are calculated - both the proportion relative to all and proportion relative to the hierarchical parent. These proportions are used in a two sample t-test, testing for equal means between the patient clinical outcome using both types of proportions.

tested_tree <- testTree(phylo=clust_tree$clust_tree,
                      clusters=clusters,
                      samples=samples,
                      classes=classes,
                      pos_class_name=NULL,
                      subjects=NULL,
                      paired = FALSE)

3.4.1 Extracting significance results

  • node: unique identifier for each node in the hierarchical tree
  • parent: the node of the parent
  • isTip: whether the node is a leaf node in the tree
  • clusters: the clusters belonging to the corresponding node
  • statAll: test statistic obtained from testing between conditions using the proportion of the node relative to all cells in each sample. pvalAll is the corresponding p-value (unadjusted)
  • statParent: test statistic obtained from testing between conditions using the proportion of the node relative to cells in the parent node in each sample. pvalParent is the corresponding p-value (unadjusted)
res_df <- getTreeResults(tested_tree)

head(res_df, 10)
#>     parent node isTip
#> 63     147   63  TRUE
#> 51     139   51  TRUE
#> 67     150   67  TRUE
#> 17     113   17  TRUE
#> 71     150   71  TRUE
#> 135    133  135 FALSE
#> 125    100  125 FALSE
#> 116    115  116 FALSE
#> 45     135   45  TRUE
#> 16     112   16  TRUE
#>                                                                       clusters
#> 63                                                                          41
#> 51                                                                          77
#> 67                                                                          32
#> 17                                                                          79
#> 71                                                                          54
#> 135                                                         75, 68, 58, 67, 57
#> 125 85, 84, 95, 97, 87, 74, 76, 96, 86, 69, 78, 56, 77, 66, 75, 68, 58, 67, 57
#> 116                                                             59, 88, 70, 60
#> 45                                                                          75
#> 16                                                                          38
#>        statAll statParent     pvalAll  pvalParent
#> 63   1.8107720   3.337019 0.080505219 0.002273427
#> 51   1.0823881   3.330997 0.290116635 0.002480052
#> 67   1.7508315   3.229075 0.092603817 0.003327796
#> 17   2.7320088   2.955004 0.012634654 0.007477687
#> 71  -2.3514750  -2.829766 0.033743471 0.008231059
#> 135  2.0299467   2.883285 0.052674011 0.008531634
#> 125  2.7073249   2.707325 0.011833319 0.011833319
#> 116  3.0537776   2.704249 0.005462897 0.014545894
#> 45   1.8202746   2.631287 0.078760577 0.015937817
#> 16   0.7166919   2.548730 0.479584397 0.016265880

3.5 Interactive Visualisation

The results of the previous steps are visualised by a coloured tree with a corresponding heatmap. The heatmap displays the median scaled marker expressions of each cluster to help understand what cell type each cluster may represent, and the tree not only reveals how clusters have been hierarchically aggregated, but is coloured on each node by the test statistic obtained when testing using the proportions relative to all of that node, with the branch connecting the child to the parent coloured by the test statistic obtained when testing using the proportions relative to parent of the child node.

plotInteractiveHeatmap(tested_tree,
                       clust_med_df = clust_tree$median_freq,
                       clusters=clusters)

3.5.1 Using different hierarchical aggregations

Below we change the hierarchical aggregation technique to average-linkage hierarchical clustering. The available options include any of the available ethods in the hclust() function, ie, one of "ward.D", "ward.D2", "single", "complete", "average", "mcquitty", "median" or "centroid"

clust_tree <- getClusterTree(exprs,
                             clusters,
                             hierarchy_method="average")

tested_tree <- testTree(clust_tree$clust_tree,
                      clusters=clusters,
                      samples=samples,
                      classes=classes,
                      pos_class_name=NULL,
                      subjects=NULL,
                      paired = FALSE)

plotInteractiveHeatmap(tested_tree,
                       clust_med_df = clust_tree$median_freq,
                       clusters=clusters)

3.5.2 Extracting Proportions

Return a dataframe containig the absolute proportions and proportions to parent for each cell type for each sample. These proportions can then be used for visualisation or as input into further analyses.

prop_df <- getCellProp(phylo=clust_tree$clust_tree,
                       clusters=clusters,
                       samples=samples,
                       classes=classes)

head(prop_df[,1:8])
#>       sample class prop_all_90 prop_all_10 prop_all_89 prop_all_21 prop_all_45
#> COV1    COV1   COV  0.07058824 0.041176471 0.011764706 0.005882353 0.011764706
#> COV10  COV10   COV  0.00000000 0.005555556 0.005555556 0.005555556 0.005555556
#> COV12  COV12   COV  0.02857143 0.000000000 0.000000000 0.005714286 0.000000000
#> COV13  COV13   COV  0.03205128 0.006410256 0.000000000 0.000000000 0.000000000
#> COV14  COV14   COV  0.01986755 0.013245033 0.033112583 0.000000000 0.000000000
#> COV15  COV15   COV  0.02097902 0.006993007 0.006993007 0.000000000 0.006993007
#>       prop_all_98
#> COV1   0.01764706
#> COV10  0.01111111
#> COV12  0.02285714
#> COV13  0.03205128
#> COV14  0.00000000
#> COV15  0.00000000