DillonHammill / CytoExploreR

Interactive Cytometry Data Analysis
61 stars 13 forks source link

Logic gates #16

Closed Mieszkol closed 4 years ago

Mieszkol commented 4 years ago

Hi Dillon, Great work here! However, I can't find any information about logic gates (tried using standard R operators). Is there a possibility to use them in your software?

Mieszko

DillonHammill commented 4 years ago

@Mieszkol, yes this is fully supported!

At the moment cyto_gate_draw() only supports negated (and) boolean gates through its negate argument. This will automatically take care of the boolean entry in the gatingTemplate.

Boolean gates are supported in openCyto, which means that you can add them to your gatingTemplate as well! To interactively add boolean gates to your gatingTemplate you can use cyto_gatingTemplate_edit() which will update the gatingTemplate and samples.

# gs is a GatingSet
gs

# Add boolean entry
cyto_gatingTemplate_edit(gs, "gatingTemplate.csv")

To add a boolean entry:

  1. Give the boolean population a name in the alias column.
  2. Set pop to +.
  3. Set parent to the population to be gated.
  4. Set the channels in which the gates have been constructed to 'dims'.
  5. Set gating_method to boolGate.
  6. Set gating_args with boolean logic using population names (e.g. CD4+|CD8+). You can conventional boolean operators such as NOT (!), OR (|) or AND (&).
  7. Remaining arguments may be left empty and the table editor can be closed. The gatingTemplate and associated GatingSet will be updated accordingly.

Let me know if you need help with your specific use case.

Happy to help!

Mieszkol commented 4 years ago

Thank you so much for an immediate answer! It works like a charm!

Chris8886 commented 4 years ago

@DillonHammill I tried to follow the instructions above but I keep getting an error: Error in.rowNamesDF<-(x, value = value) : invalid 'row.names' length I guess it's caused by adding a new row to create a boolean gate entry? Could you help me with that?

DillonHammill commented 4 years ago

@Chris8886, I can give you a hand if you provide either the gatingTemplate or tree structure (e.g. screenshot cyto_plot_gating_tree()) and tell me what you hope to achieve.

Chris8886 commented 4 years ago

Thank you!

Let's say I want to create a gate with all CD56dim cells positive for any KIR. I tried to add following entry (last row)

`

alias pop parent dims gating_method gating_args collapseDataForGating groupBy preprocessing_method preprocessing_args
Cells + root FSC-A,SSC-A cyto_gate_draw gate = list('Combined Events' = new('filters', .Data = list(new('polygonGate', boundaries = structure(c(63513.3554114528, 49332.6613325908, 60504.9171952019, 100267.538050383, 126722.29731597, 125620.487991857, 1867.66931150138, 24593.4224580394, 50573.0402924404, 55712.7785081037, 33502.4648879464, 13566.4365713929), .Dim = c(6L, 2L), .Dimnames = list( NULL, c('FSC-A', 'SSC-A'))), parameters = new('parameters', .Data = list(new('unitytransform', .Data = function () NULL, parameters = 'FSC-A', transformationId = 'defaultUnityTransform'), new('unitytransform', .Data = function () NULL, parameters = 'SSC-A', transformationId = 'defaultUnityTransform'))), filterId = 'Cells')))), openCyto.minEvents = -1 TRUE   pp_cyto_gate_draw  
Single Cells + Cells FSC-A,FSC-H cyto_gate_draw gate = list('Combined Events' = new('filters', .Data = list(new('polygonGate', boundaries = structure(c(43342.9900685855, 86576.5370044606, 130295.242778525, 124158.210185163, 37897.4221745125, 27439.3326392409, 57754.9938827685, 111084.66355299, 119827.592770604, 40892.0599936411 ), .Dim = c(5L, 2L), .Dimnames = list(NULL, c('FSC-A', 'FSC-H' ))), parameters = new('parameters', .Data = list(new('unitytransform', .Data = function () NULL, parameters = 'FSC-A', transformationId = 'defaultUnityTransform'), new('unitytransform', .Data = function () NULL, parameters = 'FSC-H', transformationId = 'defaultUnityTransform'))), filterId = 'Single Cells')))), openCyto.minEvents = -1 TRUE   pp_cyto_gate_draw  
NK + Single Cells V525-A,UV379-A cyto_gate_draw gate = list('Combined Events' = new('filters', .Data = list(new('rectangleGate', min = c('V525-A' = 1.04596725284356, 'UV379-A' = 2.04199352320796 ), max = c('V525-A' = 2.02877454985462, 'UV379-A' = 4.24275005980313 ), parameters = new('parameters', .Data = list(new('unitytransform', .Data = function () NULL, parameters = 'V525-A', transformationId = 'defaultUnityTransform'), new('unitytransform', .Data = function () NULL, parameters = 'UV379-A', transformationId = 'defaultUnityTransform'))), filterId = 'NK')))), openCyto.minEvents = -1 TRUE   pp_cyto_gate_draw  
CD56bright + NK V525-A,UV379-A cyto_gate_draw gate = list('Combined Events' = new('filters', .Data = list(new('rectangleGate', min = c('V525-A' = 0.911107204625442, 'UV379-A' = 3.59689657520001 ), max = c('V525-A' = 2.03733941060217, 'UV379-A' = 4.35368508713688 ), parameters = new('parameters', .Data = list(new('unitytransform', .Data = function () NULL, parameters = 'V525-A', transformationId = 'defaultUnityTransform'), new('unitytransform', .Data = function () NULL, parameters = 'UV379-A', transformationId = 'defaultUnityTransform'))), filterId = 'CD56bright')))), openCyto.minEvents = -1 TRUE   pp_cyto_gate_draw  
CD56dim + NK V525-A,UV379-A cyto_gate_draw gate = list('Combined Events' = new('filters', .Data = list(new('rectangleGate', min = c('V525-A' = 0.909161331917372, 'UV379-A' = 1.94522986496242 ), max = c('V525-A' = 2.05368474134996, 'UV379-A' = 3.44232670458443 ), parameters = new('parameters', .Data = list(new('unitytransform', .Data = function () NULL, parameters = 'V525-A', transformationId = 'defaultUnityTransform'), new('unitytransform', .Data = function () NULL, parameters = 'UV379-A', transformationId = 'defaultUnityTransform'))), filterId = 'CD56dim')))), openCyto.minEvents = -1 TRUE   pp_cyto_gate_draw  
KIR2DL1+ + CD56dim R780-A,FSC-H cyto_gate_draw gate = list('Combined Events' = new('filters', .Data = list(new('rectangleGate', min = c('R780-A' = 2.35154492306975, 'FSC-H' = 34474.7157481336 ), max = c('R780-A' = 3.83891890666439, 'FSC-H' = 120834.043409793 ), parameters = new('parameters', .Data = list(new('unitytransform', .Data = function () NULL, parameters = 'R780-A', transformationId = 'defaultUnityTransform'), new('unitytransform', .Data = function () NULL, parameters = 'FSC-H', transformationId = 'defaultUnityTransform'))), filterId = 'KIR2DL1+')))), openCyto.minEvents = -1 TRUE   pp_cyto_gate_draw  
KIR2DL1- + CD56dim R780-A,FSC-H cyto_gate_draw gate = list('Combined Events' = new('filters', .Data = list(new('rectangleGate', min = c('R780-A' = -0.210588901225994, 'FSC-H' = 29383.8343596154 ), max = c('R780-A' = 1.40504167321731, 'FSC-H' = 127009.546360932 ), parameters = new('parameters', .Data = list(new('unitytransform', .Data = function () NULL, parameters = 'R780-A', transformationId = 'defaultUnityTransform'), new('unitytransform', .Data = function () NULL, parameters = 'FSC-H', transformationId = 'defaultUnityTransform'))), filterId = 'KIR2DL1-')))), openCyto.minEvents = -1 TRUE   pp_cyto_gate_draw  
KIR2DL2_3+ + CD56dim YG710-A,FSC-H cyto_gate_draw gate = list('Combined Events' = new('filters', .Data = list(new('rectangleGate', min = c('YG710-A' = 1.81818025078975, 'FSC-H' = 32527.7711864019 ), max = c('YG710-A' = 3.71810124845066, 'FSC-H' = 121410.553970105 ), parameters = new('parameters', .Data = list(new('unitytransform', .Data = function () NULL, parameters = 'YG710-A', transformationId = 'defaultUnityTransform'), new('unitytransform', .Data = function () NULL, parameters = 'FSC-H', transformationId = 'defaultUnityTransform'))), filterId = 'KIR2DL2_3+')))), openCyto.minEvents = -1 TRUE   pp_cyto_gate_draw  
KIR2DL2_3- + CD56dim YG710-A,FSC-H cyto_gate_draw gate = list('Combined Events' = new('filters', .Data = list(new('rectangleGate', min = c('YG710-A' = -0.303008665341752, 'FSC-H' = 29310.5491188978 ), max = c('YG710-A' = 1.16130306935736, 'FSC-H' = 124713.275485113 ), parameters = new('parameters', .Data = list(new('unitytransform', .Data = function () NULL, parameters = 'YG710-A', transformationId = 'defaultUnityTransform'), new('unitytransform', .Data = function () NULL, parameters = 'FSC-H', transformationId = 'defaultUnityTransform'))), filterId = 'KIR2DL2_3-')))), openCyto.minEvents = -1 TRUE   pp_cyto_gate_draw  
KIR2DL1_S1+ + CD56dim YG780-A,FSC-H cyto_gate_draw gate = list('Combined Events' = new('filters', .Data = list(new('rectangleGate', min = c('YG780-A' = 0.910219300615835, 'FSC-H' = 31335.6646040617 ), max = c('YG780-A' = 3.47871712191541, 'FSC-H' = 133891.030464317 ), parameters = new('parameters', .Data = list(new('unitytransform', .Data = function () NULL, parameters = 'YG780-A', transformationId = 'defaultUnityTransform'), new('unitytransform', .Data = function () NULL, parameters = 'FSC-H', transformationId = 'defaultUnityTransform'))), filterId = 'KIR2DL1_S1+')))), openCyto.minEvents = -1 TRUE   pp_cyto_gate_draw  
KIR2DL1_S1- + CD56dim YG780-A,FSC-H cyto_gate_draw gate = list('Combined Events' = new('filters', .Data = list(new('rectangleGate', min = c('YG780-A' = -0.628535713854512, 'FSC-H' = 29112.6789689601 ), max = c('YG780-A' = 0.714001344379008, 'FSC-H' = 137841.104938998 ), parameters = new('parameters', .Data = list(new('unitytransform', .Data = function () NULL, parameters = 'YG780-A', transformationId = 'defaultUnityTransform'), new('unitytransform', .Data = function () NULL, parameters = 'FSC-H', transformationId = 'defaultUnityTransform'))), filterId = 'KIR2DL1_S1-')))), openCyto.minEvents = -1 TRUE   pp_cyto_gate_draw  
KIR3DL1+ + CD56dim V431-A,FSC-H cyto_gate_draw gate = list('Combined Events' = new('filters', .Data = list(new('rectangleGate', min = c('V431-A' = 2.5092666389782, 'FSC-H' = 29667.2039570569 ), max = c('V431-A' = 4.52632135987713, 'FSC-H' = 128509.450954286 ), parameters = new('parameters', .Data = list(new('unitytransform', .Data = function () NULL, parameters = 'V431-A', transformationId = 'defaultUnityTransform'), new('unitytransform', .Data = function () NULL, parameters = 'FSC-H', transformationId = 'defaultUnityTransform'))), filterId = 'KIR3DL1+')))), openCyto.minEvents = -1 TRUE   pp_cyto_gate_draw  
KIR3DL1- + CD56dim V431-A,FSC-H cyto_gate_draw gate = list('Combined Events' = new('filters', .Data = list(new('rectangleGate', min = c('V431-A' = -0.147038903882368, 'FSC-H' = 26686.9375012065 ), max = c('V431-A' = 1.30044730515075, 'FSC-H' = 123228.027939902 ), parameters = new('parameters', .Data = list(new('unitytransform', .Data = function () NULL, parameters = 'V431-A', transformationId = 'defaultUnityTransform'), new('unitytransform', .Data = function () NULL, parameters = 'FSC-H', transformationId = 'defaultUnityTransform'))), filterId = 'KIR3DL1-')))), openCyto.minEvents = -1 TRUE   pp_cyto_gate_draw  
KIR+ + CD56dim R780-A, V431-A, YG710-A, YG-780-A, FSC-H boolGate KIR2DL1+ OR KIR3DL1+ OR KIR2DL2_3+ OR KIR2DL1_S1+      

`

Screenshot 2020-06-09 at 19 14 23

DillonHammill commented 4 years ago

@Chris8886, in this case you should be able to leave the dims entry empty. If you replace OR with | in the gating_args it should work. Remember valid operators include | , & and ! for OR, AND and NOT respectively.

Chris8886 commented 4 years ago

@DillonHammill Unfortunately I still get the same error (I use function "Insert row below" when editing)

> cyto_gatingTemplate_edit(gs, paste(Full.Exp.Name, ".csv", sep = ""))
Do not modify existing gatingTemplate entries!
Add new rows to add boolean or reference gates to the GatingSet.
Error in `.rowNamesDF<-`(x, value = value) : invalid 'row.names' length
DillonHammill commented 4 years ago

@Chris8886, you may need to manually delete the KIR+ row in the template, reload the data, re-apply the gatingTemplate and then try to edit it. I think I will add a new cyto_gate_bool() function to handle these sorts of entries for you.

Chris8886 commented 4 years ago

@DillonHammill I can't delete that KIR+ row because it isn't saved in the first place. A new function would be great!

Chris8886 commented 4 years ago

@DillonHammill Do you have any idea why a new row isn't saved when I try to manually add a boolean gate and how can I overcome it?

DillonHammill commented 4 years ago

@Chris8886 I will have the fix up today and I will add the new cyto_gate_bool() function as well.

DillonHammill commented 4 years ago

In the meantime, you could try manually entering this in the gatingTemplate (in excel) and then re-apply to samples using cyto_gatingTemplate_apply().

Chris8886 commented 4 years ago

Manual modification works. I'm waiting for a new function then, thank you for help!

DillonHammill commented 4 years ago

Sorry @Chris8886, the new function is ready but I am working on a lot of things at the moment so it is difficult to push it right now without affecting other things, I will see what I can do. I will reopen this so it is easier to find and I will post a new demo here once I have pushed the update.

DillonHammill commented 4 years ago

OK @Chris8886 I just merged a pull request #61 to add the new cyto_gate_bool() API which will add boolean gates to the GatingSet and make relevant entries in the gatingTemplate. For example, using the Activation GatingSet and a gatingTemplate called "Activation-gatingTemplate.csv", we could add a boolean gate to encompass the CD4 T Cells and CD8 T Cells:

# CD4 T Cells OR CD8 T Cells boolean gate
cyto_gate_bool(gs,
               alias = "CD4+CD8+",
               logic = "CD4 T Cells|CD8 T Cells",
               gatingTemplate = "Activation-gatingTemplate.csv")

As you can see it works in a similar way to cyto_gate_draw() in that you supply the samples and indicate a name for the new population through alias. Although cyto_gate_bool() has a parent argument it is not required and in fact it is recommended that this not be manually supplied as it will be automatically set to the recent common ancestor by default. Internally this will be determined using the new cyto_nodes_ancestor() function. This is important as it determines where the boolean population is positioned within the gating tree.

As with cyto_gate_draw() you don't need to manually supply the name of the gatingTemplate if one is already active as indicated by cyto_gatingTemplate_active().

As you can see above, you will need to provide the boolean logic defining the new population(s) to the logic argument. The rules for this are quite straightforward, the logic is supplied as a character string with references to unique identifiable populations (i.e. if you have CD69+ gated on CD4 T Cells and CD8 T Cells then you need to append the parent - CD4 T Cells/CD69+) and these populations are separated by boolean operators for OR (|), AND (&) or NOT (!). There should be no spaces between population names and boolean operators! I will update the code to try and remove this automatically if present.

Pull down the latest CytoExploreR to give it a try:

devtools::install_github("DillonHammill/CytoExploreR")

I have got a similar function to copy gates to different parents, this will be available soon too. As for cyto_gatingTemplate_edit(), I would avoid using it for now - I am in the process of bundling the data editors into a separate package so this will be addressed eventually.

Chris8886 commented 4 years ago

@DillonHammill Thank you, it works really nice. Every time I use it I get a warning but the function itself works anyway.

Warning message: In if (grepl("root/", node)) { : the condition has length > 1 and only the first element will be used

I'm waiting for a copy gate feature then, it's great that you're working on it, very useful!

DillonHammill commented 4 years ago

Thanks I will fix this tomorrow and add the new cyto_gate_copy() function as well.

DillonHammill commented 4 years ago

@Chris8886, I just pushed an update to cyto_gate_bool() to address your warnings and to add additional checks to remove excess whitespace in the boolean logic. This should cover the common cases where people may accidentally add spaces. Please let me know if you still see the warnings and I can take another look.

I should also mention that there is no editing mechanism for boolean gates at the moment so the best way to edit existing boolean gates is through cyto_gatingTemplate_edit() - this should work fine as it does not require addition of new rows. I am considering adding support for editing boolean gates through cyto_gate_edit() as well but this will require a fair bit of work.

Chris8886 commented 4 years ago

@DillonHammill The warnings are now gone, but unfortunately there is another problem. After closing R and reloading the GatingSet again, all the gates seem to apply succesfully but when I tried exporting statistics from boolGate based populations I got 0 value for everything (count, MFI etc.). Stats exported from regular gating-based populations were just fine. I have boolean gates based on other boolean gates in my script, do you think it might cause a problem?

Should I post here the whole code to help you find out what's the problem?

DillonHammill commented 4 years ago

Hmmm, is the bool gate present in cyto_nodes(gs)? If so, can you extract the population using cyto_extract(gs, "boolname")? Replace boolname with the name of the population. Looking at the population counts may be informative.

cyto_nodes(gs)
cs <- cyto_extract(gs, "boolname")
cyto_stats_compute(cs, stat = "count")
Chris8886 commented 4 years ago

I can do both. All the boolGates are present in cyto_nodes(gs). After using cyto_extract(gs, "/2_CD56dim+, NKG2A+, CD57-, NKG2C-, KIR-") I get

> cyto_extract(gs, "/2_CD56dim+, NKG2A+, CD57-, NKG2C-, KIR-")
A cytoset with 5 samples.

  column names:
    FSC-A, FSC-H, FSC-W, SSC-A, SSC-H, SSC-W, B530-A, R670-A, R780-A, V431-A, V525-A, V605-A, UV379-A, YG586-A, YG710-A, YG780-A, Time

And actually for the MFI the value is not 0 but NaN if it's any help.

DillonHammill commented 4 years ago

Are you using stat = median?

Chris8886 commented 4 years ago

Yes, and it's the same for count, freq etc. And with regular gating based populations there is completely no problem

> cyto_stats_compute(gs[4], parent = "CD56dim", alias = "2_CD56dim+, NKG2A+, CD57-, NKG2C-, KIR-", channels = "POI", stat = "median")
# A tibble: 1 x 7
  treatment donor   name                     well  Population                              Marker MedFI
  <chr>     <chr>   <fct>                    <chr> <chr>                                   <chr>  <dbl>
1 Baseline  BCR2360 BCR2360_Baseline_A01.fcs A01   2_CD56dim+, NKG2A+, CD57-, NKG2C-, KIR- POI      NaN
DillonHammill commented 4 years ago

Can you please post the counts as well?

cyto_stats_compute(gs[4],
                   alias = "2_CD56dim+, NKG2A+, CD57-, NKG2C-, KIR-",
                   stat = "count")
Chris8886 commented 4 years ago
> cyto_stats_compute(gs[4],
+                    alias = "2_CD56dim+, NKG2A+, CD57-, NKG2C-, KIR-",
+                    stat = "count")
# A tibble: 1 x 7
  treatment donor   name                     well  Population                              Marker Count
  <chr>     <chr>   <fct>                    <chr> <chr>                                   <chr>  <int>
1 Baseline  BCR2360 BCR2360_Baseline_A01.fcs A01   2_CD56dim+, NKG2A+, CD57-, NKG2C-, KIR- count      0
DillonHammill commented 4 years ago

Are you sure that the logic is correct? Does not look like there are any events inside the gate? Does this happen for all samples or just the fourth one? This works fine for me. Might be a good idea to check the logic in the gating_args column of your gatingTemplate. Perhaps you are using & when you should be using |? & will keep events shared by both gates whilst | will keep events from both gates.

Chris8886 commented 4 years ago

Yes, I'm 100% sure. It happens for all the samples. In fact I just erased all the csv files in working directory (gating template, spillover etc) and did all the manual and bool gating again without changing a thing in the script. The stats now work but after I close the file it's the same story all over again

> cyto_stats_compute(gs[4],
+                    alias = "2_CD56dim+, NKG2A+, CD57-, NKG2C-, KIR-",
+                    stat = "count")
# A tibble: 1 x 7
  treatment donor   name                     well  Population                              Marker Count
  <chr>     <chr>   <fct>                    <chr> <chr>                                   <chr>  <int>
1 Baseline  BCR2360 BCR2360_Baseline_A01.fcs A01   2_CD56dim+, NKG2A+, CD57-, NKG2C-, KIR- count  16446

EDIT: I reloaded the data and the values for boolean gates are back to 0

DillonHammill commented 4 years ago

So when you reload the data and re-apply the gatingTemplate are there any warnings or errors?

Chris8886 commented 4 years ago

No, it looks like that. Actually quite frequently I've got a similar bug where after reloading one of my initial gate looks empty and according to stats is empty and to fix that I have to edit it's ancestor gate - moving margins by 0.1mm works just fine. Screenshot 2020-06-19 at 12 09 37

> cyto_gatingTemplate_apply(gs, gT)
Applying BCR2360_200527_Transwell_BCR2360-2363.csv to the GatingSet...
Preprocessing for 'Cells'
Gating for 'Cells'
done!
done.
Preprocessing for 'Single Cells'
Gating for 'Single Cells'
done!
done.
Preprocessing for 'NK'
Gating for 'NK'
done!
done.
Preprocessing for 'POI+'
Gating for 'POI+'
done!
done.
Preprocessing for 'CD56dim'
Gating for 'CD56dim'
done!
done.
Preprocessing for 'Double KIR+'
Gating for 'Double KIR+'
done!
done.
Preprocessing for '2DL3+'
Gating for '2DL3+'
done!
done.
Preprocessing for '2DL1+'
Gating for '2DL1+'
done!
done.
Preprocessing for 'KIR-'
Gating for 'KIR-'
done!
done.
Preprocessing for 'Single-KIR'
Gating for 'Single-KIR'
done!
done.
Bool Ed Double KIR+ gating...
done!
done.
Bool Ed 2DL3+ gating...
done!
done.
Bool Ed 2DL1+ gating...
done!
done.
Bool Ed KIR- gating...
done!
done.
Preprocessing for 'NKG2A_'
Gating for 'NKG2A_'
done!
done.
Preprocessing for 'NKG2C-'
Gating for 'NKG2C-'
done!
done.
Preprocessing for 'CD57+, NKG2C+'
Gating for 'CD57+, NKG2C+'
done!
done.
6_CD56dim+, NKG2A-, CD57+, NKG2C+, KIR2DL3+ gating...
done!
done.
6_CD56dim+, NKG2A-, CD57+, NKG2C+, KIR2DL1+ gating...
done!
done.
Preprocessing for 'NKG2A-, CD57+'
Gating for 'NKG2A-, CD57+'
done!
done.
5_CD56dim+, NKG2A-, CD57+, NKG2C-, KIR2DL3+ gating...
done!
done.
5_CD56dim+, NKG2A-, CD57+, NKG2C-, KIR2DL1+ gating...
done!
done.
Preprocessing for 'NKG2A-, CD57-'
Gating for 'NKG2A-, CD57-'
done!
done.
Preprocessing for 'NKG2A+, CD57+'
Gating for 'NKG2A+, CD57+'
done!
done.
Preprocessing for 'NKG2A+, CD57-'
Gating for 'NKG2A+, CD57-'
done!
done.
Preprocessing for 'KIR3DL1-'
Gating for 'KIR3DL1-'
done!
done.
Preprocessing for 'KIR3DL1+'
Gating for 'KIR3DL1+'
done!
done.
Preprocessing for 'KIR2DL1_S1-'
Gating for 'KIR2DL1_S1-'
done!
done.
Preprocessing for 'KIR2DL1_S1+'
Gating for 'KIR2DL1_S1+'
done!
done.
Preprocessing for 'KIR2DL2_3-'
Gating for 'KIR2DL2_3-'
done!
done.
Preprocessing for 'KIR2DL2_3+'
Gating for 'KIR2DL2_3+'
done!
done.
Preprocessing for 'KIR2DL1-'
Gating for 'KIR2DL1-'
done!
done.
Bool KIR- gating...
done!
done.
2_CD56dim+, NKG2A+, CD57-, NKG2C-, KIR- gating...
done!
done.
Preprocessing for 'KIR2DL1+'
Gating for 'KIR2DL1+'
done!
done.
Bool KIR+ gating...
done!
done.
4_CD56dim+, NKG2A-, CD57-, NKG2C-, KIR+ gating...
done!
done.
3_CD56dim+, NKG2A+, CD57-, NKG2C-, KIR+ gating...
done!
done.
Preprocessing for 'CD56bright'
Gating for 'CD56bright'
done!
done.
finished.
A GatingSet with 5 samples
Chris8886 commented 4 years ago

Maybe I'll share my loading part of the script, I might have made some mistake there

library(flowCore)
library(flowWorkspace)
library(openCyto)
library(CytoExploreR)
library(easycsv)

############ Set woking directory and read variables from names ############
path <- easycsv::choose_dir()
setwd(dir = path)
getwd()

patternExperiment.name="!/(.*?)/FCS"
pExperiment.name <- regmatches(path,regexec(patternExperiment.name,path))
Experiment.name <- pExperiment.name[[1]][2]

patternExperiment.donor="FCS/(.*?).!."
pExperiment.donor <- regmatches(path,regexec(patternExperiment.donor,path))
Experiment.donor <- pExperiment.donor[[1]][2]

rm(patternExperiment.donor)
rm(patternExperiment.name)
rm(pExperiment.donor)
rm(pExperiment.name)

Full.Exp.Name <- paste(Experiment.donor, Experiment.name, sep = "_")

############ Create GS ############
gT <- paste(Full.Exp.Name, ".csv", sep = "")
gs <- cyto_setup(path = path, gatingTemplate = gT, clean = TRUE)
gs <- cyto_names_parse(gs, split = "_", vars = c("donor", "treatment", "well"))
cyto_details(gs)

############ Load GS ############
gT <- paste(Full.Exp.Name, ".csv", sep = "")
gs <- cyto_setup(path = path, gatingTemplate = gT, clean = TRUE)
cyto_gatingTemplate_apply(gs, gT)
gs <- cyto_names_parse(gs, split = "_", vars = c("donor", "treatment", "well"))
cyto_details(gs)

############ Initial gating ############
cyto_gate_draw(gs, parent = "root", alias = "Cells", channels = c("FSC-A", "SSC-A"))
cyto_gate_draw(gs, parent = "Cells", alias = "Single Cells", channels = c("FSC-A", "FSC-H"))

############ Compensation ############

spill <- cyto_spillover_edit(gs, parent = "Single Cells")
write.csv(spill, file = paste(Full.Exp.Name, "CompMatrix.csv", sep = ""))  
gs <- cyto_compensate(gs, spillover = paste(Full.Exp.Name, "CompMatrix.csv", sep = ""))

############ Apply data transformations ############

gs <- cyto_transform(gs) 
DillonHammill commented 4 years ago

@Chris8886 do you mind sending through your gatingTemplate so I can take a closer look? You can email it through to CytoExploreR@outlook.com if you like. Not sure I fully understand what is happening just yet, what do the counts look like after cyto_setup() and after cyto_gatingTemplate_apply() in the Load GS section?

DillonHammill commented 4 years ago

Also it is probably a good idea to apply the gatingTemplate after parsing the file names, in case you used these as grouping variables when you drew the gates. I also don't see any compensation or transformations in this section? Perhaps the data is linear and gates were drawn on transformed scale?

Chris8886 commented 4 years ago

@DillonHammill I've already sent my gating template, thank you so much for help with that issue. I'm not sure I understand your questions though, the counts after cyto_setup() alone are all negative because there are no gates applied yet.

After cyto_gatingTemplate_apply() the counts are still zero but after I do that trick where I edit gate NK by moving it 1mm (it's parent gate for CD56bright and CD56dim which are parent gates for all the rest) the counts become all good for regular-gating populations and remain 0 for all boolean-gating populations.

DillonHammill commented 4 years ago

This issue has been resolved offline and was a result of applying gates prior to compensation/transformation. It is important to remember that the gates are saved to the gatingTemplate on the transformed scale and so the data must be transformed prior to applying the gatingTemplate.