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

openCyto Plugin Supporting Manual Drawing of polygonGates #171

Closed DillonHammill closed 4 years ago

DillonHammill commented 6 years ago

Hi @gfinak & @mikejiang,

This is not an issue per se, but I have written an openCyto plugin that facilitates drawing polygonGates (FlowJo style) through openCyto.

Please feel free to try it out: devtools::install_github("DillonHammill/CytoGate") registerPlugins(fun = gate_draw, methodName = "DrawGate")

Simply define coordinates of polygonGate by left clicking on the plot and finish with a right click and selecting "stop".

image

At the moment the gates can only be drawn using base graphics but I will extend this ggcyto next week (hopefully).

Not sure if you guys are interested in incorporating manual gating routines like this into openCyto. I think that it will make the transition from other software (like FlowJo) to openCyto much easier.

Keen to hear your thoughts!

Dillon

gfinak commented 6 years ago

That's a cool idea. I'd be happy to incorporate it. If you want to submit it as a pull request we can take a look.

mikejiang commented 6 years ago

Is it possible to keep the point displayed on the plot after the click ?Right now it disappears immediately and you can't see the actual gate during the drawing process, which makes it difficult to make an accurate drawing. In terms of how to incorporate it into openCyto, one way is to register it as a plugin as you are current doing. If we are concerned about the interruption of batch process of the gating pipeline, we can keep this interactive drawing as the independent feature that takes a flowSet and return a list of polygonGates. We just need to come up a clean way of passing the static gates to the template(which has been an issue in the past)

DillonHammill commented 6 years ago

@mikejiang I have just updated the package to include points when drawing gates, if you would like to try it out. I will play around with the pch argument to change the appearance.

DillonHammill commented 6 years ago

Sorry I have not followed up on this sooner, I have been really busy...

This will be my first pull request, could you guys work me through how to do this properly?

It would be great if we could come up with a way to save the gates to an object so that when the user comes back to the analysis the gates are preserved - and not re-drawn each time.

Thanks

gfinak commented 6 years ago

Hi, @DillonHammill Sorry for not getting back to you sooner. To submit a pull request, fork openCyto, add this code to openCyto, push in a new branch and you will have the option to submit it as a new pull request in the GitHub UI.

DillonHammill commented 6 years ago

Hi @gfinak & @mikejiang,

Thanks for your help, I have submitted a pull request with the code for DrawGate - hopefully I have done this correctly.

Would it be possible to save the gating coordinates to the gatingTemplate after gating (maybe a gate_coords column which is updated after gating)? Then when applying the template we look if coordinates are present in the template and apply these directly, if not we run the gating function to determine the coordinates - which are then saved to the template for future reference?

It would be great if it could be added as one of the default gating methods.

Looks like it is possible to do this with ggplot using the grid.locator() function - I will look into this when I get time. The other alternative is to convert ggplot objects to plotly objects and use the lasso tool to define the coordinates of the gate.

Cheers!

Dillon

mikejiang commented 6 years ago

As I said earlier, we haven't come up a clean way of passing the static gates to the template. Because csv is flat-structured and only suitable for high-level abstract gating method description. The original motivation of adopting it as template format was to make it compact and human-readable. adding the lengthy static gate coordinates directly to csv goes against that purpose.

The only way I can think of is to store them to the gatingTemplate R object , which is graphNEL. Then save it as rds file, which can be loaded back and resused.

That's why I thought it was cleaner to run the interactive gate drawing independently from gating process. Because we don't want the behavior of modifying gatingTemplate by the gating as we applying it. Instead, we should

DillonHammill commented 6 years ago

Sounds great!

DillonHammill commented 6 years ago

Hi guys,

I have made a few updates to the DrawGate function, here is a summary of the changes:

Each gate type prompts the user of the required input which is as follows:

I would also like to add support for gate_type="ellipse" based on user input. Perhaps the user can specify 4 points defining the limits of the gate in 2 dimensions? Do you guys have any suggestions of how I can achieve this?

Please try it out if you have time and let me know what you think: devtools::install_github("DillonHammill/CytoGate") registerPlugins(fun = gate_draw, methodName = "DrawGate")

Thanks again for all your help!

Dillon

SamGG commented 6 years ago

I have no time to test it yet, but it sounds really great. From a drawing point of view, a rectangle could be defined by 3 points, the fourth one being easily inferred. You can imagine pointing a corner, then drawing an edge, and finally pointing the opposite corner of the first corner while drawing the entire rectangle. If the rectangle is parallel to the axes, only two points are sufficient. The same applies to an ellipse if we consider the rectangle that surrounds the ellipse. An alternate definition for an ellipse would be its centre, the big axis and the small axis. Why simplifying? IMHO, the less values I enter, the better I feel. I don't remember if you already mentioned the locator function, but it helped me in specifying parameters.

2018-05-27_185618

DillonHammill commented 6 years ago

Thanks @SamGG!

I like the idea of supplying 2 points (diagonal) for rectangle gates as they are simply 2D interval gates. For rotated rectangles I think it is easier to use a polygon gate - the required number of points should be consistent for each gate type or else it may be confusing.

I have figured out a way of constructing ellipses from 4 points and will add support for these soon.

DillonHammill commented 6 years ago

gate_type="ellipse" is now supported!

Thanks for your suggestions @SamGG.

DillonHammill commented 6 years ago

Hi guys,

Last few updates:

Cheers, Dillon

DillonHammill commented 6 years ago

Short vignette added to demonstrate gating methods and required inputs:

CytoGate_Gating_Methods.pdf

For ellipses only the 4 external points are required, the center point is inferred then plotted - I may remove this to avoid confusion.

Cheers, Dillon

DillonHammill commented 6 years ago

Hi @mikejiang,

I was just wondering if you could elaborate a bit more on how you would save the gates? I would really like to get this working soon so I wouldn't mind giving it a try. I am still trying to get my head around what you have suggested so I would appreciate some guidance.

My understanding is that the samples should be loaded into a GatingSet and a complete csv gating template applied with the gating coordinates being saved to the R template object. Or should gates be applied directly to a flowSet? Then save the file as .rds which can be reused. How should this file be handled the next time you visit the data?

Thanks again for all your help!

Dillon

mikejiang commented 6 years ago

I've pushed the change and now you can pass the gates directly to add_pop call , which will convert your complex R objects to strings and thus suitable to be written to csv template and reused for new datasets. Note that particular cell in the csv will be pretty lengthy, which contains the flat-text version of your gate object. But that is way it is. See here for the complete demo http://rpubs.com/wjiang2/395270

DillonHammill commented 6 years ago

That is excellent! Thanks so much! Can't wait to try it out later today.

Thanks Mike!

DillonHammill commented 6 years ago

Hi @mikejiang,

I have given it a try but keep getting an error:

> template <- add_pop(
+   gs, alias = "NonDebris", parent = "root", pop = "+", dims = "FSC-A,SSC-A", gating_method = "gate_manual",
+   gating_args = list(gate=gateobj)
+ )
Error in .argParser(cur_args, split_args) : invalid gating argument:
<text>:1:11: unexpected '<'
1: c( gate = <
              ^
mikejiang commented 6 years ago

How about the demo code I post ? did it work for you? Have you updated your opencyto package?

DillonHammill commented 6 years ago

I will try it and yes I have updated openCyto.

DillonHammill commented 6 years ago

Yeah the demo code is giving the same error... openCyto version installed = 1.19.1

mikejiang commented 6 years ago

I can't reproduce your error. Here is my sessionInfo.txt

What's your print output of gateobj? Can you also attach the traceback as txt here?

DillonHammill commented 6 years ago

print(gateobj) A list of 1 filters applied to a flowFrame. traceback.txt sessionInfo.txt

mikejiang commented 6 years ago

Can you compare your session info with mine to find out the discrepancies of the package version? Particularly data.table

DillonHammill commented 6 years ago

After updating R and reinstalling packages this is now working! Thanks Mike!

DillonHammill commented 4 years ago

Manual gating is now supported in CytoExploreR (https://dillonhammill.github.io/CytoExploreR/). Closing this issue.