Data Visualization
David Rach
University of Maryland, Baltimoredrach@som.umaryland.edu
30 October 2024
Source:vignettes/DataVisualization.Rmd
DataVisualization.Rmd
Abstract
Spectral Flow Cytometry (SFC) capacity to rapidly acquire large number of cellular events is similar to that of conventional flow cytometry (CFC), but it’s ability to resolve very similar fluorophores allows for marker profiling comparable to mass cytometry (MC). Unmixing controls (both single color and unstained) are critical to this process. Luciernaga is a collection of tools to enable individual users to profile quality of their unmixing controls, how they vary across experiments, and their subsequent effects on unmixing of full-stained samples.
Introduction
Spectral flow cytometry (SFC) ability to resolve the presence and relative abundance of highly similar fluorophores on individual cells is heavily dependent on the quality of the reference unmixing controls (both single-color (SC) and unstained (UC)).
Despite their critical role, there are few resources and tools (either open-source or commercial) available to evaluate the quality of the unmixing controls. This leads to individual users only becoming aware of issues after unmixing the full-stained sample when the unmixed sample looks “off”. They are subsequently left to interpret the tea leaves of their unmixed data, attempting to parse what may have led to the outcome.
Given that unmixing issues can arise from a variety of sources (multiple autofluorescences, tandem degradation, or instrumental error) that similarly can result in loss of resolution, having a way to screen for problematic unmixing controls quickly and evaluate their potential effect on re-unmixing would be useful. Additionally, tools made for these purposes can be utilized to further query how individual fluorescent signatures and brightness impact the unmixing process.
Luciernaga is an R package that attempts to address these gaps. It provides functionality to implement and tailor quality control checks of unmixing controls, characterize normalized signatures present, and evaluate their effect on unmixing. Using functional programming, it can enable data exploration and visualization for an entire data set.
These work at the individual experiment basis, but can also be combined to visualize changes in fluorescence across an experimental run to identify trends affecting single color quality. Our goal is to provide tools that others can use to further develop quantitative methods to monitor their own individual panels and instrumental configurations. We additionally leverage functional programming ability of the purrr to enable data visualization of all markers present with the resulting unmixed samples, as well as all samples present within a GatingSet at a desired gating node.
Luciernaga is a free and open source software project started at the University of Maryland, Baltimore and is under active development. It was originally designed to address issues around our cytometry core’s Cytek Aurora instruments. We would love your feedback. If you identify any bugs, please open an issue on the github repository. If you have suggestions or would like to participate in extending the functionality to other spectral cytometry instruments, please reach out to the email listed in the description.
Setup
Installing Luciernaga
We are in the process of preparing Luciernaga for submission to Bioconductor later this year. Until then, it is available for download via our GitHub.
if(!require("remotes")) {install.packages("remotes")}
if(!require("Luciernaga")){
remotes::install_github("https://github.com/DavidRach/Luciernaga")
}
# install.packages("BiocManager")
# BiocManager::install("Luciernaga")
Loading Libraries
Luciernaga works using infrastructure provided by other Bioconductor cytometry packages. It also makes use of tidyverse packages available via CRAN to facilitate use by target audience of novice-intermediate R users. It is important to make sure that these are installed on your computer and then that the libraries are loaded.
Locating .fcs files
To get started, you will first need to provide the location on your computer where the .fcs files of interest are being stored. An example of how the author does this on their computer is provided below and can be modified for your own user and desired computer folder.
File_Location <- file.path("C:", "Users", "JohnDoe", "Desktop",
"TodaysExperiment")
FCS_Pattern <- ".fcs$"
FCS_Files <- list.files(path = File_Location, pattern = FCS_Pattern,
full.names = TRUE, recursive = FALSE)
For this vignette, we will using down-sampled .fcs files that can be found in Luciernaga’s extdata folder for our example. From the original .fcs files, we have retained 10000 events for cell unmixing controls, and 3000 for bead unmixing controls.
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[20:30], 10)
#> [1] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CCR7_BV650(Beads).fcs"
#> [2] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CCR7_BV650(Cells).fcs"
#> [3] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CD107a_APC-R700(Beads).fcs"
#> [4] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CD107a_APC-R700(Cells).fcs"
#> [5] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CD127_BV421(Beads).fcs"
#> [6] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CD127_BV421(Cells).fcs"
#> [7] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CD16_APC(Beads).fcs"
#> [8] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CD16_APC(Cells).fcs"
#> [9] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CD161_BV480(Beads).fcs"
#> [10] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CD161_BV480(Cells).fcs"
Within the extdata folder we have a mix of different files intended for different vignettes. The majority of the contents are unmixing controls and full-stained samples acquired in the process of processing a 29-color SFC panel of Cord (CBMC) and Peripheral Blood Mononuclear Cells (PBMCs), both raw and unmixed files. Additionally, there are samples that correspond to Cytek Aurora QC beads that were collected before and after the daily QC bead for instrument monitoring.
For this initial example, lets filter the list by keywords in the file name to organize them for subsequent use elsewhere in the vignette. For now, let’s subset the desired files as shown below:
QCBeads <- FCS_Files[grep("After|Before", FCS_Files)]
Unmixed_FullStained <- FCS_Files[grep("Unmixed", FCS_Files)]
Raw_FullStained <- FCS_Files[-grep(
"Cells|Beads|Unmixed|Unstained|After|Before", FCS_Files)]
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)]
CellSingleColors <- FCS_Files[grep("Cells", FCS_Files)]
head(CellSingleColors, 10)
#> [1] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CCR4_BUV615(Cells).fcs"
#> [2] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CCR6_BV786(Cells).fcs"
#> [3] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CCR7_BV650(Cells).fcs"
#> [4] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CD107a_APC-R700(Cells).fcs"
#> [5] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CD127_BV421(Cells).fcs"
#> [6] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CD16_APC(Cells).fcs"
#> [7] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CD161_BV480(Cells).fcs"
#> [8] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CD25_PE-Cy5(Cells).fcs"
#> [9] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CD26_PerCP-Cy5.5(Cells).fcs"
#> [10] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/CD27_APC-Fire750(Cells).fcs"
Creating a GatingSet
Once we have the list of desired .fcs files, we can use the flowWorkspace to bring these individual .fcs files first into a CytoSet object, then into a GatingSet object that we can add gates to:
MyCytoSet <- load_cytoset_from_fcs(UnstainedCells, truncate_max_range = FALSE,
transformation = FALSE)
#MyCytoSet
MyGatingSet <- GatingSet(MyCytoSet)
MyGatingSet
#> A GatingSet with 18 samples
For this example, we will use the openCyto package to automatically gate each of our .fcs files for the lymphocyte population. To do this, we first read in the example .csv file containing our desired gates (that can be found in Luciernaga’s extdata folder) using the data.table package
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 |
For your own experiments, individual gates can be added, removed or modified to match the requirements of your own .fcs files, for additional details, please refer to the openCyto packages vignettes. Alternatively, GatingSet objects can be brought directly from several commercial software formats using the CytoML package.
Now that we have the gating information from the .csv file, we can convert them into a GatingTemplate, and append them to the .fcs files contained within the GatingSet
MyGatingTemplate <- gatingTemplate(MyGates)
gt_gating(MyGatingTemplate, MyGatingSet)
MyGatingSet[[1]]
#> Sample: INF071_Ctrl_Unstained.fcs
#> GatingHierarchy with 6 gates
Visualizing Gates
Utility_GatingPlots
We can visualize our applied gates on their individual .fcs files
using Luciernaga’s Utility_GatingPlots()
function. We can
do this individually, or iterate over the entire GatingSet using the
purrr
purrr::map()
function.
To do this, we reference the data.table
imported gating information (MyGates) showcased above, and the GatingSet
object. Utility_GatingPlots()
argument export = FALSE will
return a patchwork
grouped ggplot objects, return = TRUE returns the same output in a .pdf
file to the designated output location.
removestrings <- c("DR_", "Cells", ".fcs", "-", " ")
StorageLocation <- file.path("C:", "Users", "JohnDoe", "Desktop")
IndividualPlot <- Utility_GatingPlots(x=MyGatingSet[[2]], sample.name = "GUID",
removestrings = removestrings,
gtFile = MyGates, DesiredGates = NULL,
outpath = StorageLocation, export = FALSE)
IteratedPlots <- map(.x = MyGatingSet[1:3], .f = Utility_GatingPlots,
sample.name = "GUID", removestrings = removestrings,
gtFile = MyGates, DesiredGates = NULL,
outpath = StorageLocation, export = FALSE)
IndividualPlot
#> $`1`
#>
#> $`2`
Utility_IterativeGating
In the absence of an existing gating template, the
Utility_IterativeGating()
function can be used to visualize
individual gate placements for specimens found in a GatingSet object. To
figure out the necessary information, we can use flowWorkspace
flowWorkspace::plot()
and
flowWorkspace::gs_pop_get_gate()
to find out the gate, and
the respective X and Y parameters.
plot(MyGatingSet)
gs_pop_get_gate(MyGatingSet[1], "lymphocytes")
#> $INF071_Ctrl_Unstained.fcs
#> Ellipsoid gate 'lymphocytes' in dimensions FSC-A and SSC-A
SingleSpecimen <- Utility_IterativeGating(x=MyGatingSet[1], sample.name = "GUID",
removestrings = removestrings,
subset = "nonDebris",
gate = "lymphocytes",
xValue = "FSC-A", yValue = "SSC-A",
bins = 270)
AllSpecimens <- Utility_IterativeGating(x=MyGatingSet[1:3], sample.name = "GUID",
removestrings = removestrings,
subset = "nonDebris", gate = "lymphocytes",
xValue = "FSC-A", yValue = "SSC-A", bins = 270)
SingleSpecimen
#> [[1]]
Utility_Patchwork
The previous example returned AllSpecimens, which is a list of ggplot
objects. This allows us to showcase Utility_Patchwork()
. It
is a wrapper for patchwork
that is used in the background by Luciernaga’s data visualization
functions when generating .pdf files from existing ggplot objects.
Utility_Patchwork()
will take the list of ggplot
objects, arrange them based on the specified number of columns and rows
into individual pages of designated width and height, and when
returntype = “pdf” save them to the designated outfolder file.path with
the desired file.name.
StorageLocation <- file.path("C:", "Users", "JohnDoe", "Desktop")
Utility_Patchwork(AllSpecimens, "LymphocyteGates", outfolder=StorageLocation,
thecolumns=2, therows=2, width = 7, height = 9,
returntype="patchwork")
#> $`1`
Creating a GatingSet for Unmixed .fcs files
The next couple functions are designed primarily for use with unmixed full-stained samples. We will return to the earlier example and select the corresponding example .fcs files found within Luciernaga’s extdata folder and bring them into a GatingSet object.
UnmixedFCSFiles <- Unmixed_FullStained[c(1:4)]
UnmixedFCSFiles
#> [1] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/INF071_Ctrl_Tetramer_Unmixed.fcs"
#> [2] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/INF149_Ctrl_Tetramer_Unmixed.fcs"
#> [3] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/INF179_Ctrl_Tetramer_Unmixed.fcs"
#> [4] "C:/Users/12692/AppData/Local/R/win-library/4.4/Luciernaga/extdata/ND050_15_Ctrl_Tetramer_Unmixed.fcs"
UnmixedCytoSet <- load_cytoset_from_fcs(UnmixedFCSFiles,
truncate_max_range = FALSE,
transform = FALSE)
UnmixedGatingSet <- GatingSet(UnmixedCytoSet)
UnmixedGatingSet
#> A GatingSet with 4 samples
Now that they are in a GatingSet object, we will identify
markers/fluorophores present for the .fcs file, and remove from the list
markers that don’t need to be transformed (example FSC, SSC, etc). We
will then bi-exponentially transform the data using flowWorkspace
flowWorkspace::flowjo_biexp_trans()
before applying a
gating template.
Markers <- colnames(UnmixedCytoSet)
KeptMarkers <- Markers[-grep(
"Time|FS|SC|SS|Original|-W$|-H$|AF", Markers)]
MyBiexponentialTransform <- flowjo_biexp_trans(channelRange = 256,
maxValue = 1000000,
pos = 4.5, neg = 0,
widthBasis = -1000)
TransformList <- transformerList(KeptMarkers, MyBiexponentialTransform)
UnmixedGatingSet <- transform(UnmixedGatingSet, TransformList)
FileLocation <- system.file("extdata", package = "Luciernaga")
UnmixedGates <- fread(file.path(path = FileLocation,
pattern = 'GatesUnmixed.csv'))
UnmixedGating <- gatingTemplate(UnmixedGates)
gt_gating(UnmixedGating, UnmixedGatingSet)
UnmixedGatingSet[[4]]
#> Sample: ND050_15_Ctrl_Tetramer_Unmixed.fcs
#> GatingHierarchy with 7 gates
And to verify successfully gated as we expected:
plot(UnmixedGatingSet)
StorageLocation <- file.path("C:", "Users", "JohnDoe", "Desktop")
removestrings <- ".fcs"
UnmixedIndividualPlot <- Utility_GatingPlots(x=UnmixedGatingSet[[2]],
sample.name = "GUID",
removestrings = removestrings,
gtFile = UnmixedGates,
DesiredGates = NULL,
outpath = StorageLocation,
export = FALSE)
UnmixedIndividualPlot
#> $`1`
#>
#> $`2`
# Visualizing Data
Utility_NxNPlots
Utility_NxNPlots()
is a convenient function to visualize
unmixed .fcs files for every marker compared to a reference marker. It
is particularly useful in identifying cell populations, as well as
unmixing errors. It takes a GatingSet object that has been transformed
and gated. The desired population of cells can then be specified by the
gatesubset argument. ycolumn specifies the desired marker to compare all
the other markers to. Similar to other functions that use
Utility_Patchwork behind the scenes, it can send the outputs for each
specimen to their own pdf file.
plot(UnmixedGatingSet)
removethese <- c(".fcs", "DTR_")
StorageLocation <- file.path("C:", "Users", "JohnDoe", "Desktop")
colnames(UnmixedGatingSet)[11:39]
#> [1] "BUV395-A" "BUV496-A" "BUV563-A"
#> [4] "BUV615-A" "BUV661-A" "BUV737-A"
#> [7] "BUV805-A" "BV421-A" "Pacific Blue-A"
#> [10] "BV480-A" "BV510-A" "BV605-A"
#> [13] "BV650-A" "BV711-A" "BV750-A"
#> [16] "BV786-A" "Alexa Fluor 488-A" "Spark Blue 550-A"
#> [19] "PerCP-Cy5.5-A" "PE-A" "PE-Dazzle594-A"
#> [22] "PE-Cy5-A" "PE-Vio770-A" "APC-A"
#> [25] "Alexa Fluor 647-A" "APC-R700-A" "Zombie NIR-A"
#> [28] "APC-Fire 750-A" "APC-Fire 810-A"
IndividualNxN <- Utility_NbyNPlots(x=UnmixedGatingSet[[4]],
sample.name = "GROUPNAME",
removestrings = removethese,
marginsubset = "lymphocytes",
gatesubset = "live",
ycolumn = "Spark Blue 550-A",
bins = 70, clearance = 0.2,
gatelines = FALSE, reference = NULL,
outpath = StorageLocation,
returntype="patchwork")
MultipleNxN <- map(.x = UnmixedGatingSet[1:2], .f = Utility_NbyNPlots,
sample.name = "GROUPNAME", removestrings = removethese,
marginsubset = "lymphocytes", gatesubset = "live",
ycolumn = "Spark Blue 550-A", bins = 70, clearance = 0.2,
gatelines = FALSE, reference = NULL,
outpath = StorageLocation, returntype="patchwork")
IndividualNxN[1]
#> $`1`
The return is for a given specimen all markers vs. the specified
marker on the y-axis. Utility_NxNPlots()
additionally
accepts a ycolumn = “ALL” option that will directly iterate over every
marker as the ycolumn argument. However, be warned, for larger SFC
panels with many fluorophores, it will take time for a single specimen
(and each marker pdf taking up memory space!), and even more so over
every specimen in a GatingSet!!!
removethese <- c(".fcs", "DTR_")
StorageLocation <- file.path("C:", "Users", "JohnDoe", "Desktop")
All_IndividualNxN <- Utility_NbyNPlots(x=UnmixedGatingSet[[1]],
sample.name = "GROUPNAME",
removestrings = removethese,
marginsubset = "lymphocytes",
gatesubset = "live", ycolumn = "ALL",
bins = 120, clearance = 0.2,
gatelines = FALSE, reference = NULL,
outpath = StorageLocation,
returntype="pdf")
ALL_MultipleNxN <- map(.x = UnmixedGatingSet, .f = Utility_NbyNPlots,
sample.name = "GROUPNAME", removestrings = removethese,
marginsubset = "lymphocytes", gatesubset = "live",
ycolumn = "ALL", bins = 120, clearance = 0.2,
gatelines = FALSE, reference = NULL,
outpath = StorageLocation, returntype="pdf")
Utility_ParallelNxNPlots
Utitlity_ParallelNxNPlots
is an extension of
Utility_NxNPlots
, but is used to compare two separate
samples that are overlaid on the same plot. This can be useful when
comparing different specimens, different treatment conditions, and
differences in unmixing. It is usable but remains under development
(notice the colors from the different specimens don’t blend well). It
utilizes the purrr
purrr::map2()
argument behind the scenes to determine the
order of what specimens are compared to each other.
name |
---|
INF071_Ctrl_Tetramer_Unmixed.fcs |
INF149_Ctrl_Tetramer_Unmixed.fcs |
INF179_Ctrl_Tetramer_Unmixed.fcs |
ND050_15_Ctrl_Tetramer_Unmixed.fcs |
OverlaidNxNPlots <- Utility_ParallelNbyNPlots(x=UnmixedGatingSet[1],
y = UnmixedGatingSet[4],
sample.name = "GROUPNAME",
removestrings = ".fcs",
Override = FALSE,
marginsubset = "lymphocytes",
gatesubset = "live",
ycolumn = "Spark Blue 550-A",
bins = 120, clearance = 0.2,
colorX = "lightblue",
colorY = "orange",
gatelines = FALSE,
reference = NULL,
outpath = StorageLocation,
pdf = FALSE)
OverlaidNxNPlots[1]
#> $`1`
Similar to Utility_NxNPlots()
, switching the argument
ycolumn = “ALL” will iterate over all marker combinations for y-column
vs all x-marker combinations. The same warning about run time and memory
space applies, but double it as we are overlaying plots.
#Currently bugged out for All Option
gt(pData(UnmixedGatingSet))
All_OverlaidNxNPlots <- Utility_ParallelNbyNPlots(x=UnmixedGatingSet[1],
y = UnmixedGatingSet[2],
sample.name = "GROUPNAME",
removestrings = ".fcs",
Override = FALSE,
marginsubset = "lymphocytes",
gatesubset = "live",
ycolumn = "ALL", bins = 120,
clearance = 0.2,
colorX = "lightblue",
colorY = "orange",
gatelines = FALSE,
reference = NULL,
outpath = StorageLocation,
pdf = FALSE)
All_OverlaidNxNPlots[1]
Utility_UnityPlots
While Utility_NxNPlots()
will show all marker
combinations for a single specimen, Utility_UnityPlots()
will showcase a single combination of markers for all specimens present
in the GatingSet. Given that bringing data from every specimen into
active memory is a way to max out your ram, it is helpful to break the
map calls into chunks. Here is an example:
SingleUnityPlot <- Utility_UnityPlot(x="Spark Blue 550-A", y="BUV805-A",
GatingSet=UnmixedGatingSet,
sample.name="GROUPNAME", bins=100,
clearance=0.2,removestrings=removestrings,
marginsubset="lymphocytes",
gatesubset="live", gatelines=FALSE,
reference=NULL, returntype="patchwork",
outpath=StorageLocation)
SingleUnityPlot
#> $`1`
Markers <- colnames(UnmixedCytoSet)
KeptMarkers <- Markers[-grep("Time|FS|SC|SS|Original|-W$|-H$|AF", Markers)]
KeptMarkers
#> [1] "BUV395-A" "BUV496-A" "BUV563-A"
#> [4] "BUV615-A" "BUV661-A" "BUV737-A"
#> [7] "BUV805-A" "BV421-A" "Pacific Blue-A"
#> [10] "BV480-A" "BV510-A" "BV605-A"
#> [13] "BV650-A" "BV711-A" "BV750-A"
#> [16] "BV786-A" "Alexa Fluor 488-A" "Spark Blue 550-A"
#> [19] "PerCP-Cy5.5-A" "PE-A" "PE-Dazzle594-A"
#> [22] "PE-Cy5-A" "PE-Vio770-A" "APC-A"
#> [25] "Alexa Fluor 647-A" "APC-R700-A" "Zombie NIR-A"
#> [28] "APC-Fire 750-A" "APC-Fire 810-A"
MultipleUnityPlots <- map(.x=KeptMarkers[c(1:6, 8:10)], .f=Utility_UnityPlot,
y="BUV805-A", GatingSet=UnmixedGatingSet,
sample.name="GROUPNAME", bins=100,clearance=0.2,
removestrings=removestrings, marginsubset="lymphocytes",
gatesubset="live", gatelines=FALSE, reference=NULL,
returntype="patchwork", outpath=StorageLocation)
MultipleUnityPlots[1:2]
#> [[1]]
#> [[1]]$`1`
#>
#>
#> [[2]]
#> [[2]]$`1`
Utility_ThirdColor
Similar to the other visualization functions,
Utility_ThirdColor()
plots the data from the specified
GatingSet and subset for the given X and Y axis-markers. From here it
will overlay a color for an additional marker, allowing for
identification of those cells.
Utility_ThirdColor()
has three plotting modes that are
called within the splitpoint argument. When “Continuous” is specified,
it takes two colors and forms a color gradient from the lowest to
highest values specified for the parameter specified in the zaxis
argument.
SinglePlot <- Utility_ThirdColorPlots(x=UnmixedGatingSet[1], subset = "live",
xaxis="BUV496-A", yaxis = "Spark Blue 550-A",
zaxis ="BUV805-A", splitpoint = "continuous",
sample.name = "GROUPNAME",
removestrings = c("DTR", ".fcs"),
thecolor = "blue")
#> Splitpoint is a continuous
AllPlot <- map(.x=UnmixedGatingSet, .f=Utility_ThirdColorPlots, subset = "live",
xaxis="BUV496-A", yaxis = "Spark Blue 550-A", zaxis ="BUV805-A",
splitpoint = "continuous", sample.name = "GROUPNAME",
removestrings = c("DTR", ".fcs"), thecolor = "blue")
#> Splitpoint is a continuous
#> Splitpoint is a continuous
#> Splitpoint is a continuous
#> Splitpoint is a continuous
SinglePlot
When a categorical column exist in the .fcs file and is specified as zaxis, splitpoint = “Categorical” can be specified. It will internally convert the zaxis column into a factor. A list of equivalent name(s) is then given to FactorNames. These in turn will be filtered and assigned the same color.
ColorTheseFactors <- c("1", "4") #Due to how .fcs files often save factors as numeric values.
SinglePlot <- Utility_ThirdColorPlots(x=UnmixedGatingSet[1], subset = "live",
xaxis="BUV496-A", yaxis = "Spark Blue 550-A",
zaxis ="BUV805-A", splitpoint = "120",
sample.name = "GROUPNAME",
removestrings = c("DTR", ".fcs"),
FactorNames = ColorTheseFactors,
thecolor = "orange")
AllPlot <- map(.x=UnmixedGatingSet, .f=Utility_ThirdColorPlots, subset = "live",
xaxis="BUV496-A", yaxis = "Spark Blue 550-A", zaxis ="BUV805-A",
splitpoint = "130", sample.name = "GROUPNAME",
removestrings = c("DTR", ".fcs"), FactorNames = ColorTheseFactors,
thecolor = "orange")
SinglePlot
The third option “splitpoint” will dichotomize a continuous marker expression at the given value (either raw MFI or biexponential transformed) into positive and negative cells. It will then shade the cells accordingly.
SinglePlot <- Utility_ThirdColorPlots(x=UnmixedGatingSet[1], subset = "live",
xaxis="BUV496-A", yaxis = "Spark Blue 550-A",
zaxis ="BUV805-A", splitpoint = "120",
sample.name = "GROUPNAME",
removestrings = c("DTR", ".fcs"),
thecolor = "orange")
SinglePlot
AllPlot <- map(.x=UnmixedGatingSet, .f=Utility_ThirdColorPlots, subset = "live",
xaxis="BUV496-A", yaxis = "Spark Blue 550-A", zaxis ="BUV805-A",
splitpoint = "130", sample.name = "GROUPNAME",
removestrings = c("DTR", ".fcs"), thecolor = "orange")
To provide multiple filtering arguments to
Utility_ThirdColorPlots()
, a data.frame can be provided to
the splitpoint argument. This is composed of two columns, “Fluorophore”
and “Splitpoint”, with the specified arguments present in the rows. When
a data.frame is detected, Utility_ThirdColorPlots()
will
then iterate down the rows to find each gating argument, returning only
the remaining cells that are greater than values listed for each
marker.
FileLocation <- system.file("extdata", package = "Luciernaga")
CSVLocation <- file.path(path = FileLocation, pattern = 'ThirdColorDataFrame.csv')
ThirdColorArguments <- read.csv(CSVLocation)
gt(ThirdColorArguments)
Fluorophore | Splitpoint |
---|---|
BUV805-A | 100 |
BV480-A | 95 |
PE-Cy5-A | 120 |
SinglePlot <- Utility_ThirdColorPlots(x=UnmixedGatingSet[1], subset = "live",
xaxis="BUV496-A", yaxis = "Spark Blue 550-A",
zaxis =NULL, splitpoint = ThirdColorArguments,
sample.name = "GROUPNAME",
removestrings = c("DTR", ".fcs"),
thecolor = "orange")
#> Splitpoint is a Dataframe
MultiplePlot <- map(.x=UnmixedGatingSet, .f=Utility_ThirdColorPlots, subset = "live",
xaxis="BUV496-A", yaxis = "Spark Blue 550-A", zaxis =NULL,
splitpoint = ThirdColorArguments, sample.name = "GROUPNAME",
removestrings = c("DTR", ".fcs"), thecolor = "orange")
#> Splitpoint is a Dataframe
#> Splitpoint is a Dataframe
#> Splitpoint is a Dataframe
#> Splitpoint is a Dataframe
SinglePlot
Utility_ThirdColorPlots can also be used in combination with the Coereba packages GatingCutoff estimates to allow for specimen specific split-points for the specified markers, using the GatingCutoff csv file. This is particularly useful for non-normalized specimens where batch effects are present.
To provide flexibility for your own analysis,
Utility_ThirdColorPlots()
returns ggplot objects. These in
turn can be edited, or a list of them passed to and arranged using
Utility_Patchwork()
into a .pdf of desired layout.
Utility_DensityOverlay
The function Utility_DensityOverlay()
is a wrapper
function incorporating elements from the underlying ggplot2
geom_density()
function. It’s use is particularly useful
when working with a GatingSet of multiple specimens and comparing across
individuals.
To use both Utility_DensityOverlay()
and
Utility_RidgePlots()
to their fullest extent, we will need
to create additional factor variables for each specimen and append them
to the GatingSet’s pData. These can then be called to use as axis, color
and fill arguments for the function. Below you can find examples of
local functions that you can edit for your particular data to extract
variables of interest to append to the pData.
Metadata <- pData(UnmixedGatingSet)
Metadata
#> name
#> INF071_Ctrl_Tetramer_Unmixed.fcs INF071_Ctrl_Tetramer_Unmixed.fcs
#> INF149_Ctrl_Tetramer_Unmixed.fcs INF149_Ctrl_Tetramer_Unmixed.fcs
#> INF179_Ctrl_Tetramer_Unmixed.fcs INF179_Ctrl_Tetramer_Unmixed.fcs
#> ND050_15_Ctrl_Tetramer_Unmixed.fcs ND050_15_Ctrl_Tetramer_Unmixed.fcs
NameYoink <- function(x){
pattern <- "(INF|ND)\\d{3}"
result <- stringr::str_extract(x, pattern)
result <- data.frame(result)
colnames(result)[1] <- "specimen"
result$specimen <- factor(result$specimen)
return(result)
}
ConditionYoink <- function(x){
pattern <- "Ctrl|PMA"
result <- stringr::str_extract(x, pattern)
result <- data.frame(result)
colnames(result)[1] <- "condition"
result$condition <- factor(result$condition)
return(result)
}
NormalizedYoink <- function(x){
result <- stringr::str_detect(x, "Norm")
result <- data.frame(result)
colnames(result)[1] <- "normalized"
result$normalized <- factor(result$normalized)
return(result)
}
pd <- pData(UnmixedGatingSet)
pa <- pd %>% select(`name`) %>% pull()
Specimen <- map(pa, .f=NameYoink) %>% bind_rows()
Specimen
#> specimen
#> 1 INF071
#> 2 INF149
#> 3 INF179
#> 4 ND050
Condition <- map(pa, .f=ConditionYoink) %>% bind_rows
Condition
#> condition
#> 1 Ctrl
#> 2 Ctrl
#> 3 Ctrl
#> 4 Ctrl
And once we have the factor variables that we need, we can bind the columns together, and then assign them back to the GatingSet.
pd <- cbind(pd, Specimen, Condition)
pData(UnmixedGatingSet) <- pd
pData(UnmixedGatingSet)
#> name specimen
#> INF071_Ctrl_Tetramer_Unmixed.fcs INF071_Ctrl_Tetramer_Unmixed.fcs INF071
#> INF149_Ctrl_Tetramer_Unmixed.fcs INF149_Ctrl_Tetramer_Unmixed.fcs INF149
#> INF179_Ctrl_Tetramer_Unmixed.fcs INF179_Ctrl_Tetramer_Unmixed.fcs INF179
#> ND050_15_Ctrl_Tetramer_Unmixed.fcs ND050_15_Ctrl_Tetramer_Unmixed.fcs ND050
#> condition
#> INF071_Ctrl_Tetramer_Unmixed.fcs Ctrl
#> INF149_Ctrl_Tetramer_Unmixed.fcs Ctrl
#> INF179_Ctrl_Tetramer_Unmixed.fcs Ctrl
#> ND050_15_Ctrl_Tetramer_Unmixed.fcs Ctrl
StorageLocation <- file.path("C:", "Users", "JohnDoe", "Desktop")
pData(UnmixedGatingSet)
#> name specimen
#> INF071_Ctrl_Tetramer_Unmixed.fcs INF071_Ctrl_Tetramer_Unmixed.fcs INF071
#> INF149_Ctrl_Tetramer_Unmixed.fcs INF149_Ctrl_Tetramer_Unmixed.fcs INF149
#> INF179_Ctrl_Tetramer_Unmixed.fcs INF179_Ctrl_Tetramer_Unmixed.fcs INF179
#> ND050_15_Ctrl_Tetramer_Unmixed.fcs ND050_15_Ctrl_Tetramer_Unmixed.fcs ND050
#> condition
#> INF071_Ctrl_Tetramer_Unmixed.fcs Ctrl
#> INF149_Ctrl_Tetramer_Unmixed.fcs Ctrl
#> INF179_Ctrl_Tetramer_Unmixed.fcs Ctrl
#> ND050_15_Ctrl_Tetramer_Unmixed.fcs Ctrl
#colnames(UnmixedGatingSet)
Plot <- Utility_DensityOverlay(gs=UnmixedGatingSet, subset="lymphocytes", TheX="APC-Fire 810-A",
TheFill="specimen", returntype="plots",
outpath=StorageLocation, filename="CD4_Expression")
plotly::ggplotly(Plot[[1]])
Utility_RidgePlots
The function Utility_RidgePlots()
leverages the
ggplot2
and ggridges
packages to evaluate
marker expression across specimens, and provides some additional
functionality compared to Utility_DensityOverlay()
We can generate a specific RidgePlot of interest by providing the
name of a particular fluorophore in TheX argument. Alternatively, we can
leave it out to generate RidgePlots for all markers. As with the other
functions, it uses Utility_Patchwork()
and will take the
same arguments for layout.
StorageLocation <- file.path("C:", "Users", "JohnDoe", "Desktop")
pData(UnmixedGatingSet)
#> name specimen
#> INF071_Ctrl_Tetramer_Unmixed.fcs INF071_Ctrl_Tetramer_Unmixed.fcs INF071
#> INF149_Ctrl_Tetramer_Unmixed.fcs INF149_Ctrl_Tetramer_Unmixed.fcs INF149
#> INF179_Ctrl_Tetramer_Unmixed.fcs INF179_Ctrl_Tetramer_Unmixed.fcs INF179
#> ND050_15_Ctrl_Tetramer_Unmixed.fcs ND050_15_Ctrl_Tetramer_Unmixed.fcs ND050
#> condition
#> INF071_Ctrl_Tetramer_Unmixed.fcs Ctrl
#> INF149_Ctrl_Tetramer_Unmixed.fcs Ctrl
#> INF179_Ctrl_Tetramer_Unmixed.fcs Ctrl
#> ND050_15_Ctrl_Tetramer_Unmixed.fcs Ctrl
#colnames(UnmixedGatingSet)
SinglePlot <- Utility_RidgePlots(gs=UnmixedGatingSet, subset="live", TheFill="condition",
TheX = "APC-Fire 810-A", TheY="specimen", returntype="plots",
outpath=StorageLocation, filename="RidgePlot_Condition")
SinglePlot[[1]]
Plot <- Utility_RidgePlots(gs=UnmixedGatingSet, subset="live", TheFill="condition",
TheY="specimen", returntype="patchwork",
outpath=StorageLocation, filename="RidgePlot_Condition")
Plot[1:2]
#> $`1`
#>
#> $`2`
Future Development
In combination with purrr package functions, it’s possible to extend the visualization capacity for many scenarios similar to Utility_UnityPlots and Utility_NxNPlots. As community usefulness is demonstrated, these will become integrated in later versions of the package. Reach out via the GitHub for suggested improvements.
#> 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