Defines cell populations in flow and spectral cytometry through manual gates (rectangle, polygon, quadrant, boolean) and reproducible automated gating (openCyto gating templates, flowDensity data-driven thresholds, flowClust model-based gates), organized as a hierarchical GatingSet (flowWorkspace) and round-tripped with FlowJo via CytoML. Covers the canonical gate order (time -> debris -> singlets -> live -> lineage), FMO-vs-isotype boundary setting, gate-order dependence and recompute semantics, rare-event/MRD gating, and per-population statistics. Use when building a gating strategy, automating a manual FlowJo scheme across samples, choosing manual vs data-driven gates, or extracting population frequencies.
Defines cell populations in flow and spectral cytometry through manual gates (rectangle, polygon, quadrant, boolean) and reproducible automated gating (openCyto gating templates, flowDensity data-driven thresholds, flowClust model-based gates), organized as a hierarchical GatingSet (flowWorkspace) and round-tripped with FlowJo via CytoML. Covers the canonical gate order (time -> debris -> singlets -> live -> lineage), FMO-vs-isotype boundary setting, gate-order dependence and recompute semantics, rare-event/MRD gating, and per-population statistics. Use when building a gating strategy, automating a manual FlowJo scheme across samples, choosing manual vs data-driven gates, or extracting population frequencies.
Before using code patterns, verify installed versions match. If versions differ:
R: packageVersion('<pkg>') then to verify parameters
?function_name
openCyto gating-method names drift across versions - confirm with gt_list_methods() on the installed package (e.g. gate_flowclust_2d vs flowClust.2d). Adapt rather than retrying.
Gating Analysis
"Gate my data to identify cell populations" -> Define populations by drawing boundaries in marker space, organized as a hierarchy, manually or with reproducible data-driven methods.
R (automated): openCyto gating template (CSV) or flowDensity::deGate
The Single Most Important Modern Insight -- FMO, Not Isotype, Sets the Boundary; and Gate Order Is a Funnel
The position of a positive/negative boundary is governed by SPREADING ERROR - the variance that every other bright fluorophore spills into the channel of interest - NOT by nonspecific antibody binding (Roederer 2001 Cytometry 45:194). An FMO control (full panel minus the one channel) reproduces exactly that spreading and is the correct way to set the gate; an isotype control addresses only nonspecific binding, has a different total fluorochrome load, and sits in the wrong place. Isotypes are deprecated for boundary-setting (still fine for a qualitative new-reagent check). Equally load-bearing is gate ORDER: time -> debris (FSC/SSC) -> singlets (FSC-A vs FSC-H) -> live/dead -> lineage. This is a funnel that removes the broadest, least-specific contaminants first (time instability corrupts ALL channels; doublets are scatter-normal AND viable AND double-positive; dead cells bind antibody nonspecifically) so each narrower downstream gate operates on clean input. Reorder it - gate lineage before singlets - and artifacts are baked into the result that no later gate can remove.
Automated-Gating Taxonomy
Method
Citation
Mechanism
When to use
openCyto
Finak 2014 PLoS Comput Biol 10:e1003806
CSV gatingTemplate + per-gate algorithms
reproduce a manual SOP across many samples; human-readable + automated
mindensity (openCyto)
-
KDE valley between two peaks
clear bimodal marker, 1D cut
tailgate (openCyto)
-
KDE-derivative tail onset
rare positive tail, no clean second peak
quantileGate (openCyto)
-
cut at a fixed event quantile
threshold should track a fraction
flowDensity
Malek 2015 Bioinformatics 31:606
sequential bivariate density cutoffs
reproduce an entire predefined manual strategy
flowClust / gate_flowclust_2d
Lo 2009 BMC Bioinformatics 10:145
t-mixture + Box-Cox, K by BIC
overlapping elliptical populations
DAFi
Lee 2018 Cytometry A 93:597
recursive filter + clustering on a hierarchy
discovery WITH interpretability
Rule of thumb: 1D bimodal -> mindensity; rare tail -> tailgate; overlapping ellipses -> flowClust.2d; replicate a full manual SOP -> flowDensity; discovery-with-interpretability -> DAFi.
Build a Gating Hierarchy
Goal: Apply gates in the canonical order and extract population statistics.
Approach: Build a GatingSet, add gates parent-by-parent, then recompute() - WITHOUT it, child populations are empty. Gates apply on the TRANSFORMED scale if the GatingSet is transformed.
library(flowWorkspace); library(flowCore)
gs <- GatingSet(fs)# matrix dimnames preserve 'FSC-A'/'FSC-H'; data.frame() would mangle them to FSC.A
singlet <- polygonGate('singlets', .gate = matrix(c(2e4,1e4,25e4,2e5,25e4,26e4,2e4,4e4), ncol =2, byrow =TRUE,dimnames=list(NULL,c('FSC-A','FSC-H'))))
gs_pop_add(gs, singlet, parent ='root')
gs_pop_add(gs, rectangleGate('CD3+', CD3 =c(1.5,Inf)), parent ='singlets')# transformed scale
recompute(gs)# REQUIRED - else children are empty
gs_pop_get_stats(gs, type ='count')
Automated Gating with an openCyto Template
Goal: Apply a reproducible, declarative gating strategy across all samples.
Approach: A CSV template (alias/pop/parent/dims/gating_method/gating_args) defines the hierarchy; gt_gating applies it. Confirm method names with gt_list_methods().
Goal: Detect a rare population (e.g. MRD at 1e-4 to 1e-5).
Approach: Unsupervised clustering FAILS here (a 1e-5 population is ~10 events, invisible to density/SOM); MRD stays supervised/template-gated. Compute the acquisition depth needed from the target sensitivity and the ~50-event Poisson rule BEFORE acquiring; never downsample.
# Need ~50-60 target events for CV < ~15%; sensitivity 1e-5 => acquire ~1e6 cells.
target_sensitivity <- 1e-5
events_needed <-ceiling(50/ target_sensitivity)# cells to acquire# Gate the rare population with a prespecified template; report observed LOD from cells acquired.
Per-Method Failure Modes
Empty child populations
Trigger: querying stats right after gs_pop_add. Mechanism: membership not computed. Symptom: zero counts. Fix:recompute(gs).
Gate coordinates on the wrong scale
Trigger: raw-scale gate values on a transformed GatingSet (or vice versa). Mechanism: scale mismatch. Symptom: gate in the wrong place / empty. Fix: set gate values on the same (transformed) scale the GS uses.
Isotype-defined boundary
Trigger: isotype control to set positivity. Mechanism: spreading error, not nonspecific binding, sets the edge. Symptom: wrong negative boundary. Fix: use FMO.
Clustering used for rare events
Trigger: FlowSOM for a 1e-5 population. Mechanism: too few events. Symptom: rare pop absorbed into a neighbor. Fix: supervised/template gating; size acquisition for the Poisson floor.