The following document is a guide to how the various objects were generated for the sampleDashboard app from a GatingSet.
The strength of having different display objects instead of the GatingSet are: 1) Each object can be associated with an analysis step, 2) each object handles error handling and display options in a seamless way, populating the modules with very little debugging on the user’s part, 3) exploratory data analysis of the flow data can be done in a seamless way, aggregating on notations.
This code was taken from the flowWorkspace documentation. Note that we take the incoming flowSet and convert it to a ncdfFlowSet. In general, we find this file format is more stable, especially when generating plots.
## This code was modified from flowWorkspace examples
library(flowStats)
data(GvHD)
#select raw flow data and cast as ncdfFlowSet
fs<-ncdfFlowSet(GvHD)
pData(fs)$Visit <- ordered(pData(fs)$Visit)
pData(fs)$Days <- ordered(pData(fs)$Days)
#transform the raw data
tf <- transformList(colnames(fs[[1]])[3:6], asinh, transformationId="asinh")
fs_trans<-transform(fs,tf)
#add transformed data to a GatingSet
gs <- GatingSet(fs_trans)
gs
## A GatingSet with 35 samples
getNodes(gs[[1]]) #only contains root node
## [1] "root"
#add one gate
rg <- rectangleGate("FSC-H"=c(200,400), "SSC-H"=c(250, 400),
filterId="rectangle")
nodeID<-add(gs, rg)#it is added to root node by default if parent is not specified
nodeID
## [1] 2
getNodes(gs[[1]]) #the second population is named after filterId of the gate
## [1] "root" "/rectangle"
#add a quadGate
qg <- quadGate("FL1-H"=2, "FL2-H"=4)
nodeIDs<-add(gs,qg,parent="rectangle")
nodeIDs #quadGate produces four population nodes
## [1] 3 4 5 6
getNodes(gs[[1]]) #population names are named after dimensions of gate if not specified
## [1] "root" "/rectangle"
## [3] "/rectangle/CD15 FITC-CD45 PE+" "/rectangle/CD15 FITC+CD45 PE+"
## [5] "/rectangle/CD15 FITC+CD45 PE-" "/rectangle/CD15 FITC-CD45 PE-"
#do the actual gating
recompute(gs)
Now that the GvHD data is gated and in a GatingSet, we can build the various objects. First we look at the markers and pick three markers as markers for general QC. Annotation is derived from the phenoData slot of gs@data. Here, we sample our data using only 1000 points per sample, in order to save memory.
#show annotation
pD <- pData(parameters(gs@data[[1]]))
qcMarkers <- pD$desc[-c(6)]
#show markers in data
qcMarkers
## $P1S $P2S $P3S
## "FSC-Height" "SSC-Height" "CD15 FITC"
## $P4S $P5S $P7S
## "CD45 PE" "CD14 PerCP" "CD33 APC"
## $P8S
## "Time (51.20 sec.)"
library(flowDashboard)
##build QCO object
QCO <- QCOFromGatingSet(gs,samplePop = 1000,qcMarkers = qcMarkers)
##show structure of qcFlowObj
QCO
## <qcFlowObj>
## Inherits from: <commonDataObj>
## Public:
## annotation: data.table, data.frame
## annotCols: Patient Visit Days Grade
## checkIntegrity: function (reconcile = FALSE)
## clone: function (deep = FALSE)
## contextID: NULL
## initialize: function (annotation, qcData, mapVar = NULL, checkIntegrity = TRUE,
## mapVar: name
## markers: FSC.Height SSC.Height CD15.FITC CD45.PE CD14.PerCP CD33. ...
## objId: QCO-VEQAJ10
## qcData: data.table, data.frame
## returnMergedData: function ()
## setAnnotationDisplayOptions: function (annotCols)
## setMarkers: function (markers)
## setSubsetAndSortOptions: function (subsetOptions, sortOptions, checkIntegrity = TRUE)
## sortOptionList: NULL
## sortOptions: Patient Visit Days Grade
## subsetAnnotation: function (ids)
## subsetOptionList: list
## subsetOptions: Patient Visit Days Grade
Things to notice: QCO has three main slots: QCO$qcData, which holds the expression data, QCO$annotation, which holds the annotation, and QCO$mapVar, which is the key mapping QCO$annotation into QCO$data.
Additionally, there are multiple methods that alter display options. Once these are set, the UI elements are generated automatically from the object.
QCO$setAnnotationDisplayOptions() - this controls what annotation columns to display (supplied as a vector of column names) in the hover tooltip when you mouse over the heatmap. This method checks to see that the column names supplied exist within QCO$annotation.
QCO$setSubsetAndSortOptions() - this controls what columns to subset on and sort on (supplied as a vector of column names) in the subset module. This also checks to see that the column names exist in QCO$annotation.
Note that QCO has a slot called objId. This is the identifier used when using QCO in one of flowDashboard’s shiny modules. Having unique identfiers for each object helps to avoid namespace collisions in the shiny modules. By default, the identifer is randomly generated, though the user can override the default, either by specifying objId as an argument in the QCOfromGatingSet() function, or when invoking the modules separately. This objId lets the flowDashboard modules work together, or work separately (more on that later).
QCO$objId
## [1] "QCO-VEQAJ10"
If we use the returnMergedData() method, we can see the underlying merged data/annotation. We keep these two data tables separate in order to save space (avoiding redundant information), and because different display methods require either the annotation or the underlying data.
kable(QCO$returnMergedData()[1:15,])
| idVar | cellNum | variable | value | Patient | Visit | Days | Grade |
|---|---|---|---|---|---|---|---|
| s5a01 | 1679 | FSC.Height | 178 | 5 | 1 | -6 | 3 |
| s5a01 | 3117 | FSC.Height | 350 | 5 | 1 | -6 | 3 |
| s5a01 | 1847 | FSC.Height | 400 | 5 | 1 | -6 | 3 |
| s5a01 | 1140 | FSC.Height | 197 | 5 | 1 | -6 | 3 |
| s5a01 | 1576 | FSC.Height | 61 | 5 | 1 | -6 | 3 |
| s5a01 | 2326 | FSC.Height | 274 | 5 | 1 | -6 | 3 |
| s5a01 | 2419 | FSC.Height | 594 | 5 | 1 | -6 | 3 |
| s5a01 | 2053 | FSC.Height | 621 | 5 | 1 | -6 | 3 |
| s5a01 | 1491 | FSC.Height | 190 | 5 | 1 | -6 | 3 |
| s5a01 | 107 | FSC.Height | 60 | 5 | 1 | -6 | 3 |
| s5a01 | 2260 | FSC.Height | 183 | 5 | 1 | -6 | 3 |
| s5a01 | 492 | FSC.Height | 166 | 5 | 1 | -6 | 3 |
| s5a01 | 1091 | FSC.Height | 63 | 5 | 1 | -6 | 3 |
| s5a01 | 405 | FSC.Height | 62 | 5 | 1 | -6 | 3 |
| s5a01 | 3245 | FSC.Height | 281 | 5 | 1 | -6 | 3 |
Here we build the gatingObj from the GatingSet. We also create all of the relevant gating plots. Note that if you have a lot of samples and a lot of gates, the plotting can take a while.
#run this code if you want to generate the images as well
GO <- GOFromGatingSet(gs,imageDir = "data/gating/", makeGraphs = TRUE)
#graphs not generated in this vignette -run the above code if you want to
GO <- GOFromGatingSet(gs,imageDir = "data/gating/", makeGraphs = FALSE, objId="GO-UPCWK13")
##show structure of gatingObj
GO
## <gatingObj>
## Inherits from: <commonDataObj>
## Public:
## annotation: data.table, data.frame
## annotCols: name Patient Visit Days Grade Population Count
## checkIntegrity: function (reconcile = FALSE)
## clone: function (deep = FALSE)
## contextID: NULL
## gates: NULL
## imageDir: data/gating/
## initialize: function (annotation, popTable, mapVar = NULL, gates = NULL,
## mapVar: name
## objId: GO-UPCWK13
## popSubsets: list
## popTable: data.table, data.frame
## populations: rectangle CD15 FITC-CD45 PE+ CD15 FITC+CD45 PE+ CD15 FIT ...
## returnMergedData: function ()
## setAnnotationDisplayOptions: function (annotCols)
## setPopulations: function (popList)
## setPopulationSubset: function (subPopSets = NULL)
## setSubsetAndSortOptions: function (subsetOptions, sortOptions, checkIntegrity = TRUE)
## sortOptionList: NULL
## sortOptions: Patient Visit Days Grade
## subsetAnnotation: function (ids)
## subsetOptionList: list
## subsetOptions: Patient Visit Days Grade
Again, we can see the merged data table from GO by using the returnMergedData() method built into GO:
kable(GO$returnMergedData()[1:30,])
| name | Population | Parent | Count | ParentCount | idVar | percentPop | zscore | popKey | Patient | Visit | Days | Grade |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| s5a01 | rectangle | root | 97 | 3420 | s5a01+rectangle+GO-UPCWK13 | 2.8362573 | 0.3298607 | s5a01+rectangle | 5 | 1 | -6 | 3 |
| s5a01 | CD15 FITC-CD45 PE+ | rectangle | 0 | 97 | s5a01+CD15 FITCnegCD45 PEpos+GO-UPCWK13 | 0.0000000 | -0.3904334 | s5a01+CD15 FITC-CD45 PE+ | 5 | 1 | -6 | 3 |
| s5a01 | CD15 FITC+CD45 PE+ | rectangle | 89 | 97 | s5a01+CD15 FITCposCD45 PEpos+GO-UPCWK13 | 91.7525773 | -0.1272707 | s5a01+CD15 FITC+CD45 PE+ | 5 | 1 | -6 | 3 |
| s5a01 | CD15 FITC+CD45 PE- | rectangle | 6 | 97 | s5a01+CD15 FITCposCD45 PEneg+GO-UPCWK13 | 6.1855670 | 1.0150601 | s5a01+CD15 FITC+CD45 PE- | 5 | 1 | -6 | 3 |
| s5a01 | CD15 FITC-CD45 PE- | rectangle | 2 | 97 | s5a01+CD15 FITCnegCD45 PEneg+GO-UPCWK13 | 2.0618557 | -0.1072787 | s5a01+CD15 FITC-CD45 PE- | 5 | 1 | -6 | 3 |
| s5a02 | rectangle | root | 54 | 3405 | s5a02+rectangle+GO-UPCWK13 | 1.5859031 | -0.1554846 | s5a02+rectangle | 5 | 2 | 0 | 3 |
| s5a02 | CD15 FITC-CD45 PE+ | rectangle | 0 | 54 | s5a02+CD15 FITCnegCD45 PEpos+GO-UPCWK13 | 0.0000000 | -0.3904334 | s5a02+CD15 FITC-CD45 PE+ | 5 | 2 | 0 | 3 |
| s5a02 | CD15 FITC+CD45 PE+ | rectangle | 46 | 54 | s5a02+CD15 FITCposCD45 PEpos+GO-UPCWK13 | 85.1851852 | -0.6216961 | s5a02+CD15 FITC+CD45 PE+ | 5 | 2 | 0 | 3 |
| s5a02 | CD15 FITC+CD45 PE- | rectangle | 1 | 54 | s5a02+CD15 FITCposCD45 PEneg+GO-UPCWK13 | 1.8518519 | -0.1657054 | s5a02+CD15 FITC+CD45 PE- | 5 | 2 | 0 | 3 |
| s5a02 | CD15 FITC-CD45 PE- | rectangle | 7 | 54 | s5a02+CD15 FITCnegCD45 PEneg+GO-UPCWK13 | 12.9629630 | 0.8219709 | s5a02+CD15 FITC-CD45 PE- | 5 | 2 | 0 | 3 |
| s5a03 | rectangle | root | 11 | 3435 | s5a03+rectangle+GO-UPCWK13 | 0.3202329 | -0.6467750 | s5a03+rectangle | 5 | 3 | 6 | 3 |
| s5a03 | CD15 FITC-CD45 PE+ | rectangle | 0 | 11 | s5a03+CD15 FITCnegCD45 PEpos+GO-UPCWK13 | 0.0000000 | -0.3904334 | s5a03+CD15 FITC-CD45 PE+ | 5 | 3 | 6 | 3 |
| s5a03 | CD15 FITC+CD45 PE+ | rectangle | 7 | 11 | s5a03+CD15 FITCposCD45 PEpos+GO-UPCWK13 | 63.6363636 | -2.2439970 | s5a03+CD15 FITC+CD45 PE+ | 5 | 3 | 6 | 3 |
| s5a03 | CD15 FITC+CD45 PE- | rectangle | 1 | 11 | s5a03+CD15 FITCposCD45 PEneg+GO-UPCWK13 | 9.0909091 | 1.8066506 | s5a03+CD15 FITC+CD45 PE- | 5 | 3 | 6 | 3 |
| s5a03 | CD15 FITC-CD45 PE- | rectangle | 3 | 11 | s5a03+CD15 FITCnegCD45 PEneg+GO-UPCWK13 | 27.2727273 | 2.0417866 | s5a03+CD15 FITC-CD45 PE- | 5 | 3 | 6 | 3 |
| s5a04 | rectangle | root | 33 | 8550 | s5a04+rectangle+GO-UPCWK13 | 0.3859649 | -0.6212600 | s5a04+rectangle | 5 | 4 | 12 | 3 |
| s5a04 | CD15 FITC-CD45 PE+ | rectangle | 0 | 33 | s5a04+CD15 FITCnegCD45 PEpos+GO-UPCWK13 | 0.0000000 | -0.3904334 | s5a04+CD15 FITC-CD45 PE+ | 5 | 4 | 12 | 3 |
| s5a04 | CD15 FITC+CD45 PE+ | rectangle | 31 | 33 | s5a04+CD15 FITCposCD45 PEpos+GO-UPCWK13 | 93.9393939 | 0.0373636 | s5a04+CD15 FITC+CD45 PE+ | 5 | 4 | 12 | 3 |
| s5a04 | CD15 FITC+CD45 PE- | rectangle | 2 | 33 | s5a04+CD15 FITCposCD45 PEneg+GO-UPCWK13 | 6.0606061 | 0.9810132 | s5a04+CD15 FITC+CD45 PE- | 5 | 4 | 12 | 3 |
| s5a04 | CD15 FITC-CD45 PE- | rectangle | 0 | 33 | s5a04+CD15 FITCnegCD45 PEneg+GO-UPCWK13 | 0.0000000 | -0.2830387 | s5a04+CD15 FITC-CD45 PE- | 5 | 4 | 12 | 3 |
| s5a05 | rectangle | root | 371 | 10410 | s5a05+rectangle+GO-UPCWK13 | 3.5638809 | 0.6122996 | s5a05+rectangle | 5 | 5 | 19 | 3 |
| s5a05 | CD15 FITC-CD45 PE+ | rectangle | 0 | 371 | s5a05+CD15 FITCnegCD45 PEpos+GO-UPCWK13 | 0.0000000 | -0.3904334 | s5a05+CD15 FITC-CD45 PE+ | 5 | 5 | 19 | 3 |
| s5a05 | CD15 FITC+CD45 PE+ | rectangle | 367 | 371 | s5a05+CD15 FITCposCD45 PEpos+GO-UPCWK13 | 98.9218329 | 0.4124660 | s5a05+CD15 FITC+CD45 PE+ | 5 | 5 | 19 | 3 |
| s5a05 | CD15 FITC+CD45 PE- | rectangle | 3 | 371 | s5a05+CD15 FITCposCD45 PEneg+GO-UPCWK13 | 0.8086253 | -0.4499432 | s5a05+CD15 FITC+CD45 PE- | 5 | 5 | 19 | 3 |
| s5a05 | CD15 FITC-CD45 PE- | rectangle | 1 | 371 | s5a05+CD15 FITCnegCD45 PEneg+GO-UPCWK13 | 0.2695418 | -0.2600620 | s5a05+CD15 FITC-CD45 PE- | 5 | 5 | 19 | 3 |
| s5a06 | rectangle | root | 45 | 3750 | s5a06+rectangle+GO-UPCWK13 | 1.2000000 | -0.3052791 | s5a06+rectangle | 5 | 6 | 26 | 3 |
| s5a06 | CD15 FITC-CD45 PE+ | rectangle | 0 | 45 | s5a06+CD15 FITCnegCD45 PEpos+GO-UPCWK13 | 0.0000000 | -0.3904334 | s5a06+CD15 FITC-CD45 PE+ | 5 | 6 | 26 | 3 |
| s5a06 | CD15 FITC+CD45 PE+ | rectangle | 42 | 45 | s5a06+CD15 FITCposCD45 PEpos+GO-UPCWK13 | 93.3333333 | -0.0082636 | s5a06+CD15 FITC+CD45 PE+ | 5 | 6 | 26 | 3 |
| s5a06 | CD15 FITC+CD45 PE- | rectangle | 3 | 45 | s5a06+CD15 FITCposCD45 PEneg+GO-UPCWK13 | 6.6666667 | 1.1461407 | s5a06+CD15 FITC+CD45 PE- | 5 | 6 | 26 | 3 |
| s5a06 | CD15 FITC-CD45 PE- | rectangle | 0 | 45 | s5a06+CD15 FITCnegCD45 PEneg+GO-UPCWK13 | 0.0000000 | -0.2830387 | s5a06+CD15 FITC-CD45 PE- | 5 | 6 | 26 | 3 |
Finally, we build a populationExpressionObj called PEO from the GatingSet. We limit our samples to
PEO <- PEOFromGatingSet(gs, samplePop = 1000)
PEO
## <populationExpressionObj>
## Inherits from: <commonDataObj>
## Public:
## annotation: data.table, data.frame
## annotCols: Patient Visit Days Grade
## checkIntegrity: function (reconcile = FALSE)
## clone: function (deep = FALSE)
## contextID: NULL
## expressionData: data.table, data.frame
## initialize: function (annotation, expressionData, mapVar = NULL, checkIntegrity = TRUE,
## mapVar: name
## markers: FSC-Height SSC-Height CD15 FITC CD45 PE CD14 PerCP FL2-A ...
## objId: PEO-DGWYR90
## populations: rectangle CD15 FITC-CD45 PE+ CD15 FITC+CD45 PE+ CD15 FIT ...
## returnMergedData: function ()
## setAnnotationDisplayOptions: function (annotCols)
## setMarkers: function (markers)
## setSubsetAndSortOptions: function (subsetOptions, sortOptions, checkIntegrity = TRUE)
## sortOptionList: NULL
## sortOptions: Patient Visit Days Grade
## subsetAnnotation: function (ids)
## subsetOptionList: list
## subsetOptions: Patient Visit Days Grade
We want to remove Time as a marker from PEO:
markers <- as.character(PEO$markers)
markers
## [1] "FSC-Height" "SSC-Height" "CD15 FITC"
## [4] "CD45 PE" "CD14 PerCP" "FL2-A"
## [7] "CD33 APC" "Time (51.20 sec.)"
PEO$setMarkers(markers[1:7])
Viewing the merged data table from PEO:
kable(PEO$returnMergedData()[1:30,])
| cell | idVar | variable | value | Population | Patient | Visit | Days | Grade |
|---|---|---|---|---|---|---|---|---|
| 1 | s5a01 | FSC-Height | 371 | rectangle | 5 | 1 | -6 | 3 |
| 2 | s5a01 | FSC-Height | 236 | rectangle | 5 | 1 | -6 | 3 |
| 3 | s5a01 | FSC-Height | 269 | rectangle | 5 | 1 | -6 | 3 |
| 4 | s5a01 | FSC-Height | 259 | rectangle | 5 | 1 | -6 | 3 |
| 5 | s5a01 | FSC-Height | 232 | rectangle | 5 | 1 | -6 | 3 |
| 6 | s5a01 | FSC-Height | 201 | rectangle | 5 | 1 | -6 | 3 |
| 7 | s5a01 | FSC-Height | 240 | rectangle | 5 | 1 | -6 | 3 |
| 8 | s5a01 | FSC-Height | 380 | rectangle | 5 | 1 | -6 | 3 |
| 9 | s5a01 | FSC-Height | 206 | rectangle | 5 | 1 | -6 | 3 |
| 10 | s5a01 | FSC-Height | 213 | rectangle | 5 | 1 | -6 | 3 |
| 11 | s5a01 | FSC-Height | 276 | rectangle | 5 | 1 | -6 | 3 |
| 12 | s5a01 | FSC-Height | 217 | rectangle | 5 | 1 | -6 | 3 |
| 13 | s5a01 | FSC-Height | 239 | rectangle | 5 | 1 | -6 | 3 |
| 14 | s5a01 | FSC-Height | 232 | rectangle | 5 | 1 | -6 | 3 |
| 15 | s5a01 | FSC-Height | 211 | rectangle | 5 | 1 | -6 | 3 |
| 16 | s5a01 | FSC-Height | 226 | rectangle | 5 | 1 | -6 | 3 |
| 17 | s5a01 | FSC-Height | 247 | rectangle | 5 | 1 | -6 | 3 |
| 18 | s5a01 | FSC-Height | 229 | rectangle | 5 | 1 | -6 | 3 |
| 19 | s5a01 | FSC-Height | 264 | rectangle | 5 | 1 | -6 | 3 |
| 20 | s5a01 | FSC-Height | 205 | rectangle | 5 | 1 | -6 | 3 |
| 21 | s5a01 | FSC-Height | 218 | rectangle | 5 | 1 | -6 | 3 |
| 22 | s5a01 | FSC-Height | 223 | rectangle | 5 | 1 | -6 | 3 |
| 23 | s5a01 | FSC-Height | 204 | rectangle | 5 | 1 | -6 | 3 |
| 24 | s5a01 | FSC-Height | 209 | rectangle | 5 | 1 | -6 | 3 |
| 25 | s5a01 | FSC-Height | 226 | rectangle | 5 | 1 | -6 | 3 |
| 26 | s5a01 | FSC-Height | 247 | rectangle | 5 | 1 | -6 | 3 |
| 27 | s5a01 | FSC-Height | 205 | rectangle | 5 | 1 | -6 | 3 |
| 28 | s5a01 | FSC-Height | 206 | rectangle | 5 | 1 | -6 | 3 |
| 29 | s5a01 | FSC-Height | 202 | rectangle | 5 | 1 | -6 | 3 |
| 30 | s5a01 | FSC-Height | 300 | rectangle | 5 | 1 | -6 | 3 |
Save all objects into a new Rda:
save(PEO, GO, QCO, file="data/GvHD.rda")
The reference shiny app can be seen at https://tladeras.shinyapps.io/sampleFlowDashboard/
In the app, in our server.R, we extract the annotation in order to make it a reactive that is subsettable and that has a common interface.
For example, for our gatingObj GO, we create the following subsetModule, which is used as an input for the gatingModuleOutput module created by gatingModuleOutputGGFromGO(). Note that we just pass the reactive name annotationGO and not the evaluation annotationGO().
#look for this code in server.R
annotationGO <- subsetModuleDCO(input, output, dataObj = GO)
gatingModuleOutputGGFromGO(input, output, session, GO, annotation=annotationGO)
In ui.R, there is a corresponding entry that generates the subsetting UI, and the UI for the gatingModule itself:
#this is put in a conditional panel to work with shinydashboard
subsetModuleUICDO(GO)
#this is put into a tabPanel
gatingModuleUIFromGO(GO)
If you don’t want to use the subsetModule for a visualization, you can do the following in your server.R to generate an annotation reactive. Note that gatingModuleOutputGGFromGO expects a reactive in its annotation argument.
annotationGO <- reactive({GO$annotation})
gatingModuleOutputGGFromGO(input, output, session, GO, annotation=annotationGO)
And put this in your ui.R:
#this is put into a tabPanel
gatingModuleUIFromGO(GO)