Analysis Tools
Most flow cytometry labs use GUI software like FlowJo or FCS Express. These tools are excellent for small panels and routine immunophenotyping. But as panels grow beyond 20 parameters, scripted analysis in R or Python becomes essential for reproducibility and scalability.
Traditional GUI Software
Section titled “Traditional GUI Software”FlowJo is the most widely used flow cytometry software. It supports manual gating, compensation, basic statistics, and figure export. Most published flow cytometry figures come from FlowJo. It runs on Mac and Windows with a commercial license.
FCS Express offers similar functionality with stronger integration into PowerPoint and Excel workflows. Some labs prefer it for its layout and reporting features.
These tools work well for conventional panels with fewer than 10 markers. Their main limitation is manual gating. Every analysis requires an operator to draw gates by hand, which introduces the reproducibility problems discussed in the previous page.
R Packages
Section titled “R Packages”R has the most mature ecosystem for computational flow cytometry. The Bioconductor project hosts most of these packages.
Reading and Managing Data
Section titled “Reading and Managing Data”flowCore is the foundation package. It reads FCS files into R, stores events as a flowFrame object, and provides basic operations like compensation, transformation, and simple gating. Almost every other flow cytometry package in R depends on flowCore.
library(flowCore)fs <- read.flowSet(path = "fcs_files/")flowWorkspace manages gating hierarchies. It stores a tree of gates applied to a flowSet, making it easy to extract populations at any level. This is the R equivalent of the gating tree you see in FlowJo.
Visualization
Section titled “Visualization”ggcyto extends ggplot2 for flow cytometry data. It understands flowFrame and GatingSet objects, so you can create publication quality dot plots, density plots, and histograms with familiar ggplot2 syntax.
library(ggcyto)autoplot(gs[[1]], "CD4", "CD8")CytoExploreR provides interactive exploration of flow cytometry data. It is useful for quickly inspecting gating strategies and comparing samples during early analysis.
Automated Gating
Section titled “Automated Gating”openCyto implements template based automated gating. You define your gating hierarchy in a CSV file specifying which algorithm to use at each step. The package then applies those gates consistently across all samples.
A typical template might look like this:
| alias | pop | parent | dims | gating_method |
|---|---|---|---|---|
| singlets | + | root | FSC-A,FSC-H | singletGate |
| lymph | + | singlets | FSC-A,SSC-A | flowClust |
| cd3pos | + | lymph | CD3 | mindensity |
| cd4pos | + | cd3pos | CD4,CD8 | quadrantGate |
This approach is fully reproducible. The same template produces the same gates on every run.
Unsupervised Clustering
Section titled “Unsupervised Clustering”FlowSOM uses self-organizing maps to cluster cells across all markers simultaneously. It is one of the most popular unsupervised methods for high-dimensional flow and mass cytometry data. FlowSOM first builds a grid of nodes, then metaclusters those nodes into cell populations.
library(FlowSOM)fsom <- FlowSOM(ff, colsToUse = markers, nClus = 20)FlowSOM is fast and scales well to millions of events. It works best when you have a reasonable estimate of the number of expected populations.
Differential Analysis
Section titled “Differential Analysis”CATALYST provides a complete workflow for differential discovery and differential abundance analysis. It is designed for mass cytometry but works equally well with spectral flow cytometry data. CATALYST handles clustering, dimensionality reduction, and statistical testing for differences between conditions.
Python Packages
Section titled “Python Packages”The Python ecosystem for flow cytometry is less mature than R but growing steadily.
Reading FCS Files
Section titled “Reading FCS Files”FlowIO and fcsparser both read FCS files into Python. FlowIO is a pure Python implementation. fcsparser is simpler and returns data as a pandas DataFrame.
import fcsparsermeta, data = fcsparser.parse("sample.fcs")Calibration
Section titled “Calibration”FlowCal provides calibration routines for converting arbitrary fluorescence units to standardized units using calibration beads. This is important for quantitative flow cytometry where you need to compare fluorescence intensities across experiments.
Repurposing Single-Cell Tools
Section titled “Repurposing Single-Cell Tools”Some researchers use scanpy and anndata for flow cytometry analysis. These tools were built for single-cell RNA-seq, but the data structure is similar: cells as rows, features as columns. Loading flow cytometry data into an AnnData object gives you access to UMAP, Leiden clustering, and the rest of the scanpy ecosystem.
import anndata as adimport scanpy as sc
adata = ad.AnnData(X=data[markers].values)sc.pp.neighbors(adata)sc.tl.umap(adata)sc.tl.leiden(adata)This approach works but lacks flow-specific features like compensation and FCS file handling. You need to preprocess the data separately before loading it into anndata.
Unsupervised Analysis Concepts
Section titled “Unsupervised Analysis Concepts”Why Unsupervised Methods Matter
Section titled “Why Unsupervised Methods Matter”Panels with 20 or more markers cannot be fully explored with manual gating on bivariate plots. Unsupervised clustering algorithms examine all dimensions at once and find populations that would be invisible in any single 2D plot.
The Arcsinh Transform
Section titled “The Arcsinh Transform”Flow and mass cytometry data spans several orders of magnitude. Raw fluorescence values are not suitable for clustering or dimensionality reduction. The standard transformation is the inverse hyperbolic sine (arcsinh) with a cofactor:
transformed = arcsinh(raw / cofactor)The cofactor differs by instrument type:
| Instrument | Cofactor |
|---|---|
| Mass cytometry (CyTOF) | 5 |
| Fluorescence flow cytometry | 150 |
This transform compresses high values while preserving differences near zero. It is similar to a log transform but handles zero and negative values gracefully.
Dimensionality Reduction
Section titled “Dimensionality Reduction”UMAP and tSNE reduce high-dimensional cytometry data to two dimensions for visualization. These are the same algorithms used in single-cell RNA-seq analysis. They show the overall structure of cell populations but should not be used for quantitative analysis. Distances on a UMAP plot do not represent real distances in marker space.
Clustering Algorithms
Section titled “Clustering Algorithms”FlowSOM, PhenoGraph, and Leiden are the most common clustering methods:
- FlowSOM: Fast, deterministic with a fixed seed, good default choice.
- PhenoGraph: Builds a k-nearest-neighbor graph, then applies Louvain community detection. Good for discovering rare populations.
- Leiden: An improved version of Louvain with better-connected communities. Available in scanpy.
R vs Python: Ecosystem Comparison
Section titled “R vs Python: Ecosystem Comparison”| Feature | R | Python |
|---|---|---|
| FCS file reading | flowCore (robust, full spec support) | FlowIO, fcsparser (basic) |
| Compensation | flowCore (built-in) | Manual implementation needed |
| Automated gating | openCyto (mature, template-based) | No equivalent |
| Unsupervised clustering | FlowSOM, CATALYST | scanpy (adapted from scRNA-seq) |
| Visualization | ggcyto (publication quality) | matplotlib (manual) |
| Community and publications | Large, established | Growing |
| Best for | Standard and high-dimensional analysis | Integration with ML pipelines |
For most flow cytometry analysis, R is the stronger choice. The Bioconductor ecosystem was built for this data type. Python is a good option when you need to integrate flow cytometry data with machine learning workflows or when your lab already works primarily in Python.
Choosing Your Tools
Section titled “Choosing Your Tools”If you are starting a new flow cytometry analysis project, here is a practical guide:
- Small panels (fewer than 10 markers), routine work: FlowJo or FCS Express. Manual gating is fine.
- Small panels, need reproducibility: openCyto in R with a gating template.
- Large panels (20+ markers): FlowSOM or CATALYST in R. Manual gating cannot cover all dimensions.
- Integration with Python ML pipelines: Load preprocessed data into anndata and use scanpy.