RGLab / openCyto

A package that provides data analysis pipeline for flow cytometry.
GNU Affero General Public License v3.0
75 stars 29 forks source link

how to obtain all data except a boundary gate? #169

Closed MartyMestdagh closed 6 years ago

MartyMestdagh commented 6 years ago

hi, i'm working on a gating strategy with opencyto, i don't find how to exclude a population from a gate created. i realize a boundary gate and i want to continue with all data except the pop from this boundary gate i wrote this on my CSV: alias,pop,parent,dims,gating_method,gating_args,collapseDataForGating,groupBy,preprocessing_method,preprocessing_args test,+,root,"CD5,CD11b",boundary,"min=c(2.8,3),max=c(4.75,4.75)",NA,NA,NA,NA

and i want something like this: test2,+,test-( here population except the gate), "CD2,CD3",mindensity,NA,NA,NA,NA,NA

i tried different pop +, +/-, * -/+ and same result with flowClust.2D (transitional) thanks for your help! cyto

gfinak commented 6 years ago

I think you just specify the first population as test- rather than test+ That will select all cells except those inside the gate.

MartyMestdagh commented 6 years ago

i tried it but it's always the same result.

SamGG commented 6 years ago

As a workaround, I would use a boolean gate that inverses the selection.

gfinak commented 6 years ago

Calling @mikejiang

mikejiang commented 6 years ago

Right, this was the known issue related to negated 2D gate (i.e. A-). It's been neglected due to the workaround of boolean gate mentioned by @SamGG . Bascially it is because the generic filter class (defined in flowCore) used by openCyto to represent the gate object doesn't have the slot to carry the negated information. So in 1d gate case, we simply flip the coordinates (x, Inf) --> (-Inf, x) to accomplish the negated gate and it is currently not handling 2d gate properly.

mikejiang commented 6 years ago

There are two ways to approach this:

The first solution is less intrusive to the existing framework and potentially more compatible with other platform such as cytobank which also use boolean gate to achieve negated gate . @gfinak ?

gfinak commented 6 years ago

I'm in favor of the second solution for its consistency.

mikejiang commented 6 years ago

@gfinak , To be consistent, interpreting A- as negated gate should be applied to 1d gate as well. And there are two type of 1d rectangleGates we want to support

The first use case will be handled in the same manner as 2d gate, that is passing and storing negated flag to the cytolib. This is operated by the framework that is outside of gating function so that existing gating function can work as it is without resorting to the new derived filter class.

The open ended case is currently treated differently as I mentioned above (through coordinates flipping). i.e.

I think I am going to deprecating this behavior to unify all cases. (That is storing the negated flag along with gate). The impact to the user would be minimum since this coordinates flipping mechanism (and positive argument) was never officially documented as the convention for plugin gating methods. The only affected external plugin that I am aware of is wrapper function flowDensity.1d in flowDensity (originally written by me), which can be easily adapted.

MartyMestdagh commented 6 years ago

thank you everyone, I managed to get the expected result i realize a boolGate to obtain the inverse selection Granu,+,sFSC,"CD5,CD11b",boundary,"min=c(2.8,3),max=c(4,4)",NA,NA,NA,NA notGranu,+,sFSC,,boolGate,!Granu,NA,NA,NA,NA here a test to verify test,+,notGranu,boundary,"min=c(2.8,3),max=c(4,4)",NA,NA,NA,NA toto

we can see the negative selection! thanks @gfinak @mikejiang @SamGG

mikejiang commented 6 years ago

@MartyDurden , negated gate (both 1d and 2d) are supported in the latest commits. Feel free to use the either approach (i.e. boolean gate vs negated gate) Here is the demo

library(openCyto)
dataDir <- system.file("extdata",package="flowWorkspaceData")
gs <- load_gs(list.files(dataDir, pattern = "gs_bcell_auto",full = TRUE))
setNode(gs[1], "boundary", TRUE)

#grab existing gates to demonstrate the negated gating 
gate_1d <- getGate(gs[[1]], "Live")
gate_2d <- getGate(gs[[1]], "CD3")

#create a dummy gating function that simply return this static gate
dummy_gating_func_1d <- function(fr, pp_res, channels, ...)return (gate_1d)
dummy_gating_func_2d <- function(fr, pp_res, channels, ...)return (gate_2d)

#register it as the plugin gating method
registerPlugins(dummy_gating_func_1d, "live_gate")
registerPlugins(dummy_gating_func_2d, "cd3_gate")

#apply negated gate to the gs
add_pop(gs, alias = "dead", parent = "lymph", pop = "-", dims = "Live", gating_method = "live_gate")
p <- autoplot(gs[[1]], c("dead", "Live"), merge = FALSE,strip.text = "gate")
plot(ggcyto_arrange(p, nrow = 1))

image

add_pop(gs, alias = "CD3-", parent = "Live", pop = "-", dims = "CD3,CD19", gating_method = "cd3_gate")
p <- autoplot(gs[[1]],  c("CD3-", "CD3"), merge = FALSE,strip.text = "gate")
plot(ggcyto_arrange(p, nrow = 1))

image

Note that you need the latest patch of ggcyto to display negated gate stats properly. see RGLab/ggcyto#27

SamGG commented 6 years ago

Great job Mike!

MartyMestdagh commented 6 years ago

thanks you so much for your work @mikejiang!

MSHelm commented 3 years ago

Hi, I am also working on a similar problem, but cannot manage to select the negated gate using a .csv gating template. I can reproduce your method of registering a dummy gate method and using it with add_pop but how can I do the same when using a gating template?

For my problem, I need to construct two tailgates first, and use refGate to define the debris population. I would then like to select everything except that population. Currently I use the boolGate workaround, but I would really like to switch to what you show here, as it makes everything much clearer in the plot functions.

The rectangleGate constructed by refGate has -Inf as the minimum values for both FSC-H and SSC-H, is that a problem?

Below you can find a reprex and my gating template. I would like to get the same result with the NonDebris gate as with the NonDebrisBool gate.

library(flowCore)
library(openCyto)
library(ggcyto)

data("GvHD")
fs <- GvHD[1]
gs <- GatingSet(fs)
gating_template <- "path/to/gating_template.csv"
gating_template <- gatingTemplate(gating_template)
gt_gating(gating_template, gs)
autoplot(gs[[1]], y = "SSC-H")
gs_pop_get_stats(gs)
alias pop parent dims gating_method gating_args collapseDataForGating groupBy preprocessing_method preprocessing_args
FSC-H_tmp - root FSC-H tailgate "side = 'right', auto_tol = TRUE, num_peaks = 3, ref_peak = 1" NA NA NA
SSC-H_tmp + FSC-H_tmp SSC-H tailgate "side = 'right', auto_tol = TRUE" NA NA NA
Debris -- root "FSC-H,SSC-H" refGate /FSC-H_tmp:/FSC-H_tmp/SSC-H_tmp NA NA NA
NonDebris - root "FSC-H,SSC-H" refGate /Debris NA NA NA
NonDebrisBool + root "FSC-H,SSC-H" BoolGate !Debris NA NA NA

Thanks a lot for your help and your awesome cytoverse environment! Best Martin

mikejiang commented 3 years ago

@MSHelm , Thank you for reporting it. It seems to be a missing feature (i.e.negate a 2d refGate). I've added a quick patch. It should work now

data("GvHD")
fs <- GvHD[1]
gs <- GatingSet(fs)

gs_add_gating_method(gs, "FSC-H_tmp", "-", "root", "FSC-H", "tailgate", "side = 'right', auto_tol = TRUE, num_peaks = 3, ref_peak = 1")
gs_add_gating_method(gs, "SSC-H_tmp", "+", "FSC-H_tmp", "SSC-H", "tailgate", "side = 'right', auto_tol = TRUE")
gs_add_gating_method(gs, "Debris", "--", "root", "FSC-H,SSC-H", "refGate", "/FSC-H_tmp:/FSC-H_tmp/SSC-H_tmp")
gs_add_gating_method(gs, "NonDebris", "-", "root", "FSC-H,SSC-H", "refGate", "Debris")

library(ggcyto)
autoplot(gs[[1]], c("NonDebris"))
gh_pop_get_gate(gs[[1]], "Debris")

image

gs_pop_get_stats(gs)
  sample                  pop count
1:  s5a01                 root  3420
2:  s5a01           /FSC-H_tmp  2372
3:  s5a01 /FSC-H_tmp/SSC-H_tmp  1465
4:  s5a01              /Debris   907
5:  s5a01           /NonDebris  2513
MSHelm commented 3 years ago

@mikejiang sorry for the late reply. Works perfectly now :)