Script for: Select Annotations specificly by its name & class to differentiate ROIs with the same class.

709 views
Skip to first unread message

David

unread,
Jul 13, 2018, 8:26:37 AM7/13/18
to QuPath users
Hi everyone,

I have an Organ as ROI - with 6 organs on one slide.
To get the results for the organ separately, I gave each one a number: "Organ-1"..."Organ-2"..."Organ-6".

The organs contain further annotations that segment the organ in different areas. To adress each area (that carries the same class in all 6 different cuts on the same slide), I scripted that the Name of the Organ with number appears in the name of each descendent ROI.

Now, I want to specificly adress ROIs in each Organ separately:

Example:
Select ROI with  "Epithel"-Class in "Organ-4".

The ROI carries already the name "Organ-4" and the class "Epithel".

But how can I now adress specificly only "Epithel" ROIs that additionally carry the name "Organ-4"?

Is there a way to do that via scritping?

Thanks a lot for any ideas.

Best
David


Caleb Grenko

unread,
Jul 13, 2018, 9:31:57 AM7/13/18
to QuPath users
Hey David-

Does this sort of fit what you're looking for?

def hierarchy = QP.getCurrentHierarchy()
hierarchy
.getSelectionModel().selectObjects(QP.getAnnotationObjects().findAll {it.getPathClass() == QP.getPathClass("Epithel") &&
 it
.getParent().getDisplayedName().equalsIgnoreCase("organ-4")})

Running that should find and select all objects in the hierarchy with the PathClass "Epithel" that fall within annotations with the name "organ-4".

I'm sure there's a more eloquent way to do it, preferably traversing the hierarchy top-down and iterating through a smaller set. However, I'm not sure if there's an easy hierarchy method for finding the parent-less annotations that doesn't involve traversing each object- at which point you could just use the code I posted above.

Let me know if that helps!
Caleb

micros...@gmail.com

unread,
Jul 13, 2018, 12:51:39 PM7/13/18
to QuPath users

I tried finding a way to use getChildObjects to streamline that, but was unsuccessful at figuring out a way to call it on the "top" of the hierarchy.  Anything using "level == 1" would have the same problem of running through all annotations.  Probably not a big deal from a speed point of view (unless he is converting hundreds of thousands of SLICs to annotations, maybe), but interesting from a coding one, if Pete can show us a way to do it once he is back.

micros...@gmail.com

unread,
Jul 13, 2018, 1:05:01 PM7/13/18
to QuPath users
Though on that note, if you ONLY want the objects "within" the organ ROI, and not the surrounding ROI (which as I understand has the same class and name), you could add && it.getLevel() != 1, which would end up looking something like:

def hierarchy = getCurrentHierarchy()
hierarchy.getSelectionModel().clearSelection()

hierarchy.getSelectionModel().selectObjects(getAnnotationObjects().findAll {it.getPathClass() == getPathClass("Epithel") &&
 it.getParent().getDisplayedName().equalsIgnoreCase("organ-4") && it.getLevel() != 1})

If you have a whole image annotation, that would end up being 2, etc, etc, as you go farther down into the hierarchy.

David

unread,
Jul 14, 2018, 9:26:02 AM7/14/18
to QuPath users
Hi Caleb,

thanks a lot for your idea.  I tried to make it run, but it seems like I need to import any module first.
I get this message:

INFO: Starting script at Sat Jul 14 15:25:16 CEST 2018
ERROR: Error at line 2: No such property: QP for class: Script19

ERROR: Script error
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:53)
    at org.codehaus.groovy.runtime.callsite.PogoGetPropertySite.getProperty(PogoGetPropertySite.java:52)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGroovyObjectGetProperty(AbstractCallSite.java:307)
    at Script19.run(Script19.groovy:3)
    at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:343)
    at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:152)
    at qupath.lib.scripting.DefaultScriptEditor.executeScript(DefaultScriptEditor.java:765)
    at qupath.lib.scripting.DefaultScriptEditor.executeScript(DefaultScriptEditor.java:695)
    at qupath.lib.scripting.DefaultScriptEditor.executeScript(DefaultScriptEditor.java:677)
    at qupath.lib.scripting.DefaultScriptEditor.access$400(DefaultScriptEditor.java:136)
    at qupath.lib.scripting.DefaultScriptEditor$2.run(DefaultScriptEditor.java:1029)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

David

unread,
Jul 14, 2018, 9:42:29 AM7/14/18
to QuPath users
Hi Mike,

the code worked! Cool. Thanks a lot :)

Best
David

Pete

unread,
Jul 16, 2018, 4:27:13 AM7/16/18
to QuPath users
For Caleb's method to work you'll need to either remove all references to QP. or else add this line at the top:
import qupath.lib.scripting.QP


Reply all
Reply to author
Forward
0 new messages