## ----opts, include = FALSE----------------------------------------------------
box::use(knitr[opts_chunk])
opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)

## ----install, eval = FALSE----------------------------------------------------
# if (!require("BiocManager", quietly = TRUE))
#   install.packages("BiocManager")
# 
# BiocManager::install("Seqtometry")

## ----overview, echo = FALSE, fig.align = "center", out.width = "80%"----------
box::use(knitr[include_graphics])
include_graphics("Graphical_Abstract.png")

## ----fetch, message = FALSE---------------------------------------------------
# Cleanly add functions from various packages into the current namespace
box::use(
  TENxPBMCData[TENxPBMCData],
  SingleCellExperiment[counts, rowData],
  data.table[fread],
  tibble[deframe],
  stringr[str_split_1])

# Gene expression data (with gene symbols)
dat <- TENxPBMCData(dataset = "pbmc3k")
gex <- counts(dat) |> as("dgCMatrix")
dimnames(gex) <- list(rowData(dat)[["Symbol_TENx"]], dat[["Barcode"]])

# Signatures (consisting of gene symbols)
sig <- fread("signatures.tsv") |>
  deframe() |>
  lapply(\(x) stringr::str_split_1(x, ","))

## ----pre----------------------------------------------------------------------
box::use(
  scuttle[perCellQCMetrics, perCellQCFilters, normalizeCounts],
  Seqtometry[impute])

qc <- function(mat) {
  # Indices of mitochondrial genes
  mito_idx <- grep("^MT-", rownames(mat))

  # Calculate QC metrics
  res <- mat |>
    perCellQCMetrics(subsets = list("Mito" = mito_idx)) |>
    perCellQCFilters(sub.fields = "subsets_Mito_percent")

  # Remove low quality cells
  mat[, !res$discard]
}

imputed_gex <- gex |>
  qc() |>
  normalizeCounts() |>
  impute()

## ----score--------------------------------------------------------------------
box::use(
  future[plan],
  Seqtometry[score])

# May set up parallel backend if it is supported
# Will default to non-parallel (sequential) execution
plan("sequential")

# Allot 1 GiB of memory for global variables
options(future.globals.maxSize = 1024 ^ 3)

# Scoring with lymphocyte signatures
scores <- sig[c("T cell", "B cell")] |>
  score(imputed_gex, signatures = _)

## ----plot, fig.align = "center", out.width = "50%"----------------------------
box::use(ggplot2[...])

# A flow cytometry style theme for plots
theme_custom <- theme_bw() + theme(
  aspect.ratio = 1,
  panel.grid = element_blank(),
  panel.background = element_blank(),
  panel.border = element_rect(color = "black", fill = NA, linewidth = 2),
  axis.title = element_text(size = 32, face = "italic"),
  axis.text = element_text(size = 16))

# Utility function for generating flow cytometry style plots
biaxial_plot <- function(d, x, y) {
  lim <- c(-0.15, 1.15)
  brk <- seq(0, 1, 0.25)
  lbl <- c("0", "0.25", "0.5", "0.75", "1")
  ggplot(d, aes(x = .data[[x]], y = .data[[y]])) +
    geom_density_2d(color = "black", h = c(0.2, 0.2),
      contour_var = "ndensity", binwidth = 0.125) +
    scale_x_continuous(limits = lim, breaks = brk, labels = lbl) +
    scale_y_continuous(limits = lim, breaks = brk, labels = lbl) +
    theme_custom
}

# Utility function to draw a rectangular region
rect_region <- function(lims) {
  do.call(annotate, c(lims, geom = "rect",
    color = "blue", fill = NA, linewidth = 2))
}

# Limits defining a rectangular region for double negative cells
dn_lims <- list(xmin = -0.075, xmax = 0.5, ymin = 0, ymax = 0.5)

# Draw the biaxial plot with the rectangular region
biaxial_plot(scores, "T cell", "B cell") + rect_region(dn_lims)

## ----gate, fig.align = "center", out.width = "50%"----------------------------
# Subset the imputed data, keeping only the cells in the blue region
gated_imputed_gex <- with(scores,
  imputed_gex[, `T cell` < dn_lims$xmax & `B cell` < dn_lims$ymax])

# Score the subsetted data with the remaining signatures
gated_scores <- sig[c("NK cell", "Monocyte")] |>
  Seqtometry::score(gated_imputed_gex, signatures = _)

# Plot the new scores
biaxial_plot(gated_scores, "Monocyte", "NK cell")

## ----info---------------------------------------------------------------------
sessionInfo()

