RGLab / CytoML

A GatingML Interface for Cross Platform Cytometry Data Sharing
GNU Affero General Public License v3.0
30 stars 14 forks source link

2D Box gates treated as Quadrant Gates in .wsp output file #121

Open alexheubeck opened 4 years ago

alexheubeck commented 4 years ago

Hi @gfinak and @mikejiang,

Sorry to bother you again, I have one more thing to work out with the FlowJo .wsp files that I'm exporting with CytoML.

In the .wsp file I generate from openCyto gating, there are some 2D box gates that are offset, like this one:

Screen Shot 2020-11-18 at 7 51 11 AM

When I go to move one of the gates in FlowJo, it acts like a quadrant gate, and moves the lines for both gates at once. The corner vertices can't be selected, only the center where the boxes connect:

Screen Shot 2020-11-18 at 7 52 58 AM

Once the gate is moved, it can't be moved back from the quadrant gate format:

Screen Shot 2020-11-18 at 7 54 30 AM

I believe this was changed recently, when I used a previous version of CytoML each gate was treated as it's own 2D box gate. I understand the reason for this change (I think), in that when you need to move a quadrant gate, you would have to select all four boxes to move them all at once. Would it possible to add an input for the gs_to_flowjo function to chose how to interpret 2D gates, either as box gates or quadrant gates?

Let me know what you think, and I can provide an example if necessary.

Thanks,

Alex

> sessionInfo()
R version 4.0.2 (2020-06-22)
Platform: x86_64-apple-darwin17.0 (64-bit)
Running under: macOS Catalina 10.15.7

Matrix products: default
BLAS:   /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] parallel  stats     graphics  grDevices utils     datasets  methods  
[8] base     

other attached packages:
 [1] gridExtra_2.3            colorRamps_2.3           tidyr_1.1.2             
 [4] dplyr_1.0.2              tibble_3.0.4             scales_1.1.1            
 [7] cytolib_2.3.0            CytoML_2.3.1             data.table_1.13.2       
[10] ggcyto_1.19.0            ggplot2_3.3.2            ncdfFlow_2.37.0         
[13] BH_1.72.0-3              RcppArmadillo_0.10.1.2.0 flowCore_2.2.0          
[16] flowWorkspace_4.3.0      openCyto_2.3.0          
gfinak commented 4 years ago

Thanks, Alex. I think this is a good idea, we'll see about implementing the feature.

mikejiang commented 4 years ago

Could you please provide the example wsp file?

alexheubeck commented 4 years ago

@mikejiang Here is the .wsp file for the example I showed above.

Quadrant Gate Test.wsp.zip

The specific gates related to this issue are:

/Cells/Singlets-H/Singlets-W/Cleanup/Viable/Leukocytes/CD3+ Cells/T Cells/ab T Cells/CD4 T Cells/Non-Treg CD4/Non-naive CD4 T Cells/CXCR5- PD-1 High

and

.../Non-naive CD4 T Cells/cTfh

mikejiang commented 4 years ago

These two gates don't share the same intersection (center of quadgate) so they must belong to two different quadgates.(and they happen to share the same x,y axis and under that same parents.) So it is pulling the wrong quadrants into the same plot. I will see if I can mimic your use case to verify if there is special care needed for the graph setting in wsp output.

mikejiang commented 4 years ago

If previous version of outputting simple 2d rectangle gate worked, then I will go ahead to add the option to disable quadgate as you suggested.

mikejiang commented 4 years ago

Here is a little recap of my thoughts (mainly as the notes for future trace back on this topic). when you generate opencyto gates, e.g.

  gs_add_gating_method(gs, pop = "+/-+/-", parent = "root", dims = "FSC-A,SSC-A", gating_method = "mindensity")

~It is constructing and returning a quadGate object and flowWorkspace/cytolib receives and stores it as quadGate (used to convert it to 4 rectangle gates, which is what you experienced).~

EDIT: Actually the new behavior of storing as quadGate only happens when a quadGate is explicitly added to gs, e.g

gs_pop_add(gs, quadGate(filterId="myQuadGate1", "FSC-A"=100, "SSC-A"=400))

And for CytoML , it is more natural to write the gate as whatever type/format is originally generated and stored (see #20, #23) than having a switch to alter it during the outputting process.

So to be less intrusive to CytoML workflow, maybe this coersion from quadGate to rectangleGate can happen outside of cytoml. E.g. have a convenient function gs_convert_quad_to_rectangle(gs, pops), which is explicitly invoked by user before gatingset_to_flowjo call

alexheubeck commented 4 years ago

Hey @mikejiang,

Sorry for the delay getting back to you. I think your solution would be great, especially since you can determine which gates you want to be quads and rectangles specifically. Would this be part of CytoML or flowWorkspace? Not that it matters, just interested.

Also, if you need my gs archive for this sample still, I can send it. What is the best way of getting you files that are above the 10MB limit for github issue threads?

mikejiang commented 4 years ago

I will put it in CytoML for now until its usage spread to other occasions in future. Let's test this solution first before I decide whether we need your gs

mikejiang commented 4 years ago

I've corrected my inaccurate comment above regarding to the quadGate from openCyto. In fact openCyto typically only construct 4 individual rectangleGate and thus CytoML only sees 4 rectangles. The reason you still see quadgate in flowJo is NOT because CytoML tries to reconstruct/restore the quadGate during outputting to wsp. It has to do with the way how the infinite bounds of rectangleGate is treated. For a gate with Inf bound (which is what gs_add_gating_method(gs, pop = "+/-+/-", generates) e.g.

> rectangleGate(`FSC-A` = c(100, Inf), `SSC-A` = c(200, Inf))
Rectangular gate 'defaultRectangleGate' with dimensions:
  FSC-A: (100,Inf)
  SSC-A: (200,Inf)

We used to replace Inf with .Machine$integer.max(i.e. 2147483647), and then still write it as regular rectangle gate in xml

<gating:RectangleGate>
                <gating:dimension gating:min="100" gating:max="2147483647">
                  <data-type:fcs-dimension data-type:name="FSC-A"/>
                </gating:dimension>
                <gating:dimension gating:min="200" gating:max="2147483647">
                  <data-type:fcs-dimension data-type:name="SSC-A"/>

Now the new logic introduced in this release is always to omit infinite bounds, so we ends up to

<gating:RectangleGate>
                <gating:dimension gating:min="100">
                  <data-type:fcs-dimension data-type:name="FSC-A"/>
                </gating:dimension>
                <gating:dimension gating:min="200">
                  <data-type:fcs-dimension data-type:name="SSC-A"/>

So when FlowJo sees this type of rectangleGate it automatically treats it as quadGate. In other words, both explicit quadGate and inf-bound 2d rectGate from cytolib will become quadGate in flowJo , even though they are stored and treated differently in cytolib

So gs_convert_quad_to_rectangle approach won't be sufficient, and before we switch to the solution of interpolating Inf with max int , I do want to see your gs and fcs to explore if there is cleaner way to address your issue. You can send to my email directly or through google drive

alexheubeck commented 3 years ago

Hey @mikejiang,

Just wondering if there are any updates for this issue, thanks!

Alex