15 Updates and Issues
Source:vignettes/articles/15_Updates_And_Issues.Rmd
15_Updates_And_Issues.RmdUpdates and news
Version 0.8.1: More fluorophores, rearranging detectors if needed
Version 0.8.2: Support for Mosaic and Xenith cytometers
Version 0.8.3: Patch for error introduced in 0.8.2
Version 0.8.4: Changes to error messaging in check.control.file
Version 0.8.5: Improvements to keyword handling in writing FCS files
Version 0.8.6: Improvements to plotting, fluorophore matching
Version 0.8.7: Support for Symphony A5 SE and Cytek Northern Lights. More improvements to plotting. Marker names will now be added to the control file based on matches in the FCS file names, where possible. The Hotspot(TM) matrix will be calculated and plotted as per the preprint by Peter Mage et al.
-
Version 0.9.0:
- Changes to
get.spectral.variants, including fixing of previously user-modifiable parameters, low-level denoising of spectra and a bug patch for situations with beads using internal negatives. - More checks in
check.control.file. - New parallel backend.
- Faster AutoSpectral unmixing in base R.
- Adjustments to reduce any discontinuities produced during unmixing.
- See also updates in
AutoSpectralRcpp, including a large speed up and general improvement to the Poisson IRLS unmixing. - Patch to
reload.flow.controlbug affecting ID7000 samples. - Patch to
define.flow.control()affecting universal negative definitions and impacting onclean.controls(). - Calculation of the unmixing matrix (Moore-Penrose pseudoinverse)
will now be done using singular value decomposition
svd()for numerical stability for all approaches. Up to now, it has been done with normal equations viasolve(). This should be better in edge cases. In most cases, the only difference will be floating point error. Calculation time is equivalent because almost all of the computational effort is on projecting the raw data into the unmixed space via the unmixing matrix, not calculating the unmixing matrix. - New functions to
save.unmixing.matrixandcalculate.weights - Patches to
define.flow.controlthat were causing redundant gates to be created. - Code legibility formatting.
- Changes to
-
Version 0.9.1:
- Switch to
FlowSOM::SOM()fromEmbedSOM::SOM(). - Patch to appending “-A” suffix to parameter names.
- Switch to
-
Version 0.9.2:
- Faster base R per-cell optimization.
- Patch to writing of “-A” in the channel names of FCS files.
-
Version 1.0.0:
- Changes to
unmix.autospectral()to speed up processing and reduce discontinuities in the resulting unmixed data. - Version 1.0.0 brings a revamp to how AutoSpectral identifies the
best spectra on a per-cell basis. The theory behind it remains the
same–we are still trying to identify the variation in the
autofluorescence and fluorophores that best reduces the residual on a
per-cell basis. Now, however, we do not need to do that using brute
force. Instead, we can search only through variants (or
autofluorescences) that align with a given cell’s residual. Thus we can
pre-screen the variants to a select few and then test just those. This
means we can figure out the solution in way less time. It also means
that a native R implementation of the algorithm is possible in R in a
somewhat reasonable time frame. So, that may help for anyone struggling
to use the fast C++ version in
AutoSpectralRcpp. - Since we can now quickly identify which variants are useful for a given cell, we can test more variants, allowing a finer-grained view of the variation, which may improve unmixing quality.
- Autofluorescence extraction and fluorophore variation extraction are now modified to search for more variation, focusing on “problematic” cells that remain far from where they should be when the first batch of variation is applied. This is most helpful for extracting autofluorescence in complex tissue samples, where AutoSpectral previously struggled to deal with the last few messy cells.
- Speed in unmixing should be the biggest change, particularly if you
run using
AutoSpectralRcpp. - When extracting autofluorescence using
get.af.spectra(), you will now get a set of plots showing you the unmixed data for the channels most affected by the autofluorescence (“worst channels”). The same channels will be plotted after a single round of autofluorescence extraction per cell (as in AutoSpectral v0.9.2 and earlier) as well as after the second round, using data from more difficult cells. To see this, run withrefine = TRUE, which is the default setting now. - Autofluorescence is now assigned to each cell using a shortcut to “project” where the AF will impact on fluorophore or residual space. This is especially fast for residual-based assignment.
- Perhaps most importantly, discontinuities that sometimes appeared in the data after unmixing using per-cell-fluorophore optimization, particularly with the “fast” approximation, should now be gone or at least greatly diminished.
- Another change to the base unmixing functions to provide a speed-up when unmixing in a per-cell loop. When performing standard OLS or WLS unmixing outside of per-cell optimization, singular value decomposition will still be used to calculate the unmixing matrix.
- Changes to
-
Version 1.5.0:
- New gating approach adapted from
flowstate. This uses cellular landmarks to identify the position of key populations on forward and side-scatter. Essentially, we backgate. This means that you can use well-expressed markers on known cell populations (think CD3, CD19, CD14) to define the location of your cells. This is fast, appears to be pretty robust, and should be easy for you, the user, to change how it works. Control over this is provided via the CSV control file spreadsheet using two new columns: “gate.name” to define which controls should share the same gate, and “gate.define” (TRUE/FALSE) to specify which samples should be used to define the gate boundaries (e.g., we might use CD4 but not TIM-3 or IL-4). - To assist with the new gating, there is a
tune.gate()function that allows you to put in a range of parameters to quickly see the impact on the gate boundary prior to runningdefine.flow.control(). - Native FCS read/write functionality adapted from
flowstate. - FCS file concatenation via
concatenateFCS(). - Faster gating by reducing
MASS::kde2dcalls and allowing C++ kernel density estimation ifAutoSpectralRcppis installed. - Faster plotting along the same lines.
- Hopefully graceful error handling during
clean.controls(). - Hopefully graceful error handling with diagnostic plotting during
gate definition, both with the gate.define functions and directly in
define.flow.control(). - Success/failure reporting from
clean.controls(). - Reduced memory usage when unmixing.
- Chunking of files when unmixing to support unmixing of any size of file.
- Spectral signature QC when running
get.fluorophore.spectra(). - Autofluorescence profile QC when running
get.af.spectra(). - Faster processing in
get.af.spectra()through integration ofAutoSpectralRcpp, when available.
- New gating approach adapted from
-
Version 1.5.1:
- A patch for
get.spectral.variants()to resolve an issue that occurred when only a single fluorophore was being assessed.
- A patch for
-
Version 1.5.2:
- A patch for
get.af.spectra()to better handle situations where a given AF spectrum is essentially inverted, with the greatest magnitude signal being negative. This occurs occasionally on the FACSDiscover S8 and A8 cytometers. The spectra will now be kept as negative, since this provides better unmixing, empirically. For the plotting, any negative spectra will be inverted to avoid issues with scaling. - A patch for
get.af.spectra()to exclude plotting of the unmixed data on biplots when only a single fluorophore is being unmixed (so only one axis can be drawn). - Exclusion of a problematic keyword from BD FACSDiscover files. This
affects
define.keywords(), which updates the keywords after unmixing. Files were being produced, but the keyword headers were corrupted. - Rearrange the arguments for
tune.gate(),define.gate.landmarks()and alsodefine.gate.density()to put thegate.nameargument earlier. The default value forgate.namehas been removed because the user should be providing this.
- A patch for
AutoSpectral 1.5.3 (2026-03-31)
AutoSpectral 1.5.4 (2026-04-13)
Bug fixes
- A change to
validate.control.file()to permit duplication of the unstained samples in the control file. Necessary for integration with the newAutoSpectralHelperapp.
AutoSpectral 1.5.6 (2026-04-21)
Improvements
- M x N and N x N plotting of unmixed data using
unmixed.mxn.plot()andunmixed.nxn.plot() - Calculate the secondary stain index per “Evaluating the performance
of Slingshot SpectraComp particles as universal single stain controls in
flow cytometry” by Oliveira et al. Call
calculate.ssi(). - Plot the mismatch between two spectral profiles (e.g., beads
vs. cells) as in the pre-print by Konecny et al. on unmixing-dependent
spread. Call
ppectral.mismatch.plot(). - Compare unmixing of the same data side-by-side with two different
spectral mixing matrices. Call
compare.unmix(). - Multiple file formats when creating plots: pdf, tiff, png, jpg, etc.
Bug fixes
- Now passing random seed from
asp$downsample.seedthroughout. - Fixed an issue where
spectral.variant.plot()would not push the plot to the viewer.
AutoSpectral 1.6.0 (2026-06-01)
New Features
- Automated spectral profile extraction using approaches developed by
Nathan Laniewski in
flowState. This simplifies the workflow considerably, and eliminates the need for gating, which was a key cause of stress. The new automated approach employs projection orthogonalization to determine the peak channel (which way is the control going that isn’t like the autofluorescence?), and uses cosine filtering (which events are least contaminated by AF?) to find the clean spectral signatures. - New joint unmixing pipeline
(
unmix.autospectral.joint()), implemented in C++, using covariance-weighted spillover and residual alignment to solve autofluorescence and fluorophore assignment together rather than sequentially. Structurally collinear fluorophore pairs (e.g., APC/BUV661) are handled via joint-pair conflict resolution so genuine double-positive signal isn’t suppressed. Seven new tuning parameters (n.af.passes,cell.weight,noise.floor,alpha,collinear.threshold,joint.pair.resolution,refine.af.quantile) are now wired through bothunmix.fcs()andunmix.folder(). -
calculate.optimize.necessity()to determine which cells actually require per-cell fluorophore optimization, avoiding unnecessary computation. - Multipass autofluorescence refinement using a matching-pursuit approach, with fixed pass-1 baseline denominators to prevent noise from dominating the highest-abundance cells in later passes.
-
simulate.flow.data()generates synthetic ground-truth data by summing single-stained controls, providing a benchmark for false-negative rates on double-positive populations. - New AF autofluorescence comparison and benchmarking functions for evaluating accuracy against ground truth.
- A merging of the approaches for per-cell autofluorescence assignment
using the covariance structure:
assign.af.joint.cov()to assess how autofluorescence variation impacts fluorophore values, with joint scoring of residuals. This improves on the existing residual- and projection-based AF assignment methods. - Extension of the variance-covariance error propagation plus residuals scoring metric to per-cell fluorophore optimization. This avoids the previous need to optimize in the reduced space of only positive fluorophores in each cell, which was responsible for discontinuities appearing in several data sets around zero.
- Legacy mode support. All pre-existing workflows remain intact, but
some must be accessed via a
legacyargument in the function calls. - AutoSpectral landing page. Type
?AutoSpectralin your IDE to open a workflow overview with links to key functions and articles. - FCS 3.1 compliance. Modified FCS files now carry the
$ORIGINALITY,$LAST_MODIFIER, and$LAST_MODIFIEDkeywords per the FCS 3.1 standard.
Improvements
- C++ accelerated FCS reading and writing via
AutoSpectralRcpp. Adapted from work by Samuel Granjeaud. - Much faster plotting throughout, using a combination of point
downsampling, raster rendering
(
ragg/scattermore), and C++ acceleration whenAutoSpectralRcppis available. - Faster variant and AF spectra determination via
EmbedSOMwhenAutoSpectralRcppis installed. -
viridisadded as a dependency for improved colour scaling in density plots. - Support for
patchworkto allow manual faceting and combination of plots. - Spectral reference library updated with additional entries.
- Scatter-matching via k-nearest neighbours for higher precision.
- Cosine filtering of unstained samples against the fluorophore spectral profiles to reduce potential errors when the “unstained” isn’t actually completely unstained.
- Cosine filtering and kNN background matching for
get.spectra.variants()to reduce undesireable influence of autofluorescence. - Non-negative clamping of spectral profiles to prevent artefactual negative spectral values propagating into unmixing.
- Type-checking and validation added at function entry (e.g.,
get.spectral.variants()) to guard against deprecated positional arguments silently corrupting subsequent parameters, with explicit error messages. - Cell weighting is now enabled by default for the ID7000, and detection thresholds have been relaxed for this platform.
-
NAMESPACEinjection for optional dependencies (AutoSpectralRcpp,EmbedSOM) replaced withrequireNamespace()calls for a safer, more portable pattern. - Removed the
cairoandmethodspackage dependencies. - Defensive
tryCatchwrapping around plotting calls, and guards against unintended matrix-to-vector dropping. - Guards added for low cell count edge cases to prevent dimension errors.
- General function and code cleanup throughout.
Bug fixes
- Keywords issue causing files from BD instruments to occasionally emit scrambled data should now be fixed. Only whitelisted channels are preserved from the input raw FCS files.
- Fixed handling of negative autofluorescence spectra in normalization and plotting.
- Fixed hexbin rendering in N x N plots.
- Fixed a typo (
applyshould have beenlapply). - Various fixes to get
unmix.fcs()passing its test suite again.