| name | bio-flow-cytometry-bead-normalization |
| description | Bead-based normalization for CyTOF and high-parameter flow cytometry. Covers EQ bead normalization, signal drift correction, and batch normalization. Use when correcting instrument drift in CyTOF or harmonizing data across batches. |
| tool_type | r |
| primary_tool | CATALYST |
Bead Normalization
CyTOF EQ Bead Normalization
library(CATALYST)
library(flowCore)
ff <- read.FCS('cytof_with_beads.fcs')
bead_channels <- c('Ce140Di', 'Eu151Di', 'Eu153Di', 'Ho165Di', 'Lu175Di')
bead_data <- exprs(ff)[, bead_channels]
bead_scores <- rowMeans(scale(bead_data))
bead_threshold <- quantile(bead_scores, 0.99)
is_bead <- bead_scores > bead_threshold
cat('Identified', sum(is_bead), 'bead events (', round(mean(is_bead) * 100, 2), '%)\n')
Calculate Normalization Factors
calculate_norm_factors <- function(ff, bead_channels, bead_idx) {
bead_intensities <- exprs(ff)[bead_idx, bead_channels]
medians <- apply(bead_intensities, 2, median)
return(medians)
}
reference_beads <- c(Ce140 = 500, Eu151 = 600, Eu153 = 550, Ho165 = 450, Lu175 = 400)
sample_beads <- calculate_norm_factors(ff, bead_channels, is_bead)
norm_factors <- reference_beads sample_beads
cat
printnorm_factors
Apply Normalization
marker_channels <- setdiff(colnames(ff), c('Time', 'Event_length', bead_channels))
normalize_cytof <- function(ff, norm_factors, channels) {
expr <- exprs(ff)
global_factor <- exp(mean(log(norm_factors)))
expr[, channels] <- expr[, channels] * global_factor
exprs(ff) <- expr
return(ff)
}
ff_normalized <- normalize_cytofff norm_factors marker_channels
ff_clean ff_normalizedis_bead
cat nrowff_clean
Time-Based Drift Correction
correct_drift <- function(ff, time_channel = 'Time') {
expr <- exprs(ff)
time <- expr[, time_channel]
n_bins <- 20
time_bins <- cut(time, breaks = n_bins, labels = FALSE)
corrected <- expr
marker_cols <- setdiff(colnames(expr), c(time_channel, 'Event_length'))
for (marker in marker_cols) {
bin_medians <- tapply(expr[is_bead, marker], time_bins[is_bead], median
uniquetime_binsis_bead
drift_data data.frame
time bin_medians
intensity bin_medians
loess_fit loessintensity time data drift_data span
correction predictloess_fit newdata data.frametime time_bins
reference mediandrift_dataintensity
corrected marker expr marker reference correction
exprsff corrected
ff
ff_drift_corrected correct_driftff
Batch Normalization with CytoNorm
library(CytoNorm)
train_files <- list.files('batch1_reference/', pattern = '\\.fcs$', full.names = TRUE)
train_data <- lapply(train_files, read.FCS)
model <- CytoNorm.train(
files = train_files,
labels = rep('Reference', length(train_files)),
channels = marker_channels,
transformList = NULL,
nQ = 100,
seed = 42
)
test_files <- list.files( pattern full.names
normalized_files CytoNorm.normalize
model model
files test_files
labels test_files
outputDir
Quantile Normalization
quantile_normalize <- function(fs, channels) {
expr_list <- lapply(fs, function(ff) exprs(ff)[, channels])
all_values <- do.call(rbind, expr_list)
reference_quantiles <- apply(all_values, 2, function(x) sort(x))
reference <- colMeans(reference_quantiles)
normalized_fs <- fs
for (i in 1:length(fs)) {
expr <- exprs(fsi
ch channels
ranks rankexpr ch ties.method
normalized_values approxreference sortreference
xout ranksy
expr ch normalized_values
exprsnormalized_fsi expr
normalized_fs
CATALYST-Based Normalization
library(CATALYST)
sce <- prepData(fs, panel, md,
transform = TRUE,
cofactor = 5,
by_time = TRUE)
Visualization
library(ggplot2)
bead_plot_data <- data.frame(
Time = exprs(ff)[is_bead, 'Time'],
Ce140 = exprs(ff)[is_bead, 'Ce140Di'],
Eu151 = exprs(ff)[is_bead, 'Eu151Di']
)
ggplot(bead_plot_data, aes(x = Time, y = Ce140)) +
geom_point(alpha = 0.1, size = 0.5) +
geom_smooth(method = 'loess', color = 'red') +
theme_bw()
labstitle x y
ggsave width height
compare_df data.frame
Value exprsff exprsff_normalized
Status each nrowff
ggplotcompare_df aesx Value fill Status
geom_histogrambins alpha position
theme_bw
labstitle
Export Normalized Data
write.FCS(ff_clean, 'normalized_sample.fcs')
Related Skills
Workflow order: cytometry-qc → doublet-detection → bead-normalization → clustering
- cytometry-qc - Run first: identify drift and quality issues
- doublet-detection - Run before: remove doublets prior to normalization
- compensation-transformation - Initial data preprocessing
- clustering-phenotyping - Analysis after normalization
- differential-analysis - Batch-aware statistical testing