Unmixing with Luciernaga
David Rach
University of Maryland, Baltimoredrach@som.umaryland.edu
30 October 2024
Source:vignettes/Unmixing.rmd
Unmixing.rmd
Introduction
Unmixing is a black box for many spectral flow cytometry users, you adjust gates on your single color controls, you provide full-stained samples, you unmix and then you evaluate the outputs with NxN plots. The golden rules of reference controls (1. Single Color Controls as Bright or Brighter than Full-Stain Sample; 2. Unmixing Single Color should be the same fluorophore (even better same manufacturer and lot); 3. Single Color Controls should have autofluorescence subtracted from a matching/equivalent unstained sample; 4. enough events) are useful guidepost that obviously work but few have mechanistic explanations behind why.
Building on examples from Jakob Theorell’s flowSpecs
and Christopher Hall’s flowUnmix package, we
implemented a way to take Luciernaga_QC()
outputs of
purified fluorophore signatures and unmix them using ordinal least
squares (OLS) working from GatingSet objects, and returning FCS 3.0
standard files. In combination with functional programming principles,
we have been leveraging this to understand how variations of fluorophore
signature and brightness impact the unmixing of full-stained samples. We
hope our addditive contribution enables users to push the limits of SFC
and uncover new insights, write ways to handle issues arising from
relative heterogeneity of individual immune cells unmixed with
combination outputs, and spare future graduate students having to go
write their own R package to answer space-wormhole questions.
Getting Started
This section uses the generated purified flourophore signatures
generated by Luciernaga_QC()
in the previous vignettes.
Let’s first load the required packages by calling them with library.
library(Luciernaga)
library(flowCore)
library(flowWorkspace)
library(openCyto)
library(ggcyto)
library(data.table)
library(dplyr)
library(purrr)
library(stringr)
library(ggplot2)
library(gt)
library(plotly)
library(htmltools)
Then we can find the .fcs files stored within the
Luciernaga
packages extdata folder and sort them by their
respective type
File_Location <- system.file("extdata", package = "Luciernaga")
FCS_Pattern <- ".fcs$"
FCS_Files <- list.files(path = File_Location, pattern = FCS_Pattern,
full.names = TRUE, recursive = FALSE)
head(FCS_Files[10:30], 20)
#> [1] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/21_Before.fcs"
#> [2] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/22_After.fcs"
#> [3] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/22_Before.fcs"
#> [4] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/23_After.fcs"
#> [5] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/23_Before.fcs"
#> [6] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/4BeadsUnstained(Beads).fcs"
#> [7] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CCR4_BUV615(Beads).fcs"
#> [8] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CCR4_BUV615(Cells).fcs"
#> [9] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CCR6_BV786(Beads).fcs"
#> [10] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CCR6_BV786(Cells).fcs"
#> [11] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CCR7_BV650(Beads).fcs"
#> [12] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CCR7_BV650(Cells).fcs"
#> [13] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CD107a_APC-R700(Beads).fcs"
#> [14] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CD107a_APC-R700(Cells).fcs"
#> [15] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CD127_BV421(Beads).fcs"
#> [16] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CD127_BV421(Cells).fcs"
#> [17] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CD16_APC(Beads).fcs"
#> [18] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CD16_APC(Cells).fcs"
#> [19] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CD161_BV480(Beads).fcs"
#> [20] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CD161_BV480(Cells).fcs"
UnstainedFCSFiles <- FCS_Files[grep("Unstained", FCS_Files)]
UnstainedBeads <- UnstainedFCSFiles[grep("Beads", UnstainedFCSFiles)]
UnstainedCells <- UnstainedFCSFiles[-grep("Beads", UnstainedFCSFiles)]
BeadFCSFiles <- FCS_Files[grep("Beads", FCS_Files)]
BeadSingleColors <- BeadFCSFiles[-grep("Unstained", BeadFCSFiles)]
CellSingleColorFiles <- FCS_Files[grep("Cells", FCS_Files)]
CellSingleColors <- CellSingleColorFiles[!str_detect("Unstained", CellSingleColorFiles)]
Now lets create a GatingSet for our single-color cell unmixing controls
MyCytoSet <- load_cytoset_from_fcs(CellSingleColors,
truncate_max_range = FALSE,
transform = FALSE)
MyCytoSet
#> A cytoset with 30 samples.
#>
#> column names:
#> Time, UV1-A, UV2-A, UV3-A, UV4-A, UV5-A, UV6-A, UV7-A, UV8-A, UV9-A, UV10-A, UV11-A, UV12-A, UV13-A, UV14-A, UV15-A, UV16-A, SSC-W, SSC-H, SSC-A, V1-A, V2-A, V3-A, V4-A, V5-A, V6-A, V7-A, V8-A, V9-A, V10-A, V11-A, V12-A, V13-A, V14-A, V15-A, V16-A, FSC-W, FSC-H, FSC-A, SSC-B-W, SSC-B-H, SSC-B-A, B1-A, B2-A, B3-A, B4-A, B5-A, B6-A, B7-A, B8-A, B9-A, B10-A, B11-A, B12-A, B13-A, B14-A, YG1-A, YG2-A, YG3-A, YG4-A, YG5-A, YG6-A, YG7-A, YG8-A, YG9-A, YG10-A, R1-A, R2-A, R3-A, R4-A, R5-A, R6-A, R7-A, R8-A
MyGatingSet <- GatingSet(MyCytoSet)
MyGatingSet
#> A GatingSet with 30 samples
FileLocation <- system.file("extdata", package = "Luciernaga")
MyGates <- fread(file.path(path = FileLocation, pattern = 'Gates.csv'))
gt(MyGates)
alias | pop | parent | dims | gating_method | gating_args | collapseDataForGating | groupBy | preprocessing_method | preprocessing_args |
---|---|---|---|---|---|---|---|---|---|
singletsFSC | + | root | FSC-A,FSC-H | singletGate | FALSE | NA | NA | NA | |
singletsSSC | + | singletsFSC | SSC-A,SSC-H | singletGate | FALSE | NA | NA | NA | |
singletsSSCB | + | singletsSSC | SSC-A,SSC-B-A | singletGate | FALSE | NA | NA | NA | |
nonDebris | + | singletsSSCB | FSC-A | gate_mindensity | FALSE | NA | NA | NA | |
lymphocytes | + | nonDebris | FSC-A, SSC-A | flowClust | K=2, target=c(1e5, 5e4) | FALSE | NA | NA | NA |
MyGatingTemplate <- gatingTemplate(MyGates)
gt_gating(MyGatingTemplate, MyGatingSet)
MyGatingSet[[1]]
#> Sample: CCR4_BUV615(Cells).fcs
#> GatingHierarchy with 6 gates
Now lets create a GatingSet for our unstained cell unmixing controls
MyUnstainedCytoSet <- load_cytoset_from_fcs(UnstainedCells,
truncate_max_range = FALSE,
transform = FALSE)
MyUnstainedCytoSet
#> A cytoset with 18 samples.
#>
#> column names:
#> Time, UV1-A, UV2-A, UV3-A, UV4-A, UV5-A, UV6-A, UV7-A, UV8-A, UV9-A, UV10-A, UV11-A, UV12-A, UV13-A, UV14-A, UV15-A, UV16-A, SSC-W, SSC-H, SSC-A, V1-A, V2-A, V3-A, V4-A, V5-A, V6-A, V7-A, V8-A, V9-A, V10-A, V11-A, V12-A, V13-A, V14-A, V15-A, V16-A, FSC-W, FSC-H, FSC-A, SSC-B-W, SSC-B-H, SSC-B-A, B1-A, B2-A, B3-A, B4-A, B5-A, B6-A, B7-A, B8-A, B9-A, B10-A, B11-A, B12-A, B13-A, B14-A, YG1-A, YG2-A, YG3-A, YG4-A, YG5-A, YG6-A, YG7-A, YG8-A, YG9-A, YG10-A, R1-A, R2-A, R3-A, R4-A, R5-A, R6-A, R7-A, R8-A
MyUnstainedGatingSet <- GatingSet(MyUnstainedCytoSet)
MyUnstainedGatingSet
#> A GatingSet with 18 samples
FileLocation <- system.file("extdata", package = "Luciernaga")
MyGates <- fread(file.path(path = FileLocation, pattern = 'Gates.csv'))
gt(MyGates)
alias | pop | parent | dims | gating_method | gating_args | collapseDataForGating | groupBy | preprocessing_method | preprocessing_args |
---|---|---|---|---|---|---|---|---|---|
singletsFSC | + | root | FSC-A,FSC-H | singletGate | FALSE | NA | NA | NA | |
singletsSSC | + | singletsFSC | SSC-A,SSC-H | singletGate | FALSE | NA | NA | NA | |
singletsSSCB | + | singletsSSC | SSC-A,SSC-B-A | singletGate | FALSE | NA | NA | NA | |
nonDebris | + | singletsSSCB | FSC-A | gate_mindensity | FALSE | NA | NA | NA | |
lymphocytes | + | nonDebris | FSC-A, SSC-A | flowClust | K=2, target=c(1e5, 5e4) | FALSE | NA | NA | NA |
MyGatingTemplate <- gatingTemplate(MyGates)
gt_gating(MyGatingTemplate, MyUnstainedGatingSet)
MyUnstainedGatingSet[[1]]
#> Sample: INF071_Ctrl_Unstained.fcs
#> GatingHierarchy with 6 gates
Generate Luciernaga_QC Outputs
Now that the GatingSets are re-established, let’s continue where the
last vignette left off by processing all the fcs files with
Luciernaga_QC
to characterize the fluorescent signatures
within.
Let’s first provision the AFOverlap csv to handle conflicts.
FileLocation <- system.file("extdata", package = "Luciernaga")
pattern = "AutofluorescentOverlaps.csv"
AFOverlap <- list.files(path=FileLocation, pattern=pattern,
full.names = TRUE)
AFOverlap_CSV <- read.csv(AFOverlap, check.names = FALSE)
AFOverlap_CSV
#> Fluorophore MainDetector
#> 1 Unstained UV7-A,V7-A,V3-A,V5-A
#> 2 BUV496 UV7-A
#> 3 BV480 V5-A
#> 4 BV510 V7-A
#> 5 BV570 V8-A
And next generate a CellAF unstained signature that can be used when these fluorophore-autofluorescence overlap files are encountered:
# pData(MyUnstainedGatingSet[1])
removestrings <- c(".fcs")
TheCellAF <- map(.x=MyUnstainedGatingSet[1], .f=Luciernaga_QC, subsets="lymphocytes",
removestrings=removestrings, sample.name="GUID",
unmixingcontroltype = "cells", Unstained = TRUE,
ratiopopcutoff = 0.001, Verbose = FALSE,
AFOverlap = AFOverlap, stats = "median",
ExportType = "data", SignatureReturnNow = TRUE,
outpath = TemporaryFolder, Increments=0.1,
SecondaryPeaks=2, experiment = "FirstExperiment",
condition = "ILTPanel", SCData="subtracted",
NegativeType="default")
#> Normalizing Data for Signature Comparison
TheCellAF <- TheCellAF[[1]] #Removes list caused by map
gt(TheCellAF)
UV1-A | UV2-A | UV3-A | UV4-A | UV5-A | UV6-A | UV7-A | UV8-A | UV9-A | UV10-A | UV11-A | UV12-A | UV13-A | UV14-A | UV15-A | UV16-A | V1-A | V2-A | V3-A | V4-A | V5-A | V6-A | V7-A | V8-A | V9-A | V10-A | V11-A | V12-A | V13-A | V14-A | V15-A | V16-A | B1-A | B2-A | B3-A | B4-A | B5-A | B6-A | B7-A | B8-A | B9-A | B10-A | B11-A | B12-A | B13-A | B14-A | YG1-A | YG2-A | YG3-A | YG4-A | YG5-A | YG6-A | YG7-A | YG8-A | YG9-A | YG10-A | R1-A | R2-A | R3-A | R4-A | R5-A | R6-A | R7-A | R8-A |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
359.38 | 612.9988 | 437.0275 | 559.4488 | 779.7476 | 1246.153 | 2423.138 | 1793.776 | 1682.139 | 625.345 | 402.5919 | 251.5363 | 198.8788 | 255.1806 | 175.5994 | 168.3106 | 379.9125 | 1167.719 | 1815.069 | 2080.031 | 3214.613 | 3112.45 | 4226.681 | 3096.637 | 2104.025 | 2316.6 | 1251.25 | 704.825 | 632.8438 | 574.3375 | 518.1688 | 295.5562 | 1192.289 | 1367.454 | 1904.727 | 1289.431 | 1090.77 | 870.5431 | 619.2231 | 459.5087 | 477.0831 | 316.0812 | 239.0244 | 221.5788 | 163.0619 | 210.1844 | 516.2194 | 394.8131 | 402.2363 | 388.5 | 308.8575 | 310.3838 | 380.73 | 196.4006 | 195.2213 | 131.2575 | 189.9812 | 239.6306 | 253.4731 | 285.1131 | 152.1969 | 142.1681 | 129.8794 | 89.97625 |
Now let’s use Luciernaga_QC()
with ExportType = “fcs” to
export the data as individual .fcs files, and set Brightness = TRUE to
save .csv files that can be used for Luciernaga_Tree()
. For
this vignette, we will be saving the .fcs files to a temporary folder.
On your own workstation, save the outputs to a folder where you can
retrieve them later by providing a file.path to the outpath
argument.
Let’s start by processing the single-color unmixing controls.
#pData(MyGatingSet)
StorageLocation <- file.path(tempdir(), "LuciernagaOutputs")
if (!dir.exists(StorageLocation)) {
dir.create(StorageLocation)
}
SingleColor_Data <- map(.x=MyGatingSet, .f=Luciernaga_QC, subsets="nonDebris",
removestrings=removestrings, sample.name="GUID",
unmixingcontroltype = "cells", Unstained = FALSE,
ratiopopcutoff = 0.001, Verbose = FALSE,
AFOverlap = AFOverlap, stats = "median",
ExportType = "fcs", Brightness=TRUE, SignatureReturnNow = FALSE,
outpath = StorageLocation, Increments=0.1,
SecondaryPeaks=2, experiment = "FirstExperiment",
condition = "ILTPanel", Subtraction = "Internal",
CellAF=TheCellAF, SCData="subtracted",
NegativeType="default", minimalfcscutoff=0.01)
#> No second peak
#> No second peak
#> No second peak
#> No second peak
#> Only a single detector present. If this was not an autofluorescence overlap
#> fluourophore, it would suggest there was no antibody staining, or everything
#> was overstained. Please investigate further.
#> No second peak
#> No second peak
#> No second peak
#> No second peak
#> No second peak
#> No second peak
TheLuciernagaOutputs_FCS <- list.files(StorageLocation, pattern="fcs", full.names = TRUE)
head(TheLuciernagaOutputs_FCS, 4)
#> [1] "C:\\Users\\12692\\AppData\\Local\\Temp\\Rtmp0AUE9A/LuciernagaOutputs/CCR4_BUV615(Cells)_UV1010YG300V1000.fcs"
#> [2] "C:\\Users\\12692\\AppData\\Local\\Temp\\Rtmp0AUE9A/LuciernagaOutputs/CCR4_BUV615(Cells)_UV1010YG307V1000.fcs"
#> [3] "C:\\Users\\12692\\AppData\\Local\\Temp\\Rtmp0AUE9A/LuciernagaOutputs/CCR4_BUV615(Cells)_UV1010YG307V1003.fcs"
#> [4] "C:\\Users\\12692\\AppData\\Local\\Temp\\Rtmp0AUE9A/LuciernagaOutputs/CCR4_BUV615(Cells)_UV1010YG307V1004.fcs"
And let’s also process an unstained unmixing control specimen also to characterize autofluorescence that is present.
#pData(MyUnstainedGatingSet)
Unstained_Data <- map(.x=MyUnstainedGatingSet[1], .f=Luciernaga_QC, subsets="nonDebris",
removestrings=removestrings, sample.name="GUID",
unmixingcontroltype = "cells", Unstained = TRUE,
ratiopopcutoff = 0.001, Verbose = FALSE,
AFOverlap = AFOverlap, stats = "median",
ExportType = "fcs", Brightness=TRUE, SignatureReturnNow = FALSE,
outpath = StorageLocation, Increments=0.1,
SecondaryPeaks=2, experiment = "FirstExperiment",
condition = "ILTPanel", Subtraction = "Internal",
CellAF=TheCellAF, SCData="subtracted",
NegativeType="default", minimalfcscutoff=0.01)
Luciernaga_Tree
We generate a lot of clusters with Luciernaga_QC()
. We
can visualize them using the report and plotting functions described in
the previous vignette, but selecting individual candidate output .fcs
for use in unmixing can be tiresome and confusing.
Luciernaga_Tree()
is our initial attempt to reduce the
burden, by instituting a decision tree to help filter the many outputs
and return likely candidates that will work for unmixing. It relies on
the Luciernaga_QC()
Brightness=TRUE .csv outputs in making
this decision.
We want to be upfront and say this is developmental. We have recently created the tools to allow us to query how fluorophore brightness, signature, and relative abundance impact the unmixing of full-stained samples. We have not had the time to delve into the outcomes at the depth we would like to come up with a grand unified theory of perfect unmixing. That is on my to-do-list as a postdoc/industry/whatever (hire me if this interest you or you want to avoid me working for your competitors). For the time, it works well enough, but with occasional bugs in the final unmixing. We highly encourage your feedback and tinkering with the decision trees step methodology in order to achieve more consistent results. For now, the process works as follows (detailed explanation logic).
With that background out of the way, let’s continue.
ReferencePath <- system.file("extdata", package = "Luciernaga")
PanelPath <- file.path(ReferencePath, "UnmixingPanel.csv")
UnmixingPanel <- read.csv(PanelPath, check.names=FALSE)
MoveThese <- Luciernaga_Tree(BrightnessFilePath = StorageLocation, PanelPath = PanelPath)
gt(head(MoveThese, 5))
sample | Cluster | Decision | Brightness | Detector1 | Detector1Value | Detector2 | Detector2Value | Detector3 | Detector3Value | Detector1Raw | Detector2Raw | Detector3Raw | Count | Ratio | Time | UV1 | UV2 | UV3 | UV4 | UV5 | UV6 | UV7 | UV8 | UV9 | UV10 | UV11 | UV12 | UV13 | UV14 | UV15 | UV16 | SSC-W | SSC-H | SSC | V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 | V9 | V10 | V11 | V12 | V13 | V14 | V15 | V16 | FSC-W | FSC-H | FSC | SSC-B-W | SSC-B-H | SSC-B | B1 | B2 | B3 | B4 | B5 | B6 | B7 | B8 | B9 | B10 | B11 | B12 | B13 | B14 | YG1 | YG2 | YG3 | YG4 | YG5 | YG6 | YG7 | YG8 | YG9 | YG10 | R1 | R2 | R3 | R4 | R5 | R6 | R7 | R8 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
CD62L_BUV395(Cells) | UV2_10-V7_04-B3_02 | Fourth Level | 16 | UV2 | 10 | V7 | 4 | B3 | 2 | 16802.65 | 5682.600 | 2461.571 | 100 | 0.02515723 | 334183 | 4784.4324 | 16802.6517 | 8266.559 | 6514.1719 | 5815.1582 | 6467.6503 | 5803.6301 | 3065.7003 | 2504.0204 | 793.0607 | 527.2444 | 239.1900 | 220.3731 | 276.7122 | 225.5050 | 47.0050 | 753165.5 | 2305322 | 2857364.8 | 538.10629 | 1925.58435 | 2992.4813 | 3250.5686 | 4505.0500 | 4137.3751 | 5682.5996 | 4346.3407 | 2877.9094 | 3246.4780 | 1820.0875 | 1008.9063 | 815.13440 | 821.2188 | 570.693726 | 341.1375 | 702061.5 | 1752840 | 2062621 | 736991.8 | 1227946.5 | 1501699.9 | 1469.90649 | 1719.32745 | 2461.57123 | 1833.4966 | 1463.27600 | 1197.27835 | 851.6490 | 604.5134 | 619.3197 | 342.08875 | 400.73438 | 240.247498 | 160.808731 | 204.3262 | 856.78128 | 586.91249 | 619.9004 | 780.5728 | 554.4797 | 577.0959 | 670.6829 | 309.79408 | 175.13719 | 121.5797 | 736.05373 | 1107.39996 | 949.3766 | 842.2031 | 524.92029 | 430.989 | 352.98373 | 229.21343 |
CD8_BUV496(Cells) | UV7_10-V6_02 | Second Level | 12 | UV7 | 10 | V6 | 2 | NA | NA | 70514.98 | 9989.169 | NA | 356 | 0.19614325 | 215615 | 643.8644 | 2160.2963 | 1777.116 | 1547.4463 | 2121.7701 | 12550.8562 | 70514.9775 | 37302.5232 | 17475.8574 | 4163.3640 | 1116.9266 | 494.4078 | 309.6975 | 324.9072 | 165.4100 | 149.3450 | 714194.6 | 1264984 | 1482504.8 | 0.00000 | 0.00000 | 437.3188 | 4245.9658 | 13527.0786 | 9989.1694 | 9940.2881 | 3753.2686 | 1716.3438 | 1295.8689 | 199.3064 | 62.5968 | 70.64062 | 0.0000 | 9.831238 | 0.0000 | 687766.3 | 1457523 | 1650837 | 696512.3 | 610634.0 | 695478.2 | 4402.12341 | 2587.23120 | 1946.73193 | 382.9025 | 187.13818 | 35.05212 | 0.0000 | 0.0000 | 0.0000 | 0.00000 | 0.00000 | 0.000000 | 1.416245 | 0.0000 | 0.00000 | 0.00000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.00000 | 0.00000 | 0.0000 | 0.00000 | 0.00000 | 0.0000 | 0.0000 | 0.00000 | 0.000 | 0.00000 | 0.00000 |
CD69_BUV563(Cells) | UV9_10-YG1_05-B4_02 | Fourth Level | 17 | UV9 | 10 | YG1 | 5 | B4 | 2 | 58291.45 | 24073.820 | 10734.081 | 2557 | 0.48483125 | 290718 | 450.6753 | 1821.7785 | 1427.554 | 1217.5560 | 1194.4254 | 1296.5423 | 1061.2197 | 19671.4825 | 58291.4473 | 14812.1540 | 3321.2531 | 1374.3013 | 721.0656 | 485.2597 | 286.5669 | 113.9425 | 676148.9 | 814268 | 918510.8 | 0.00000 | 0.00000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 636.5564 | 3010.4248 | 1032.5907 | 732.8405 | 0.0000 | 0.0000 | 0.00000 | 0.0000 | 0.000000 | 0.0000 | 665055.9 | 1180244 | 1308017 | 664419.1 | 391099.0 | 433493.0 | 0.00000 | 0.00000 | 5128.04797 | 10734.0806 | 5463.21667 | 3337.10327 | 915.7665 | 527.0060 | 392.0116 | 110.88593 | 48.66751 | 9.205612 | 0.000000 | 0.0000 | 24073.81958 | 11266.91614 | 6576.4381 | 1813.6359 | 964.4513 | 675.1575 | 461.5172 | 62.57625 | 21.50624 | 0.0000 | 0.00000 | 0.00000 | 0.0000 | 0.0000 | 0.00000 | 0.000 | 0.00000 | 0.00000 |
CCR4_BUV615(Cells) | UV10_10-YG3_09-V10_03 | Second Level | 22 | UV10 | 10 | YG3 | 9 | V10 | 3 | 11788.22 | 10077.725 | 2985.744 | 105 | 0.28301887 | 301599 | 163.4763 | 465.6991 | 296.905 | 335.6916 | 357.8181 | 443.3494 | 567.5186 | 448.5556 | 2767.7170 | 11788.2153 | 4934.8184 | 2550.1329 | 1411.9722 | 1318.7060 | 816.0426 | 357.2604 | 691204.0 | 942409 | 1078212.5 | 65.96564 | 171.42816 | 130.6594 | 138.1533 | 149.7719 | 145.0282 | 212.0938 | 285.2094 | 989.3125 | 2985.7437 | 947.3751 | 478.2250 | 262.24692 | 148.8438 | 110.893768 | 0.0000 | 670592.4 | 1333099 | 1482412 | 677919.3 | 432542.0 | 491643.7 | 0.00000 | 15.99713 | 93.40814 | 0.0000 | 402.24719 | 758.11221 | 357.5709 | 185.7218 | 245.3975 | 75.89815 | 21.72657 | 1.351883 | 13.100319 | 0.0000 | 847.51971 | 4367.43384 | 10077.7245 | 4452.3139 | 3342.9385 | 2586.9591 | 2417.1986 | 826.77660 | 584.55374 | 250.3744 | 63.52719 | 48.09562 | 102.7594 | 0.0000 | 16.03188 | 0.000 | 14.93718 | 12.46531 |
VD2_BUV661(Cells) | UV11_10-R2_09-YG5_04 | Fourth Level | 23 | UV11 | 10 | R2 | 9 | YG5 | 4 | 86813.77 | 70225.652 | 27538.511 | 162 | 0.43665768 | 273109 | 419.2147 | 1979.3049 | 1661.798 | 1488.8387 | 1489.6198 | 2034.1936 | 2082.1655 | 1109.2660 | 896.0701 | 4066.1930 | 86813.7747 | 40145.4697 | 30780.3556 | 25282.2200 | 13378.0181 | 8205.7942 | 676304.0 | 1042726 | 1192782.1 | 0.00000 | 77.61871 | 102.3344 | 189.4062 | 265.0658 | 238.7688 | 360.1470 | 362.3813 | 290.2969 | 1423.9502 | 23883.7852 | 10718.9844 | 8158.66602 | 5113.2468 | 3031.771851 | 1253.5188 | 668752.4 | 1442295 | 1588795 | 666351.9 | 469419.5 | 528043.8 | 23.56128 | 21.75873 | 41.16785 | 163.3515 | 72.22876 | 184.69186 | 3418.9240 | 2455.4234 | 1950.8199 | 1238.99338 | 788.59373 | 503.219345 | 347.753754 | 289.6231 | 41.93719 | 99.20624 | 1108.7166 | 39621.1736 | 27538.5113 | 18824.3518 | 21832.0009 | 7933.17007 | 4608.65071 | 2325.3459 | 68384.88156 | 70225.65219 | 52687.7684 | 37440.7836 | 26223.80379 | 14398.319 | 11817.25746 | 5413.54745 |
By scrolling through the returned selections, we can screen based on
our knowledge of the panel and decide if the outcomes seem reasonable.
We will also verify that these decisions were correct before we reach
the unmixing process by visualizing vs. reference signatures in
Luciernaga_SingleColors()
. In the case that the wrong file
output was selected, it is much easier to remove and replace one .fcs
file than 30.
Luciernaga_Move
Once Luciernaga_Tree()
has identified the
Luciernaga_QC()
output .fcs files that will likely produce
the best unmixing outcome, it would be absolutely brutal having to track
down within a folder of hundreds of .fcs files with some repetition of
CCR4BUV615_UV6_10-V7_08-B3_04 nomenclature (believe me, I did so
initially). Luciernaga_Move()
takes the
Luciernaga_Tree()
list of ideal candidates, and copies
these .fcs files to a designated folder, saving you the hassle, and
allowing you to simply point at that folder for use in the functions
mentioned below.
Continuing from where we left off with Luciernaga_Tree()
above, for this example, we will create a different temporary folder
were we will store the selected .fcs files for later use in the
unmixing.
SortedStorageLocation <- file.path(tempdir(), "LuciernagaSelected")
if (!dir.exists(SortedStorageLocation)) {
dir.create(SortedStorageLocation)
}
UnmixingPanel <- read.csv(PanelPath, check.names=FALSE)
TheseFluorophores <- UnmixingPanel %>% pull(Fluorophore)
walk(.x=TheseFluorophores, .f=Luciernaga_Move, data=MoveThese, input=StorageLocation, output=SortedStorageLocation)
MovedFiles <- list.files(SortedStorageLocation, pattern="fcs", full.names=TRUE)
length(MovedFiles)
#> [1] 30
With these steps completed, we are now ready to proceed to the steps to validate our choice in unmixing controls.
Luciernaga_LinearSlices
We had previously showcased Luciernaga_LinearSlices()
ability to take an .fcs file, and visualize variation in the signature
based on the quantile splits for the MFI brightness. What we saw for APC
CD16 is replicated below:
#pData(MyGatingSet)
APC_Example <- subset(MyGatingSet, str_detect(name, "CD16_"))
RawSlices <- Luciernaga_LinearSlices(x=APC_Example[1], subset="lymphocytes",
sample.name="GUID", removestrings=removestrings,
stats="median", returntype="raw",
probsratio=0.1, output="plot", desiredAF="R1-A")
plotly::ggplotly(RawSlices)
#pData(MyGatingSet[6])
NormalizedSlices <- Luciernaga_LinearSlices(x=APC_Example[1], subset="lymphocytes",
sample.name="GUID", removestrings=removestrings,
stats="median", returntype="normalized",
probsratio=0.1, output="plot", desiredAF="R1-A")
plotly::ggplotly(NormalizedSlices)
For today, we highlight Luciernaga_LinearSlices()
ability to do this also with the Luciernaga_QC()
outputs.
MovedFiles <- list.files(SortedStorageLocation, pattern="fcs", full.names=TRUE)
Selected_CS <- load_cytoset_from_fcs(MovedFiles, truncate_max_range = FALSE, transform = FALSE)
Selected_GS <- GatingSet(Selected_CS)
pData(Selected_GS)
#> name
#> CCR4_BUV615(Cells)_UV1010YG309V1003.fcs CCR4_BUV615(Cells)_UV1010YG309V1003.fcs
#> CCR6_BV786(Cells)_V1510UV1502.fcs CCR6_BV786(Cells)_V1510UV1502.fcs
#> CCR7_BV650(Cells)_V1110YG502R202.fcs CCR7_BV650(Cells)_V1110YG502R202.fcs
#> CD107a_APC-R700(Cells)_R110R210YG504.fcs CD107a_APC-R700(Cells)_R110R210YG504.fcs
#> CD127_BV421(Cells)_V110V210UV701.fcs CD127_BV421(Cells)_V110V210UV701.fcs
#> CD16_APC(Cells)_R110R209YG406.fcs CD16_APC(Cells)_R110R209YG406.fcs
#> CD161_BV480(Cells)_V510UV703.fcs CD161_BV480(Cells)_V510UV703.fcs
#> CD25_PE-Cy5(Cells)_YG510B807R203.fcs CD25_PE-Cy5(Cells)_YG510B807R203.fcs
#> CD26_PerCP-Cy5.5(Cells)_B910YG606V1306.fcs CD26_PerCP-Cy5.5(Cells)_B910YG606V1306.fcs
#> CD27_APC-Fire750(Cells)_R710YG903V1502.fcs CD27_APC-Fire750(Cells)_R710YG903V1502.fcs
#> CD3_AlexaFluor488(Cells)_B210.fcs CD3_AlexaFluor488(Cells)_B210.fcs
#> CD3_AlexaFluor647(Cells)_R210YG502.fcs CD3_AlexaFluor647(Cells)_R210YG502.fcs
#> CD3_SparkBlue550(Cells)_B310V703.fcs CD3_SparkBlue550(Cells)_B310V703.fcs
#> CD38_APC-Fire810(Cells)_R810YG1003.fcs CD38_APC-Fire810(Cells)_R810YG1003.fcs
#> CD4_BUV805(Cells)_UV1610R802.fcs CD4_BUV805(Cells)_UV1610R802.fcs
#> CD45RA_BV510(Cells)_V710UV804.fcs CD45RA_BV510(Cells)_V710UV804.fcs
#> CD56_BV605(Cells)_V1010YG304UV1003.fcs CD56_BV605(Cells)_V1010YG304UV1003.fcs
#> CD62L_BUV395(Cells)_UV210V704B302.fcs CD62L_BUV395(Cells)_UV210V704B302.fcs
#> CD69_BUV563(Cells)_UV910YG105B402.fcs CD69_BUV563(Cells)_UV910YG105B402.fcs
#> CD7_BV711(Cells)_V1310R403UV1402.fcs CD7_BV711(Cells)_V1310R403UV1402.fcs
#> CD8_BUV496(Cells)_UV710V602.fcs CD8_BUV496(Cells)_UV710V602.fcs
#> CXCR3_BUV737(Cells)_UV1410R506V704.fcs CXCR3_BUV737(Cells)_UV1410R506V704.fcs
#> Dump_CD19_PacificBlue(Cells)_V810V710UV806.fcs Dump_CD19_PacificBlue(Cells)_V810V710UV806.fcs
#> IFNg_BV750(Cells)_V1410V1509UV1502.fcs IFNg_BV750(Cells)_V1410V1509UV1502.fcs
#> INF071_Ctrl_Unstained_V710UV804B304.fcs INF071_Ctrl_Unstained_V710UV804B304.fcs
#> NKG2D_PE(Cells)_YG110B407V802.fcs NKG2D_PE(Cells)_YG110B407V802.fcs
#> PD1_PE-Vio770(Cells)_YG910B1306V702.fcs PD1_PE-Vio770(Cells)_YG910B1306V702.fcs
#> TNFa_PE-Dazzle594(Cells)_YG310B607V1002.fcs TNFa_PE-Dazzle594(Cells)_YG310B607V1002.fcs
#> VD2_BUV661(Cells)_UV1110R209YG504.fcs VD2_BUV661(Cells)_UV1110R209YG504.fcs
#> Viability_ZombieNIR(Cells)_R710R610B1303.fcs Viability_ZombieNIR(Cells)_R710R610B1303.fcs
ThePlots <- map(.x=Selected_GS, .f=Luciernaga_LinearSlices, subset="root", removestrings=".fcs",
sample.name="GUID", stats="median", returntype="normalized", output="plot")
plotly::ggplotly(ThePlots[[1]])
As we can see, with the exception of cells below 30 percentile in
brightness, most of the variation in signature we saw in the original
file, and that the sorting within Luciernaga_QC()
appears
to have sorted cells of similar signature regardless of brightness.
By passing the generated plots to Utility_Patchwork()
,
we can set returntype=“pdf” or “patchwork” to generate a report for all
fluorophores.
PatchworkObjects <- Utility_Patchwork(ThePlots, filename = "LinearSlices", outfolder=ReferencePath, returntype = "patchwork")
PatchworkObjects[1]
#> $`1`
Luciernaga_SingleColors
The main purpose of Luciernaga_SingleColors()
is to
generate a reference matrix for use in unmixing full-stained samples. It
additionally provides a mechanism by which we can visualize the
signatures we plan on using and compare them to the reference signatures
stored within Luciernaga
. This allows us to screen out
potential issues in the single-color reference matrix before we proceed
to unmix the full-stained specimens.
To begin, we need to generate either a .csv file or a data.frame for
each of the fluorophores present, and specify a cutoff point for each,
dictated by our observations from what we saw with
Luciernaga_LinearSlices()
. For this example, we will do
this in R and set the intervals from 0.4 to 1.0 across the board. If you
want to fine-tune things further, it would be easier to save the output
as a .csv file, modify it, and then return it to R.
UnmixingPanel <- read.csv(PanelPath, check.names=FALSE)
ThePanelCuts <- UnmixingPanel %>% select(-Detector) %>% mutate(From=0.3) %>% mutate(To=1)
head(ThePanelCuts, 5)
#> Fluorophore From To
#> 1 BUV395-A 0.3 1
#> 2 BUV496-A 0.3 1
#> 3 BUV563-A 0.3 1
#> 4 BUV615-A 0.3 1
#> 5 BUV661-A 0.3 1
#write.csv(ThePanelCuts, path="SaveHere.csv", row.names=FALSE)
An important thing to ensure is that we correctly identify each fluorophore and ligand at this step, to ensure names are correct in the unmixed full-stained .fcs file. In this case, we are using the keyword “TUBENAME” to identify between the .fcs files. This is what the original name looks like:
keyword(Selected_GS[1], "TUBENAME")
#> TUBENAME
#> 1 DR_CCR4 BUV615 (Cells)
Luciernaga_SingleColors()
will automatically clean up
any portion of the name that has “(Cells)” or “(Beads)” present in it.
However, that would leave the final name as “DR_CCR4 BUV615” which would
be converted into Fluorophore = BUV615, Ligand = DR_CCR4. To clean this
up, we will remove the authors initials (“DR_”) by providing them as
part of a list to the remove strings argument.
#pData(Selected_GS)
removestrings=c("DR_", ".fcs")
SCs <- map(.x=Selected_GS[1], .f=Luciernaga_SingleColors, sample.name="TUBENAME",
removestrings=removestrings, subset="root", PanelCuts=ThePanelCuts,
stats="median", Verbose=TRUE, SignatureView=TRUE, returntype = "plots")
#> After removestrings cleanup the name is CCR4 BUV615
#> The Fluorophore is BUV615 and the ligand is CCR4
In the case above, we set the returntype = “plot” to visualize the
outcome compared to the stored Reference Signatures within
Luciernaga
. Let’s see what these look like:
plotly::ggplotly(SCs[[1]])
As you can tell, the provided signature originating from our output
.fcs file closely resembles that of the reference signature. We can
repeat this for all the fluorophores and using
Utility_Patchwork()
, set returntype = “pdf” and examine all
fluorophores to spot any issues. For this example, I will set it the
argument to “patchwork” to visualize.
SCs <- map(.x=Selected_GS, .f=Luciernaga_SingleColors, sample.name="TUBENAME",
removestrings=removestrings, subset="root", PanelCuts=ThePanelCuts,
stats="median", Verbose=TRUE, SignatureView=TRUE, returntype = "plots")
TheView <- Utility_Patchwork(x=SCs, filename="ReferenceMatches",
outfolder = ReferencePath, returntype = "patchwork")
TheView[3]
#> $`3`
In this particular case, we can see that while most generated signatures aligned with their references, the .fcs files we are using for BUV737 and PacificBlue deviate substantially and are likely to impact the final unmixing. Within our workflow, we would follow up by removing the current output .fcs from the Selected Folder, and replace it with another variant.
While this highlights the visualizing portion of
Luciernaga_SingleColors()
lets go ahead and generate the
reference matrix by changing returntype = “data”
SC_Reference <- map(.x=Selected_GS, .f=Luciernaga_SingleColors, sample.name="TUBENAME",
removestrings=removestrings, subset="root", PanelCuts=ThePanelCuts,
stats="median", Verbose=FALSE, SignatureView=FALSE, returntype = "data") %>%
bind_rows()
head(SC_Reference, 4)
#> Fluorophore Ligand UV1-A UV2-A UV3-A UV4-A UV5-A
#> 1 BUV615 CCR4 186.1606 641.521606 390.39441 452.4603 452.2001
#> 2 BV786 CCR6 53.8475 7.325958 59.87189 0.0000 0.0000
#> 3 BV650 CCR7 593.7357 1046.530701 908.34186 1106.6628 1231.2781
#> 4 APC-R700 CD107a 1279.4733 3029.070801 3013.52637 3407.7139 4471.2764
#> UV6-A UV7-A UV8-A UV9-A UV10-A UV11-A UV12-A
#> 1 557.8869 802.7666 660.1525 3567.620 14820.930 6095.664 3081.617
#> 2 0.0000 0.0000 0.0000 0.000 0.000 0.000 0.000
#> 3 1933.8989 3245.7625 2545.9304 2495.542 2563.000 10016.305 4557.254
#> 4 7032.0078 11404.7373 7828.4893 6751.242 2659.576 12536.651 5248.198
#> UV13-A UV14-A UV15-A UV16-A V1-A V2-A V3-A
#> 1 1898.16150 1681.135 984.2044 508.316 19.35312 193.6343 141.0407
#> 2 10.70999 1352.324 5023.2507 4109.182 1641.57812 1643.1250 1479.6719
#> 3 3401.24329 2766.304 1604.9755 1068.918 4004.13745 5897.5815 6977.1631
#> 4 6263.04443 6465.568 3412.2507 2374.199 2380.12524 7611.5874 11858.7568
#> V4-A V5-A V6-A V7-A V8-A V9-A V10-A
#> 1 138.1533 203.8094 145.0282 238.7686 382.6969 1327.975 3955.188
#> 2 641.8844 243.9250 106.8031 0.0000 0.0000 0.000 0.000
#> 3 5040.4067 5719.1064 5486.0781 7418.2969 5893.8003 5118.094 20654.357
#> 4 12383.5254 17391.3438 16034.9072 21225.4629 15140.5371 9949.020 11313.088
#> V11-A V12-A V13-A V14-A V15-A V16-A B1-A
#> 1 1349.906 634.4249 358.0844 217.250 161.4937 0.000 2.542908
#> 2 0.000 0.0000 395.0031 7721.519 32902.4453 17867.919 0.000000
#> 3 58440.148 26664.5850 19260.8643 11865.803 7511.5566 3044.388 1887.603638
#> 4 36744.539 15177.9385 18939.9375 13898.775 8024.9131 3463.350 5915.804688
#> B2-A B3-A B4-A B5-A B6-A B7-A B8-A
#> 1 17.47784 83.17242 0.000 526.4265 960.6359 424.8428 264.1306
#> 2 0.00000 0.00000 0.000 0.0000 0.0000 0.0000 0.0000
#> 3 2249.52002 3330.79468 2431.186 1948.3414 1809.3558 1888.2152 1424.3934
#> 4 6264.07324 8485.97656 5455.523 4460.5435 3486.8074 11263.1777 7628.5659
#> B9-A B10-A B11-A B12-A B13-A B14-A YG1-A
#> 1 331.4025 82.72188 51.91843 24.26936 1.062187 7.885941 1144.792
#> 2 0.0000 0.00000 59.73999 231.42810 592.089050 648.224030 0.000
#> 3 1301.8878 809.12939 600.07156 424.45654 350.554016 341.123138 1052.800
#> 4 6682.5752 5642.40430 4194.80371 2879.23633 1801.791870 1890.049805 1597.429
#> YG2-A YG3-A YG4-A YG5-A YG6-A YG7-A YG8-A
#> 1 5.777896e+03 12523.749 5701.758 4401.185 3108.451 2949.235 1086.6554
#> 2 3.468323e-02 0.000 0.000 0.000 0.000 0.000 165.0431
#> 3 9.510966e+02 2228.429 11140.862 7616.473 5853.169 6489.719 2278.3098
#> 4 1.466449e+03 2041.359 70883.148 47194.148 30333.732 57502.301 24562.9121
#> YG9-A YG10-A R1-A R2-A R3-A R4-A
#> 1 699.6469 335.9831 151.7378 41.5275 1.197094e+02 22.91782
#> 2 736.0688 612.6853 0.0000 0.0000 1.765671e-01 22.84718
#> 3 1590.9769 789.6956 6911.8921 6685.9980 5.755832e+03 3799.20117
#> 4 13512.3770 7128.1426 142743.1562 131535.3906 9.798209e+04 108904.66406
#> R5-A R6-A R7-A R8-A
#> 1 52.05063 0.0000 66.28156 2.224689
#> 2 197.25562 954.9206 2531.72974 1467.375549
#> 3 2560.01501 1486.2678 1330.36316 642.263794
#> 4 91088.17188 48160.9531 39263.82812 18772.619141
While we are at it, we might as well identify how far the cosine difference for the trouble Pacific Blue Fluorophore is before we go and correct it:
PacificBlue <- SC_Reference %>% select(-Ligand) %>% rename(Sample=Fluorophore)
Results <- QC_WhatsThis(x="Pacific Blue", data=PacificBlue, NumberHits=10,
returnPlots = TRUE)
#> Normalizing Data for Signature Comparison
Results[[1]]
#> Fluorophore ID_Pacific Blue
#> 1 BV510 0.88
#> 2 LIVE DEAD Aqua 0.84
#> 3 VioGreen 0.82
#> 4 Krome Orange 0.80
#> 5 OC515 0.80
#> 6 Zombie Aqua 0.80
#> 7 Monochlorobimane 0.79
#> 8 Amethyst Orange 0.78
#> 9 BV480 0.78
#> 10 cFluor V547 0.78
plotly::ggplotly(Results[[2]])
As you can tell, the fluorophore more closely resembles BV510 with no Pacific Blue appearing in the list of hits. This suggest that the returned fluorescent signature in the .fcs file is mainly autofluorescence, and should not be used.
Back on topic, once we have corrected the Selected Folder, rerun
Luciernaga_SingleColors()
and are satisfied with out
results, we should go ahead and save the results data.frame elsewhere
for further reference, or that they can be so edited to correct for any
typos or format issues that may have been missed before creating unmixed
.fcs files.
Luciernaga_Unmix
Luciernaga_Unmix()
is the unmixing function implemented
within the Luciernaga
package. What mainly distinguishes it
from other R package implementations of ordinary least squares unmixing
is it works at the GatingSet level in terms of infrastructure (reducing
active memory use) and is set up in such a way to allow us to rapidly
iterate/modify/change the inputs to subsequently evaluate the unmixed
full-stained .fcs files for the impacts that those decisions had on the
unmixing. We have put some effort into ensuring that the subsequent
unmixed files are compatible with various software typically used by
those who prefer to use GUI for their flow data. This involved changes
done within the newly produced .fcs files exprs, parameters and
description folder, it’s possible we may have missed something, so if
you encounter a bug, please reach out.
As previously stated, this remains experimental, and at the moment is just intended as a tool to allow me to querry how brightness/signature/abundance of individual single colors impacts the full-unmixing. As I improve on my existing knowledge, the quality of inputs/outputs is likely to also improve as I figure out the things that I don’t yet know and correct for them. So consider this a work in progress for now, feel free to reach out if you know something I don’t, and want to collaborate on getting it implemented here.
For now, let’s identify the raw full-stained files and load them into a GatingSet:
File_Location <- system.file("extdata", package = "Luciernaga")
FCS_Pattern <- ".fcs$"
FCS_Files <- list.files(path = File_Location, pattern = FCS_Pattern,
full.names = TRUE, recursive = FALSE)
RawFullStainedFCSFiles <- FCS_Files[grep("Tetramer", FCS_Files)]
RawFullStainedFCSFiles <- RawFullStainedFCSFiles[-grep("Unmixed", RawFullStainedFCSFiles)]
UnmixCytoSet <- load_cytoset_from_fcs(RawFullStainedFCSFiles, truncate_max_range = FALSE, transform = FALSE)
UnmixGatingSet <- GatingSet(UnmixCytoSet)
Let’s identify the Single Color Reference Data output from
Luciernaga_SingleColors()
that we have validated
(correcting from any issues)
ReferencePath <- system.file("extdata", package = "Luciernaga")
ValidatedSCReferenceData <- file.path(ReferencePath, "ValidatedSCReferenceData.csv")
SingleColorReference <- read.csv(ValidatedSCReferenceData, check.names = FALSE)
And finally, lets provide a file.path to the panel (to establish correct ordering of fluorophores in the final file)
PanelPath <- file.path(ReferencePath, "UnmixingPanel.csv")
PanelNames <- read.csv(PanelPath, check.names=FALSE)
With these pre-requisites prepared we can go ahead. For this example, we will merge the “GROUPNAME” and “TUBENAME” to form the final name. For the final file, we will use the addon argument to append “_Unmixed” at the end. As Ordinary Least Squares (OLS) returns values close to 0, the multiplier increases all values across the board, which allows the data to resemble that of other softwares when the bi-exponential transform is applied.
Luciernaga_IterativeUnmix
This function is an extension of Luciernaga_Unmix()
using the same inputs, with the added provision that you provide it a
folder of variant of Luciernaga_QC()
.fcs files for a
single fluorophore of interest. Luciernaga_IterativeUnmix()
will then proceed one by one through the files in that folder, process
them individually and swap them in to the Reference Matrix, unmix the
full-stain samples, and return the variant unmixed full-stain files to
the outfolder. It will repeat this until everything is complete. What we
will do subsequently, is use Utility_UnityPlots()
and
Utility_NxNPlots()
and the workflow described in Vignette 1
to consolidate all the variant unmixed files and evaluate how the
variation in that iterated single-color impacted the final unmixing.
IterativePath <- file.path(ReferencePath, "DifferentialPerCP")
removestrings <- c("DR_", ".fcs")
iterate_removestrings <- c("DR_", "(Cells)", ".fcs", " ", "PerCP-Cy5.5", "CD26", "_")
TheSampleName <- c("GROUPNAME", "TUBENAME")
Luciernaga_IterativeUnmixing(IterativePath=IterativePath, iterate_removestrings=iterate_removestrings,
removestrings=removestrings, sample.name=TheSampleName, subset="root",
PanelCuts=ThePanelCuts, stats="median", Verbose=FALSE, SignatureView=FALSE,
FullStainedGS=UnmixGatingSet, controlData=SingleColorReference, multiplier=50000,
outpath=UnmixedOutpath, PanelPath=PanelPath)
Conclusion
And with that, we conclude our tour of the current state of the
unmixing functions within the Luciernaga
package. They
remain a work in progress, and we welcome any
contributions/insights/bug-reports to continue improving on them. This
entire project arose when curious of how placing a positive gate on a
single-color unmixing control would alter the unmixing of that file, and
the sum of Luciernaga
’s functions have been geared to
allowing me to answer these questions so that no other graduate student
will have to go through the horror of “it unmixed weird, no idea why” 20
years from now.
#> R version 4.4.1 (2024-06-14 ucrt)
#> Platform: x86_64-w64-mingw32/x64
#> Running under: Windows 11 x64 (build 22631)
#>
#> Matrix products: default
#>
#>
#> locale:
#> [1] LC_COLLATE=English_United States.utf8
#> [2] LC_CTYPE=English_United States.utf8
#> [3] LC_MONETARY=English_United States.utf8
#> [4] LC_NUMERIC=C
#> [5] LC_TIME=English_United States.utf8
#>
#> time zone: America/New_York
#> tzcode source: internal
#>
#> attached base packages:
#> [1] stats graphics grDevices utils datasets methods base
#>
#> other attached packages:
#> [1] htmltools_0.5.8.1 plotly_4.10.4 gt_0.11.1
#> [4] stringr_1.5.1 purrr_1.0.2 dplyr_1.1.4
#> [7] data.table_1.16.2 ggcyto_1.32.0 ncdfFlow_2.50.0
#> [10] BH_1.84.0-0 ggplot2_3.5.1 openCyto_2.16.1
#> [13] flowWorkspace_4.16.0 flowCore_2.16.0 Luciernaga_0.99.1
#> [16] BiocStyle_2.32.1
#>
#> loaded via a namespace (and not attached):
#> [1] RBGL_1.80.0 gridExtra_2.3 rlang_1.1.4
#> [4] magrittr_2.0.3 matrixStats_1.4.1 ggridges_0.5.6
#> [7] compiler_4.4.1 dir.expiry_1.12.0 png_0.1-8
#> [10] systemfonts_1.1.0 vctrs_0.6.5 reshape2_1.4.4
#> [13] pkgconfig_2.0.3 fastmap_1.2.0 labeling_0.4.3
#> [16] utf8_1.2.4 rmarkdown_2.28 graph_1.82.0
#> [19] ragg_1.3.3 xfun_0.48 zlibbioc_1.50.0
#> [22] cachem_1.1.0 jsonlite_1.8.9 highr_0.11
#> [25] SnowballC_0.7.1 parallel_4.4.1 R6_2.5.1
#> [28] bslib_0.8.0 stringi_1.8.4 RColorBrewer_1.1-3
#> [31] reticulate_1.39.0 lubridate_1.9.3 jquerylib_0.1.4
#> [34] figpatch_0.2 Rcpp_1.0.13 bookdown_0.41
#> [37] knitr_1.48 zoo_1.8-12 Matrix_1.7-0
#> [40] timechange_0.3.0 tidyselect_1.2.1 rstudioapi_0.17.0
#> [43] yaml_2.3.10 viridis_0.6.5 lattice_0.22-6
#> [46] tibble_3.2.1 plyr_1.8.9 Biobase_2.64.0
#> [49] basilisk.utils_1.16.0 withr_3.0.1 evaluate_1.0.1
#> [52] Rtsne_0.17 desc_1.4.3 xml2_1.3.6
#> [55] pillar_1.9.0 lsa_0.73.3 BiocManager_1.30.25
#> [58] filelock_1.0.3 stats4_4.4.1 generics_0.1.3
#> [61] S4Vectors_0.42.1 munsell_0.5.1 scales_1.3.0
#> [64] glue_1.8.0 lazyeval_0.2.2 tools_4.4.1
#> [67] hexbin_1.28.4 fs_1.6.4 XML_3.99-0.17
#> [70] grid_4.4.1 flowClust_3.42.0 tidyr_1.3.1
#> [73] RProtoBufLib_2.16.0 crosstalk_1.2.1 colorspace_2.1-1
#> [76] patchwork_1.3.0 basilisk_1.16.0 cli_3.6.3
#> [79] textshaping_0.4.0 fansi_1.0.6 cytolib_2.16.0
#> [82] viridisLite_0.4.2 uwot_0.2.2 Rgraphviz_2.48.0
#> [85] gtable_0.3.5 sass_0.4.9 digest_0.6.37
#> [88] BiocGenerics_0.50.0 htmlwidgets_1.6.4 farver_2.1.2
#> [91] pkgdown_2.1.1 lifecycle_1.0.4 httr_1.4.7