-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRedditExample_CompensationR.qmd
248 lines (197 loc) · 8.26 KB
/
RedditExample_CompensationR.qmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
---
title: "Cytometry in R:"
subtitle: "Compensation in flowCore"
date: "10/22/2024"
layout: full
format:
html: default
toc: true
toc-location: right
fig-cap-location: top
embed-resources: TRUE
---
# Getting Set Up
If you haven't already, please go ahead and install the following packages:
```{r}
#| eval: FALSE
#| code-fold: show
#|
# If not yet done so, install required packages
install.packages("BiocManager")
install.packages("BiocStyle")
BiocManager::install("flowCore")
BiocManager::install("ggcyto")
BiocManager::install("FlowSOM")
```
Once installed, load the required packages into R by calling library.
```{r}
#| code-fold: show
#| message: false
library(flowCore)
library(ggcyto)
library(BiocStyle)
library(FlowSOM)
```
For this example, I am using an .fcs file contained within the `r Biocpkg("FlowSOM")` package's extdata folder. I find it using system.file, and then list.files to show the full path to it's location. Once it's located, I will load it into a flowframe via flowCore similar to what we can see in the Christopher Hall video.
```{r}
#| code-fold: show
File_Location <- system.file("extdata", package = "FlowSOM")
FCSFile_Example <- list.files(File_Location, pattern="fcs", full.names=TRUE)
flowframe <- read.FCS(FCSFile_Example, transformation = FALSE, truncate_max_range = FALSE)
```
If you have your own .fcs file, instead of system.file I usually will use file.path to indicate the location. For example:
```{r}
#| eval: FALSE
#| code-fold: show
Location <- file.path("C:", "Users", "StepUpCytometry", "Desktop", "TodaysExperiment")
ExperimentFCSFiles <- list.files(Location, pattern=".fcs", full.names=TRUE)
flowframe <- read.FCS(FCSFile_Example[1], transformation = FALSE, truncate_max_range = FALSE)
```
# flowFrame objects
Once you have loaded the .fcs file into a flowframe, let's quickly poke around to see what this kind of object looks like in R.
```{r}
#| code-fold: show
flowframe
```
Within `r Biocpkg("flowCore")` flowframe and flowset objects, the information for an individual .fcs file is contained within exprs (data), parameters and description (keywords). For this example I will abbreviate them to the first 10 entries, if you want to see the full entries, run the code-chunks below on your own computer.
```{r}
#| eval: false
#| code-fold: show
View(flowframe@description)
```
```{r}
#| echo: FALSE
Example <- flowframe@description
head(Example, 10)
```
Description (keywords) is a named list containing everything from voltage settings, compensation matrix, metadata, software configurations, etc.
```{r}
#| eval: false
#| code-fold: show
View(flowframe@parameters@data)
```
```{r}
#| echo: FALSE
Example <- flowframe@parameters@data
Example
```
Parameters is one of the many locations containing the name of the fluorophore, and the ligand name.
```{r}
#| eval: false
#| code-fold: show
View(flowframe@exprs)
```
```{r}
#| echo: FALSE
Example <- flowframe@exprs
head(Example, 10)
```
And exprs contains the actual raw data, with each row representing the measurements of an individual cell.
# Applying Compensation
For the question of compensation, the compensation matrix is stored under keyword "SPILL" within the description (keyword) list and is a matrix object.
```{r}
#| code-fold: show
flowframe@description[["SPILL"]]
```
In the case of Christopher Hall's video #2's example, if we look at the initial data (from flowframe@exprs) we can see the initial values for the first ten cells
```{r}
Example <- flowframe@exprs
head(Example, 10)
```
And after compensation, we can compare the values to see how they change once compensation is applied:
```{r}
TheComps <- spillover(flowframe)
flowframe_comped <- compensate(flowframe, TheComps[[1]])
head(flowframe_comped@exprs, 10)
```
As you might be able to tell, FSC SSC parameters remain the same, while the values for the Fluorophore columns have been adjusted. This is due to no columns being present for FSC SSC Time etc. in the Spillover matrix.
# Visualizing (ggcyto)
We can visualize this with the with the `r Biocpkg("ggcyto")` package to see the effects for the before vs. after:
```{r}
#| code-fold: show
autoplot(flowframe, x = "PE-Cy7-A", y = "PE-Texas Red-A", bins = 270) +
scale_x_flowjo_biexp() + scale_y_flowjo_biexp() + theme_bw()
```
```{r}
#| code-folde: show
autoplot(flowframe_comped, x = "PE-Cy7-A", y = "PE-Texas Red-A", bins = 270) +
scale_x_flowjo_biexp() + scale_y_flowjo_biexp() + theme_bw()
```
# Applying an External Compensation Matrix.
The above works great when the acquisition software already stored the compensation matrix in the SPILL keyword. But what happens when it is not there, or we want to apply an external compensation matrix? It can be done, but there is a bit more data-tidying that needs to be done first to make the .csv output from FlowJo compatible with the matrix format flowCore stores FILL as. To save someone who is just getting started a headache, here is a worked out example below:
If we look closer at what type of object is returned by spillover, we can see that the initial command is returning three list:
```{r}
#| code-fold: show
TheComps <- spillover(flowframe)
TheComps
```
And that the first item that we passed to compensate is the matrix array object containing the spillover/compensation matrix. If we didn't have it in the fcs file to begin with (either due to a difference in acquisition software, or desire to apply a separate compensation matrix you generated elsewhere), you could format it similarly and swap it in.
```{r}
#| code-fold: show
TheComps[[1]]
class(TheComps[[1]])
```
In the case of the FlowSOM example file, the compensation applied appears to be mostly correct. The closest example to an overcompensation was the following:
```{r}
#| code-fold: show
autoplot(flowframe_comped, x = "Qdot 605-A", y = "Alexa Fluor 700-A", bins = 270) +
scale_x_flowjo_biexp() + scale_y_flowjo_biexp() + theme_bw()
```
In FlowJo, I edited the compensation matrix and then hit Save Matrix and saved as a .csv. This can then be imported into R on an individual computer something similar to as follows:
```{r}
#| eval: FALSE
#| code-show: TRUE
# Set Location for your own folder
Location <- file.path("C:", "Users", "StepUpCytometry", "Desktop", "MyCompensations")
TheMatrix <- list.files(Location, pattern = ".csv", full.names = TRUE)
MyMatrixOfInterest <- TheMatrix[4] # Ie, the 4th .csv file in the Matrix list above
```
```{r}
#| code-show: TRUE
MyCompensation <- read.csv("MyComp.csv", check.names=FALSE)
MyCompensation
```
If we compare the above to the matrix currently stored in spillover, we can see a couple potential issues, namely, the FlowJo exported .csv has the names of the ligands still included; and the row.names column is still present.
```{r}
#| code-show: TRUE
TheComps[1]
```
We could of course edit this manually by hand, or we can have R do it. First we remove the row name column:
```{r}
#| code-show: TRUE
MyCompensation <- MyCompensation[-1] #Removed the first rowname column
colnames(MyCompensation)
```
With that done, we remove everything within the column names that is present after -A:
```{r}
#| code-show: TRUE
colnames(MyCompensation) <- sub("-A.*", "-A", colnames(MyCompensation))
colnames(MyCompensation)
```
And finally, we convert it from a data.frame to a matrix
```{r}
MyCompensation <- as.matrix(MyCompensation)
MyCompensation
```
Now, returning to the original example of applying the spillover, we provide the external:
```{r}
flowframe_ExternalComp <- compensate(flowframe, MyCompensation)
```
And visualize the effect before and after:
```{r}
#| code-fold: show
autoplot(flowframe_comped, x = "Qdot 605-A", y = "Alexa Fluor 700-A", bins = 270) +
scale_x_flowjo_biexp() + scale_y_flowjo_biexp() + theme_bw()
```
```{r}
#| code-fold: show
autoplot(flowframe_ExternalComp, x = "Qdot 605-A", y = "Alexa Fluor 700-A", bins = 270) +
scale_x_flowjo_biexp() + scale_y_flowjo_biexp() + theme_bw()
```
Notice it did move (still ugly-ish but I only barely adjusted the compensation matrix due to lack of time).
Hope this helps clarify a little!!! Keep it up!
# System Information
```{r}
#| code-fold: show
sessionInfo()
```