Question: How to select left hand side of mindensity2 gate
0
gravatar for biomiha
10 months ago by
biomiha20
UK/Cambridge
biomiha20 wrote:

Hi,

I'm trying to use the gate_mindensity2 from the openCyto package to gate out debris from my .fcs files. I'm using https://flowrepository.org/id/FR-FCM-ZZ36 as an example. I can gate out the debris at the lower end (i.e. left hand side of the gate) but if I want to apply a gate to remove the events on the right hand side, I am unable to do so, even if I set the positive argument to TRUE. I've probably just missed something, but has the positive=TRUE argument to gate_mindensity2 been removed from the recent version of openCyto.

Reprex and link to reprex output below. The issue I have is from applying FCSgate2fun to the gating set and expecting the filter to take the real line to the left of the cutpoint

Many thanks, Miha

https://github.com/Biomiha/FACS/blob/master/FACS_reprex.html

library(tidyverse)
library(openCyto)
library(ggcyto)

PBMC_luca <- list.files(path = "FR-FCM-ZZ36/", pattern = ".fcs", full.names = TRUE) %>% 
  grep(pattern = "luca", value = TRUE) %>% 
  read.ncdfFlowSet(.)

PBMC_luca[[1]] %>% 
  ggcyto(aes(x = `FSC-A`)) +
  geom_density()

PBMC_luca_gatingSet <- GatingSet(PBMC_luca)
FCS_gate1_fun <- function(fr, channel = "FSC-A"){
  peaks_found <- openCyto:::.find_peaks(x = as.numeric(unname(unlist(exprs(fr[, channel])))), num_peaks = 3)
  openCyto::gate_mindensity2(fr, channel = channel, gate_range = sort(peaks_found$x)[1:2])
}
FCS_gate1_fun(getData(PBMC_luca_gatingSet[[1]]))

if(require(openCyto)){
  thisData <- getData(PBMC_luca_gatingSet)
  nonDebris_gate <- fsApply(thisData, FCS_gate1_fun)
  add(PBMC_luca_gatingSet, nonDebris_gate, parent = "root", name = "nonDebris")
  recompute(PBMC_luca_gatingSet)
}

getData(PBMC_luca_gatingSet[[1]]) %>% 
  ggcyto(aes(x = `FSC-A`)) +
  geom_density() +
  geom_gate(FCS_gate1_fun(getData(PBMC_luca_gatingSet[[1]])))

getData(PBMC_luca_gatingSet[[1]], y = "nonDebris") %>% 
  ggcyto(aes(x = `FSC-A`)) +
  geom_density()

FCS_gate2_fun <- function(fr, channel = "FSC-A"){
  openCyto::gate_mindensity2(fr, channel = channel, positive = TRUE) #not sure if this argument exists anymore
}

getData(PBMC_luca_gatingSet[[1]], y = "nonDebris") %>% 
  ggcyto(aes(x = `FSC-A`)) +
  geom_density() +
  geom_gate(FCS_gate2_fun(getData(PBMC_luca_gatingSet[[1]], y = "nonDebris")))

if(require(openCyto)){
  thisData <- getData(PBMC_luca_gatingSet, y = "nonDebris")
  nonDebris_gate2 <- fsApply(thisData, FCS_gate2_fun)
  add(PBMC_luca_gatingSet, nonDebris_gate2, parent = "nonDebris", name = "nonDebris2")
  recompute(PBMC_luca_gatingSet)
}

getData(PBMC_luca_gatingSet[[1]], y = "nonDebris") %>% 
  ggcyto(aes(x = `FSC-A`)) +
  geom_density()

getData(PBMC_luca_gatingSet[[1]], y = "nonDebris2") %>% 
  ggcyto(aes(x = `FSC-A`)) +
  geom_density()

sessionInfo()
opencyto mindensity • 286 views
ADD COMMENTlink modified 10 months ago by Jiang, Mike1.2k • written 10 months ago by biomiha20

I've figured out the reason. At least in my version of openCyto::gate_mindensity2 the last 3 lines of code are:

coords <- list(c(g$final_cut, Inf))
names(coords) <- channel
return(rectangleGate(coords, filterId = filterId))

Meaning that any positive argument passed to gate_mindensity2 is irrelevant as the coords are hardwired to be c(g$final_cut, Inf). I'm not sure if this was done deliberately, but I've noticed the same for the other gates, e.g. openCyto::gate_tail.

I've generated my own version of the gating function. Attached below.

my_mindensity <- function(fr, channel, filterId = "", pivot = FALSE, gate_range = NULL, min = NULL, max = NULL, peaks = NULL, positive = TRUE, ...) {
  stopifnot(require(openCyto))
  if (missing(channel) || length(channel) != 1) {
    stop("A single channel must be specified.")
  }
  if (!(is.null(min) && is.null(max))) {
    fr <- .truncate_flowframe(fr,
      channels = channel, min = min,
      max = max
    )
  }
  x <- exprs(fr[, channel])
  g <- openCyto:::.improvedMindensity(
    D = x, gate_range = gate_range,
    ...
  )
  if (positive == TRUE) {
    coords <- list(c(g$final_cut, Inf))
  } else {
    coords <- list(c(-Inf, g$final_cut))
  }
  names(coords) <- channel
  return(rectangleGate(coords, filterId = filterId))
}
ADD REPLYlink modified 10 months ago • written 10 months ago by biomiha20
Answer: How to select left hand side of mindensity2 gate
0
gravatar for Jiang, Mike
10 months ago by
Jiang, Mike1.2k
(Private Address)
Jiang, Mike1.2k wrote:

I'd recommend openCyto gating functions to be used with its template-based gating framework. Instead of iterating through each sample (i.e. fsApply) of each gated population (i.e. getData) and invoking mindensity and adding gates manually, you can simply submit the gating strategy to the framework and let openCyto do these boilerplate jobs for you. It can be done either through a csv template or incrementally by add_pop API. To select lower(left) end of 1d gate, simply set pop column(or argument) to "-" in csv (or add_pop() call)

Here is the example http://rpubs.com/wjiang2/464414, which is more succinct and easy to read/understand.

P.S. With more recent development version of openCyto (trunk branch of github repo), you will able to quickly undo add_pop through newly added 'remove_pop' API.(instead of manually remove gates through 'Rm' function)

ADD COMMENTlink written 10 months ago by Jiang, Mike1.2k

Thanks Mike. With regards to the fsApply iteration I followed this vignette, which seems to be quite recent https://www.bioconductor.org/packages/devel/bioc/vignettes/flowCore/inst/doc/HowTo-flowCore.pdf. The add_pop API looks like a very good alternative though.

ADD REPLYlink written 10 months ago by biomiha20

flowCore&flowWorkspace provide the relative low-level of APIs to interact with the basic data structures (e.g. flowSet, Gatingset). For the auto gating, openCyto package provides more high-level interlaces and convenient wrappers (which are built upon those two packages). They operate at the different layers and thus serve different purposes. From my understanding based on your use cases, template/gating strategy-based openCyto will meet your needs better. That said, flowCore&flowWorkspace are the building blocks of openCyto, feel free to use them if you need more complex and customized gating and you didn't find the existing tools available in openCyto.

ADD REPLYlink written 10 months ago by Jiang, Mike1.2k

Hi Mike,

One thing I've noticed is that even with the pop argument set to "-" in the add_pop API, the gate dimensions themselves are actually set to:

Rectangular gate 'nonDebris2' with dimensions:
FSC-A: (244703.838155759,Inf)

i.e. right hand side. I'm not sure what goes on behind the scenes because the population stats look ok and the ggcyto labels are fine as well but if I use a different plotting function it (correctly) sets the gate on the right. I've summarised it all here: http://rpubs.com/biomiha/470168. Presumably the desired behaviour would be to get the gate dims as:

Rectangular gate 'nonDebris2' with dimensions:
FSC-A: (-Inf, 244703.838155759)

?

ADD REPLYlink modified 9 months ago • written 9 months ago by biomiha20

openCyto tries to interpret pop = '-' in a generic way (i.e. set 'negate' flag to the gate) that is not limited to 1d gate but can also work the same manner for 2d gate and even non-geometrical gate (e.g. bool gate). So you will get a negated 1d gate that is open-ended at right side and 'ggcyto' is aware of it and knows how to treat it properly regarding to the stats. You will have to file the bug/issue report to Dillon Hammill in order for CytoRSuite::cyto_plot to plot stats correctly.

ADD REPLYlink written 9 months ago by Jiang, Mike1.2k
Please log in to add an answer.

Help
Access

Use of this site constitutes acceptance of our User Agreement and Privacy Policy.
Powered by Biostar version 16.09
Traffic: 222 users visited in the last hour