Analysis code for "Phasor-based spectral flow cytometry enables fit-free single-cell spectroscopy at scale."
This repository reproduces every figure, statistic and simulation reported in the paper. It transforms 16-channel spectral flow cytometry (SFC) acquisitions and hyperspectral confocal imaging (HSI) stacks into spectral phasor coordinates, fits linear component models in phasor space, and quantifies membrane order with the LAURDAN order ratio
Supported inputs are .fcs (spectral flow cytometry) and .lsm / .tif (hyperspectral microscopy).
python -m venv venv && source venv/bin/activate
pip install -r requirements.txtTested on Python 3.13.9. Package versions in requirements.txt are pinned to those reported in the manuscript's Code availability statement.
Raw and processed datasets are archived on Zenodo (see the Data availability statement in the paper). Data files are not tracked in this repository.
Every notebook and module reads from a single dataset root, ../data, that is, a data/ folder sitting next to the repository:
phSFC_repo/
├── data/ # download from Zenodo, not tracked here
│ ├── SFC/
│ │ ├── MLVs/Pre-gated/{MLVs 1, MLVs 2}
│ │ ├── Vero cells/{Pre-gated/Vero cells 1..8, Ungated, OLS Unmixed}
│ │ ├── BAL/{Pre-gated, Ungated}
│ │ ├── Flow rate analysis/
│ │ └── Gain analysis/
│ └── HSI/
│ ├── MVLs/{MLVs 1, MLVs 2}
│ └── Vero cells/Vero cells 1..8
└── phSFC/ # this repository
The simulation modules resolve this through phsfc_spectra.DATA_ROOT, which defaults to ../data/SFC and can be overridden with the PHSFC_DATA environment variable. Notebooks set their own DATA_ROOT (or explicit data_paths) in the configuration cell near the top; all of them point below ../data. The only data file kept in the repository itself is phasor_gates.csv, the exported phasor gate polygons used to reproduce Figure 2d.
Hyperspectral masks live beside their images as <folder>/mask/mask_<filename>.png and are generated with interactive_mask_generator.py.
.
├── figure_1.ipynb # main figures
├── figure_2.ipynb
├── supp_figure_S1.ipynb # supplementary figures, numbered as in the paper
├── ... supp_figure_S15.ipynb
├── phsfc_*.py # shared analysis modules
├── vero_reference.py # real-data calibration constants
├── spectra_simulator.py # 16-channel violet detector model
├── interactive_mask_generator.py
├── interactive_phasor_gating.py
├── phasor_gates.csv # exported phasor gate polygons
├── requirements.txt
└── extras/ # not required to reproduce the paper
Each notebook is named for the figure it produces. Run the cells in order after setting the paths in the configuration cell near the top.
| Notebook | Produces | Output folder |
|---|---|---|
figure_1.ipynb |
Figure 1: phasor framework, perturbation sweeps, mixture linearity, gain series | figures_figure_1/ |
figure_2.ipynb |
Figure 2a–d, Extended Data Fig. 1, Supplementary Fig. S10 | Figure_2/ |
supp_figure_S1.ipynb |
Supp. Fig. S1: flow rate and detector gain on measured acquisitions | figures_vel_gain_analysis/ |
supp_figure_S2.ipynb |
Supp. Fig. S2: spectral phasor framework for SFC and HSI | inline (no file export) |
supp_figure_S3.ipynb |
Supp. Fig. S3: cross-modal MLV workflow, HSI vs SFC | Supp_Figure_S3/ |
supp_figure_S4.ipynb |
Supp. Fig. S4: MLVs by hyperspectral microscopy | Supp_Figure_S4/ |
supp_figure_S5.ipynb |
Supp. Fig. S5: linear combination across lipid mixtures and cholesterol | Supp_Figure_S5/ |
supp_figure_S6.ipynb |
Supp. Fig. S6: Vero membrane order after MβCD, by HSI | Supp_Figure_S6/ |
supp_figure_S7.ipynb |
Supp. Fig. S7: simulated spectral detection limits | figures_close_components/ |
supp_figure_S8.ipynb |
Supp. Fig. S8: detection limit along the LAURDAN Lo–Ld trajectory | figures_close_components/ |
supp_figure_S9.ipynb |
Supp. Fig. S9: three-component unmixing precision across phasor space | figures_unmixing_precision/ |
supp_figure_S15.ipynb |
Supp. Fig. S15: phasor component analysis vs conventional OLS unmixing | figures_phasor_vs_unmixing/ |
Supplementary Figs. S11 to S14, S16 and S17 are FlowJo gating hierarchies and validation controls; they are not generated by this code.
figure_2.ipynb is organised in sections a to f, each headed with the manuscript figure it produces. All outputs are written below Figure_2/.
| Section | Produces | Subfolder |
|---|---|---|
| a | Figure 2a: multilamellar vesicles | Figure_2a/ |
| b | Figure 2b: Vero cells with MβCD | Figure_2b/ |
| c | Extended Data Fig. 1 and Supplementary Fig. S10: BAL, per population | BAL_per_population/ |
| d | Figure 2c: myeloid vs lymphoid, within a condition | Figure_2c_myeloid_vs_lymphoid/ |
| e | Figure 2c: control vs LPS, within a compartment | Figure_2c_control_vs_LPS/ |
| f | Figure 2d: phasor gating and backgating | Figure_2d/ |
Run the sections in the order they appear. That order follows the data pipeline rather than the figure numbering: section c builds the shared BAL multi-component model and the contour and annotation helpers that sections d, e and f all consume, so it must run first even though its own outputs belong to Extended Data Fig. 1 and Supplementary Fig. S10. Sections d and e together produce Figure 2c, d giving the myeloid versus lymphoid contrast within each treatment group and e the control versus LPS contrast within each lineage.
Every statistical table is written to CSV alongside the figure it accompanies.
The three simulation notebooks (S7, S8, S9) expose the Monte-Carlo size (N_MC, MC_POINTS) in their configuration cell. Defaults run in minutes; raise them to reproduce the published validation points exactly.
| Module | Responsibility |
|---|---|
phsfc_sim_common.py |
Detector model, Poisson photon sampling, phasor transform, threaded Monte-Carlo |
phsfc_spectra.py |
Spectral models: synthetic perturbations and measured MLV pure-component spectra |
phsfc_unmixing.py |
Two- and three-component phasor unmixing and its geometry |
phsfc_stats.py |
Sample-level detection limits, analytic power, n-vs-n Monte-Carlo validation |
phsfc_fcs.py |
Phasor analysis of measured .fcs acquisitions: gating, polar statistics, dataset discovery |
phsfc_plots.py |
Figure builders (each returns a matplotlib figure) |
vero_reference.py |
Real-data calibration: effective photons per event, events per sample, between-replicate biological variability |
spectra_simulator.py |
Definition of the 16 violet-excited channels (V1 to V16) |
Dependency order: spectra_simulator → phsfc_sim_common → {phsfc_spectra, phsfc_unmixing} → {phsfc_stats, phsfc_plots}.
Generates binary masks from hyperspectral microscopy images (.lsm, .tif) by polygonal ROI selection. Masks are reloaded at analysis time so that pixels outside the ROI propagate as missing values and are excluded from every histogram, component fit and statistic.
python interactive_mask_generator.py /path/to/image/folderQt-based GUI for phasor gating of .fcs data. Draw polygonal gates directly on the phasor plot, inspect gated events on conventional scatter plots, and export the gate vertices with Export Gates (CSV). The exported CSV (phasor_gates.csv) is re-applied reproducibly by section f of figure_2.ipynb to produce Figure 2d.
python interactive_phasor_gating.py path_to_file.fcsRequires PyQt5 (PyQt6 is used automatically if PyQt5 is absent).
If you use this code, please cite the paper and PhasorPy.