Steady-state analysis of flow cytometry data

R Clay Wright

2023-10-24

This vignette will guide you through analysis of an example flow cytometry data set from an experiment examining the fluorescent reporter levels of a synthetic biological circuit in liquid cultures of budding yeast. Here, we analyze a circuit in which a florescent reporter is fused to a protein that is degraded over time after addition of an inducer molecule. At some time post-induction (as optimized by the experimenter) fluorescence of these cultures is analyzed by flow cytometry. Here we demonstrate how to import the resulting .fcs files into R, annotate this data with experimental metadata (e.g. the strain and treatment for each sample), and compile the relevant events and measurements.

#Importing and annotating data Import your flow cytometry data using read.flowset. Here, we will import an example flowSet.

plate1 <- read.flowSet(path = system.file("extdata", "ss_example", package = "flowTime"),
    alter.names = TRUE)
# add plate numbers to the sampleNames
sampleNames(plate1) <- paste("1_", sampleNames(plate1), sep = "")
dat <- plate1

If you have several plates this code can be repeated and each plate can be combined to assemble the full data set.

plate2 <- read.flowSet(path = paste(experiment, "_2/", sep = ""), alter.names = TRUE)
sampleNames(plate2) <- paste("2_", sampleNames(plate2), sep = "")
dat <- rbind2(plate1, plate2)

For this example, we will import the table of metadata. The sampleNames of the assembled flowSet (dat in this example) must match that of a unique identifier column of annotation.

annotation <- read.csv(system.file("extdata", "ss_example.csv", package = "flowTime"))
head(annotation)
#>           X      name  AFB   IAA treatment repl
#> 1 1_A01.fcs 1_A01.fcs TIR1  IAA1      0.00    1
#> 2 1_A02.fcs 1_A02.fcs TIR1 IAA17      0.00    1
#> 3 1_A03.fcs 1_A03.fcs AFB2  IAA1      0.00    1
#> 4 1_A04.fcs 1_A04.fcs AFB2 IAA17      0.00    1
#> 5 1_B01.fcs 1_B01.fcs TIR1  IAA1      0.05    1
#> 6 1_B02.fcs 1_B02.fcs TIR1 IAA17      0.05    1
sampleNames(dat)
#>  [1] "1_A01.fcs" "1_A02.fcs" "1_A03.fcs" "1_A04.fcs" "1_B01.fcs" "1_B02.fcs"
#>  [7] "1_B03.fcs" "1_B04.fcs" "1_C01.fcs" "1_C02.fcs" "1_C03.fcs" "1_C04.fcs"
#> [13] "1_D01.fcs" "1_D02.fcs" "1_D03.fcs" "1_D04.fcs" "1_E01.fcs" "1_E02.fcs"
#> [19] "1_E03.fcs" "1_E04.fcs" "1_F01.fcs" "1_F02.fcs" "1_F03.fcs" "1_F04.fcs"
#> [25] "1_G01.fcs" "1_G02.fcs" "1_G03.fcs" "1_G04.fcs" "1_H01.fcs" "1_H02.fcs"
#> [31] "1_H03.fcs" "1_H04.fcs"
sampleNames(dat) == annotation$name
#>  [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
#> [16] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
#> [31] TRUE TRUE

We can also create this column from our data set and attach the annotation columns. Alternatively one can use the createAnnotation function to create a data frame with the appropriate name column that can then be filled in via R-code or saved as a csv file and filled via a spreadsheet editor. The order of the entries in annotation does not matter, so long as each entry in sampleNames(dat) is represented. The annotateFlowSet function will match entries by the mergeBy column

annotation <- cbind(annotation, name = sampleNames(dat))
# or
annotation <- createAnnotation(yourFlowSet = dat)
write.csv(annotation, file = "path/to/yourAnnotation.csv")

Finally we can attach this metadata to the flowSet using the annotateFlowSet function.

adat <- annotateFlowSet(yourFlowSet = dat, annotation_df = annotation, mergeBy = "name")
head(rownames(pData(adat)))
#> [1] "1_A01.fcs" "1_A02.fcs" "1_A03.fcs" "1_A04.fcs" "1_B01.fcs" "1_B02.fcs"
head(pData(adat))
#>                name         X  AFB   IAA treatment repl
#> 1_A01.fcs 1_A01.fcs 1_A01.fcs TIR1  IAA1      0.00    1
#> 1_A02.fcs 1_A02.fcs 1_A02.fcs TIR1 IAA17      0.00    1
#> 1_A03.fcs 1_A03.fcs 1_A03.fcs AFB2  IAA1      0.00    1
#> 1_A04.fcs 1_A04.fcs 1_A04.fcs AFB2 IAA17      0.00    1
#> 1_B01.fcs 1_B01.fcs 1_B01.fcs TIR1  IAA1      0.05    1
#> 1_B02.fcs 1_B02.fcs 1_B02.fcs TIR1 IAA17      0.05    1

Now we can save this flowSet and anyone in perpetuity can load and analyze this annotated flowSet with ease!

write.flowSet(adat, outdir = "your/favorite/directory")

# Read the flowSet with the saved experimental meta data
read.flowSet("flowSet folder", path = "your/flow/directory", phenoData = "annotation.txt",
    alter.names = TRUE)

#Compiling and plotting data Now we are ready to analyze the raw data in this flowSet. First we load the set of gates that will be used to subset our data. To analyze this steady-state or single time point experiment we will use the steadyState function. This function will gate each flowFrame in the flowSet and compile and return a dataframe of the relevant data and metadata for each event. This dataframe can then be used to visualize the full data set.

loadGates()  # use the default included gateSet
dat.SS <- steadyState(flowset = adat, ploidy = "diploid", only = "singlets")
#> [1] "Gating with diploid singlet gates..."
#> [1] "Converting events..."

p <- ggplot(dat.SS, aes(x = as.factor(treatment), y = FL2.A, fill = AFB)) + geom_boxplot(outlier.shape = NA) +
    facet_grid(IAA ~ AFB) + theme_classic(base_family = "Arial", base_size = 16) +
    ylim(c(-1000, 10000)) + xlab(expression(paste("Auxin (", mu, "M)", sep = ""))) +
    ylab("Fluorescence (AU)") + theme(legend.position = "none")
p
#> Warning: Removed 85 rows containing non-finite values (`stat_boxplot()`).