Analysis Type : QC report

Authors
Affiliation

Eugénie Lohmann

CRCM (CiBi Group)

Adrien Mazuel

CRCM (CiBi Group)

Published

July 6, 2023

Input parameters
Sélection
project Demonstration on ChKV
rds demochkv.rds
path /home/lohmann/immunopanc_jg/12_demochkv_sg/11_concat/
adcode TRUE
analyse_type QC
min_cells 5
min_samples 1
p_value 0.001
cluster_id cluster_id
conditions cond
batch acqdate
individuals patient_id
ncells Freq
sorted 1
log_bar 1
cluster_column_id marker
id_mfi shared_col

This document has been formated using knitr (Xie 2015) and quarto (Allaire 2022).

1 Features summary

Sample table with information on conditions (cond), batch (acqdate), individuals (patient_id), ncells (Freq)

Information on metaclusters is grouped in this table with the number of cells and the corresponding description.

A total of 39 markers are included in this analysis report.

The exhaustive list of markers is as follows: Bi209Di, Dy161Di, Dy162Di, Dy163Di, Dy164Di, Er166Di, Er167Di, Er168Di, Er170Di, Eu151Di, Eu153Di, Gd155Di, Gd156Di, Gd158Di, Gd160Di, Ho165Di, In113Di, In115Di, Lu175Di, Nd142Di, Nd143Di, Nd144Di, Nd145Di, Nd146Di, Nd148Di, Nd150Di, Pt194Di, Pt198Di, Sm147Di, Sm149Di, Sm152Di, Sm154Di, Tb159Di, Tm169Di, Yb171Di, Yb172Di, Yb173Di, Yb174Di, Yb176Di.

2 Number of cells Barplot

  • Check the number of cells in each fcs.

  • Controls the possible association with a batch effect.

Bars are sorted by conditions. Annotations columns are added on the barplot’s top to control possible batch effects.

(a) Condition grouped samples
Figure 1: Barplot number of cells per fcs

3 MFI’s Heatmap

  • Check or help annotate clusters.

The input is the MFI cluster x marker array. The MFI is already transformed (typically using asinh(intensity/cofactor)).

Heatmap of the MFI with clusters in rows and markers in columns.

A barplot shows the number of cells in each metacluster.

The first heatmap covers all fcs.

4 Mfi x Abundance Heatmap

  • Heatmap grouping the MFI of each marker per cluster and cluster abundance per fcs.

  • MFIs are normalized per line between 0 and 1 to give a comparable distribution of marker expression per cluster.

  • Markers are grouped hierarchically to facilitate cluster reading/interpretation.

Relative abundances shown on the second heat map are transformed abundances relative to the cluster mean. The green-purple color scale applies to the entire matrix.

Figure 2: Abundance heatmap with clusters associated with mfi

5 Abundance Heatmap

  • Visualize samples organized according to hierarchical grouping or by condition.

  • Check that sample states are homogeneous; identify outliers or gender effects.

  • Check whether conditions have already been separated.

Percentage heatmap with samples in columns and clusters in rows.

By default, clusters and samples are grouped using hierarchical clustering. It is also possible to classify samples by condition, gender or patient, and to give clusters as an ordered vector.

Group abundance is shown in the right-hand barplot with log values.

Figure 3: Abundance Heatmap

6 PCA (or NMDS) of samples using percentages per cluster

  • Visualize samples in a reduced space.

  • Check that sample states are homogeneous; identify outliers or gender effects.

  • Check whether conditions can already be separated.

Input is the percentages table sample x cluster. Percentages are previously transformed with asinh(%+cte) with cte = 0.03 and centered by cluster.

6.1 Barplot of variance of each PC

  • check that the first 2 or 3 components retains the main information

3 graphs as below ; points are samples. Overimpose conditions or Genders on each points using color and shape.

7 Plots of variables in order to identify their contribution to each PC

PCA (or NMDS) of samples using MFI per cluster Similar to Nowicka et al., but at the clustering level (not the cell level).

  • View the samples in a reduced space.

  • Verify that States of samples are homogeneous; identify outliers or Gender effects.

  • Check if the conditions could already be separated.

Input is the MFI table sample x cluster. MFI are previously transformed.

Code

Code
# css: www/custom.css
# js: www/script.js
#| include=F
library(R.AnalytiCyte)
library(readr)
library(dplyr)
library(SummarizedExperiment)
library(diffcyt)
library(ComplexHeatmap)
library(RColorBrewer)
library(randomcoloR)
library(colorRamp2)
library(data.table)
library(tidyr)
library(ggplot2)
library(ggrepel)
library(grid)
library(kableExtra)
library(tibble)
library(plotly)
library(reactable)





# parameters set

se <- dataSE$SE_abundance
rowData(se) |>
  as.data.frame() %>%
  mutate(cluster_id = factor(cluster_id, levels = rownames(se))) %>%
  arrange(cluster_id) -> rowData(se)

desired_width <- 10 # Adjust the
desired_height <- 10 # Adjust the coefficient to control the scaling


knitr::opts_chunk$set(
  fig.width = desired_width,
  fig.height = desired_height
)


se_mfi <- dataSE$SE_mfi
applied_fct_plot <- "median"
t_metadata <- "meta"
perCellCounts <- "perCellCounts"
id <- "shared_col"
scaled_MFI <- "scaled_MFI"

Conditions <- params$conditions
batch <- params$batch

patient <- params$individuals
size_ <- params$ncells


col_interest <- Conditions
col_cell <- size_
separator_ <- Conditions
col_ <- Conditions
shape_ <- Conditions

r_order <- rowData(se) |>
  as.data.frame() |>
  dplyr::arrange(desc(n_cells)) |>
  rownames()


cluster_column_id <- params$cluster_column_id # : "ftr (sec)"
id_mfi <- params$id_mfi # : "file"

sorted <- params$sorted
log_bar <- params$log_bar

if (params$analyse_type == "DA" | params$analyse_type == "DS") {
  trend_method_ <- "none"
  min_cells_ <- params$min_cells
  min_samples_ <- params$samples
  normalize_ <- FALSE
  norm_factors_ <- "TMM"
  c_id <- params$cluster_id
  pval <- params$p_value
}


R.AnalytiCyte::create_dt(colData(se) %>%
  as.data.frame(), length = 10, filter = "top")


R.AnalytiCyte::create_dt(rowData(se) %>%
  as.data.frame(), length = 10, filter = "top")
markers <- names(assays(se_mfi))




labs <- knitr::all_labels()

R.AnalytiCyte::barplot_n_cells(
  se = se,
  t_metadata = t_metadata,
  counts = size_,
  Conditions = Conditions,
  id = id,
  sorted = sorted,
  col_interest = col_interest,
  col_cell = col_cell,
  batch = batch
)
R.AnalytiCyte::heatmap_median_mfi_like_catalyst(
  # ajouter la possibilité de trier les colonnes, rows
  se = se,
  id = id,
  exprs = "counts",
  se_mfi = se_mfi,
  subset_marker = NULL, # reduction of marker of interest, order of the heatmap if clustr F
  subset_cluster = NULL, # reduction of clusters of interest, order of the heatmap if clustc F
  clustr = T,
  clustc = T,
  margin_ = 2,
  t_metadata = t_metadata,
  split_heat = NULL,
  q_ = 0.1,
  fontsize_ = 8,
  round_ = 8,
  applied_fct = "mean",
  log_bar = 0,
  title = "All Samples"
)
#
#
#
#
# Let's say our group comparison is based on the metadata column `r col_interest`, the different groups are : `r unique(metadata(se)[[t_metadata]][[col_interest]])`

#
subgroup <- unique(metadata(se)[[t_metadata]][[col_interest]])
second_plot <- FALSE
markers_list <- names(assays(se_mfi))
cluster_list <- names(se_mfi)
for (sub_el in subgroup) {
  R.AnalytiCyte::heatmap_median_mfi_like_catalyst(
    # ajouter la possibilité de trier les colonnes, rows
    se = se,
    id = id,
    exprs = "counts", # perCellCounts
    se_mfi = se_mfi,
    subset_marker = {
      if (second_plot) markers_list[new_order_c] else markers_list
    }, # reduction of marker of interest, order of the heatmap if clustC F
    subset_cluster = {
      if (second_plot) cluster_list[new_order_r] else cluster_list
    }, # reduction of clusters of interest, order of the heatmap if clustR
    clustr = {
      if (second_plot) F else T
    },
    clustc = {
      if (second_plot) F else T
    },
    margin_ = 2,
    t_metadata = t_metadata,
    split_heat = c(separator_, sub_el),
    q_ = 0.1,
    fontsize_ = 8,
    round_ = 8,
    applied_fct = "mean",
    log_bar = 1,
    title = sub_el
  ) -> plot
  #   |> ComplexHeatmap::draw(
  #   column_title = sub_el,
  #   column_title_gp = grid::gpar(fontsize = 16)
  # )


  second_plot <- TRUE
  new_order_c <- ComplexHeatmap::column_order(plot)
  new_order_r <- ComplexHeatmap::row_order(plot)
}

R.AnalytiCyte::heatmap_like_cytofast(
  se = se, # se=dataSE$SE_abundance
  exprs = "counts", #  assays name reference in se -> counts
  id = id, # sample id accross metadata "shared_col"
  se_mfi = se_mfi, # a SummarizedExperiment (se) object with mfi info   se_mfi=dataSE$SE_mfi
  scaled_MFI = scaled_MFI, # Name of metadata, if the SE scaled_MFI data
  clust_id = cluster_column_id, # name of the cluster column name
  metadata_sub = c("acqdate", "Gender", "patient_id"),
  id_mfi = "shared_col",
  t_metadata = t_metadata,
  metadata_sort = NULL,
  clustr = T,
  clustc = F,
  fontsize_ = 8,
  subset_patient = NULL, # reduction of patients of interest, order of the heatmap if clustr F
  subset_marker = NULL, # reduction of marker of interest, order of the heatmap if clustr F
  subset_cluster = NULL, # reduction of clusters of interest, order of the heatmap if clustc F
  round_ = 8,
  applied_fct = "mean" # applied_fct_plot
)

R.AnalytiCyte::heatmap_abundance_like_catalyst(
  # ajouter la possibilité de trier les colonnes, rows
  se = se,
  exprs = "counts",
  t_metadata = t_metadata,
  separator_ = separator_,
  metadata_sub = c("acqdate", "patient_id", "cond"),
  patient = patient,
  id = id,
  metadata_sort = "cond",
  clustr = T,
  clustc = T,
  margin_ = 1,
  q_ = 0.01,
  round_ = 8,
  fontsize_ = 8,
  subset_patient = NULL, # reduction of patients of interest, order of the heatmap if clustr F
  subset_cluster = NULL, # reduction of clusters of interest, order of the heatmap if clustc F
  log_bar = 1
)
PCA_SE <- R.AnalytiCyte::pca_plot(
  se = se,
  pca = T,
  pcX = "PC1",
  pcY = "PC2",
  exprs = "perCellCountsNorm",
  t_metadata = t_metadata,
  id = "shared_col",
  round_ = 8,
  col_ = col_,
  shape_ = shape_,
  size_ = size_,
  scaled_MFI = NULL
)
PCA_SE$eigen
R.AnalytiCyte::pca_plot(
  se = se,
  pca = T,
  pcX = "PC1",
  pcY = "PC2",
  exprs = "perCellCountsNorm",
  t_metadata = t_metadata,
  id = "shared_col",
  round_ = 8,
  col_ = col_,
  shape_ = shape_,
  size_ = size_,
  scaled_MFI = NULL
)$pca


R.AnalytiCyte::pca_plot(
  se = se,
  pca = T,
  pcX = "PC3",
  pcY = "PC2",
  exprs = "perCellCountsNorm",
  t_metadata = t_metadata,
  id = "shared_col",
  round_ = 8,
  col_ = col_,
  shape_ = shape_,
  size_ = size_,
  scaled_MFI = NULL
)$pca



R.AnalytiCyte::pca_plot(
  se = se,
  pca = T,
  pcX = "PC1",
  pcY = "PC3",
  exprs = "perCellCountsNorm",
  t_metadata = t_metadata,
  id = "shared_col",
  round_ = 8,
  col_ = col_,
  shape_ = shape_,
  size_ = size_,
  scaled_MFI = NULL
)$pca

R.AnalytiCyte::pca_plot(
  se = se,
  pca = T,
  pcX = "PC1",
  pcY = "PC2",
  exprs = "perCellCountsNorm",
  t_metadata = t_metadata,
  id = "shared_col",
  round_ = 8,
  col_ = col_,
  shape_ = shape_,
  size_ = size_,
  scaled_MFI = NULL
)$biplot


R.AnalytiCyte::pca_plot(
  se = se,
  pca = T,
  pcX = "PC3",
  pcY = "PC2",
  exprs = "perCellCountsNorm",
  t_metadata = t_metadata,
  id = "shared_col",
  round_ = 8,
  col_ = col_,
  shape_ = shape_,
  size_ = size_,
  scaled_MFI = NULL
)$biplot


R.AnalytiCyte::pca_plot(
  se = se,
  pca = T,
  pcX = "PC1",
  pcY = "PC3",
  exprs = "perCellCountsNorm",
  t_metadata = t_metadata,
  id = "shared_col",
  round_ = 8,
  col_ = col_,
  shape_ = shape_,
  size_ = size_,
  scaled_MFI = NULL
)$biplot



PCA_MFI <- R.AnalytiCyte::pca_plot(
  se = se_mfi,
  pca = T,
  pcX = "PC1",
  pcY = "PC2",
  exprs = "counts",
  t_metadata = t_metadata,
  id = "shared_col",
  round_ = 8,
  col_ = col_,
  shape_ = shape_,
  size_ = size_,
  scaled_MFI = scaled_MFI
)
PCA_MFI$eigen
# PCA_MFI$pca

R.AnalytiCyte::pca_plot(
  se = se_mfi,
  pca = T,
  pcX = "PC1",
  pcY = "PC2",
  exprs = "counts",
  t_metadata = t_metadata,
  id = "shared_col",
  round_ = 8,
  col_ = col_,
  shape_ = shape_,
  size_ = size_,
  scaled_MFI = scaled_MFI
)$pca


R.AnalytiCyte::pca_plot(
  se = se_mfi,
  pca = T,
  pcX = "PC3",
  pcY = "PC2",
  exprs = "counts",
  t_metadata = t_metadata,
  id = "shared_col",
  round_ = 8,
  col_ = col_,
  shape_ = shape_,
  size_ = size_,
  scaled_MFI = scaled_MFI
)$pca



R.AnalytiCyte::pca_plot(
  se = se_mfi,
  pca = T,
  pcX = "PC1",
  pcY = "PC3",
  exprs = "counts",
  t_metadata = t_metadata,
  id = "shared_col",
  round_ = 8,
  col_ = col_,
  shape_ = shape_,
  size_ = size_,
  scaled_MFI = scaled_MFI
)$pca

R.AnalytiCyte::pca_plot(
  se = se_mfi,
  pca = T,
  pcX = "PC1",
  pcY = "PC2",
  exprs = "counts",
  t_metadata = t_metadata,
  id = "shared_col",
  round_ = 8,
  col_ = col_,
  shape_ = shape_,
  size_ = size_,
  scaled_MFI = scaled_MFI
)$biplot


R.AnalytiCyte::pca_plot(
  se = se_mfi,
  pca = T,
  pcX = "PC3",
  pcY = "PC2",
  exprs = "counts",
  t_metadata = t_metadata,
  id = "shared_col",
  round_ = 8,
  col_ = col_,
  shape_ = shape_,
  size_ = size_,
  scaled_MFI = scaled_MFI
)$biplot


R.AnalytiCyte::pca_plot(
  se = se_mfi,
  pca = T,
  pcX = "PC1",
  pcY = "PC3",
  exprs = "counts",
  t_metadata = t_metadata,
  id = "shared_col",
  round_ = 8,
  col_ = col_,
  shape_ = shape_,
  size_ = size_,
  scaled_MFI = scaled_MFI
)$biplot

Sources

Allaire, JJ. 2022. Quarto: R Interface to ’Quarto’ Markdown Publishing System. https://CRAN.R-project.org/package=quarto.
Xie, Yihui. 2015. Dynamic Documents with R and Knitr. 2nd ed. Boca Raton, Florida: Chapman; Hall/CRC. https://yihui.org/knitr/.