Object hierarchy lost in Annotation Results

323 views
Skip to first unread message

Lavinia Alberi

unread,
Jun 6, 2018, 11:47:36 AM6/6/18
to QuPath users
I have the impossible task of counting axonal nodes and despite the precious help of the community, an unbiased pattern recognition sys could not be found.

I decided to still use Qpath as I can record easily the parent ROI and the area of the selected nodes but in the annotation results the order does not respect the hierarchy (see attached) and knowing the number of nodes per length of the parent ROI, I can retrieve the density.

There is no OD measurement involved besides the ones I have done manually.

Can anyone help?

THX THX THX & HGD,

LA


 I apologize for the dum Q: when running the scripts were do the data end up...?
ObjectHierarchy_lostInResults.png

micros...@gmail.com

unread,
Jun 6, 2018, 1:42:51 PM6/6/18
to QuPath users
In version 1.3 (https://petebankhead.github.io/qupath/2018/03/19/qupath-updates.html) parent annotations are shown.

Another option is that there is a script to convert annotations into cells: https://gist.github.com/Svidro/5829ba53f927e79bb6e370a6a6747cfd#file-change-annotations-into-cell-objects-groovy

For example, in your drawing, it should take all of the ellipses and convert them into "cell objects" as it converts every annotations that is "within" an annotation.

The data is only in the measurements lists by default (or slightly different for the TMA) for the individual objects, or in the summaries provided in the Measure menu.  You can create pretty much any measurement output you want through scripting, whether it is writing it out to the screen or creating your own file.  Pete also created two scripts which takes annotation measurements from a variety of slides and merges them into a single document.

Lavinia Alberi

unread,
Jun 6, 2018, 4:07:55 PM6/6/18
to QuPath users
THX a lot for the prompt reply and for redirecting me to the 1.3 add-ons onto the 1.2 version. 

I tried to run the scripts at point #59
1) 
getDetectionObjects() each {detection -> detection.setName(detection.getParent().getName())}
fireHierarchyUpdate()

but I get the following error: ERROR: Error at line 1: No signature of method: org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.getDetectionObjects() is applicable for argument types: () values: []

2) import qupath.lib.objects.PathCellObject

// Get the current hierarchy
def hierarchy = getCurrentHierarchy()

// Get the non-top level annotations.  This assumes you have a tissue area selected, and have hand drawn some cells within that.

def targets = getObjects{return it.getLevel()!=1 && it.isAnnotation()}


// Check we have anything to work with
if ( targets.isEmpty()) {
    print("No objects selected!")
    return
}

// Loop through objects
def newDetections = new ArrayList<>()
for (def pathObject in  targets) {

    // Unlikely to happen... but skip any objects not having a ROI
    if (!pathObject.hasROI()) {
        print("Skipping object without ROI: " + pathObject)
        continue
    }
    def roi = pathObject.getROI()
    def detection = new PathCellObject(roi,roi,pathObject.getPathClass())
    newDetections.add(detection)
    print("Adding " + detection)
}
removeObjects( targets, true)
// Actually add the objects
hierarchy.addPathObjects(newDetections, false)
//Remove nucleus ROI
newDetections.each{it.nucleus = null}
fireHierarchyUpdate()
if (newDetections.size() > 1)
    print("Added " + newDetections.size() + " detections(s)")

but it says : ERROR: Error at line 4: No signature of method: org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.getCurrentHierarchy() is applicable for argument types: () values: []


 Guess those are the same errors as the error code are the same. Which other add-on should I get?

Unfortunately the whole package 1.3 is not readily available:(

THX a lot& HGD,

LA

micros...@gmail.com

unread,
Jun 6, 2018, 8:37:36 PM6/6/18
to QuPath users
Hmm, something must have gone wrong with the install.  1.3 is not an add on, it is the whole program as a new version.  If you create the program through Gradle, the only things you might need to change would be making sure that the pointer to your extensions folder was correct (in the case of accessing the BioFormats extension, for example, though the Gradle version might get that automatically.  I am not sure.).

As a Windows user, I have several copies of QuPath in my Program Files directory, each folder named for the particular version I am currently using.  When I want to use a given version of the program I just pick which folder to label "QuPath" and the rest are "QuPath 1.2" etc.  

You should be able to copy the Gradle "QuPath" folder straight into the Program Files folder (from the /build/jfx/native/QuPath location) as soon as you rename the old copy to "QuPath 1.2" (in case you need to swap back).

Some of these actions may require Admin privileges on Windows systems, and I have recently become acquainted with ITS policies that do not allow all users to have that...

Pete

unread,
Jun 7, 2018, 3:23:11 AM6/7/18
to QuPath users
For the script troubles, within the script editor in QuPath make sure that the menu item Run -> Include default bindings is selected.  I see the same errors if I turn this setting off (it's on by default).

Lavinia Alberi

unread,
Jun 7, 2018, 3:46:13 AM6/7/18
to QuPath users
THX a lot for all the feedback....I am attempting installation of the 1.3 version...I am half way with it.

Will also try the default binding option>

THX& HGD,

LA 

Lavinia Alberi

unread,
Jun 7, 2018, 8:39:29 AM6/7/18
to QuPath users
THX for all the help, I have downloaded the Qpath 1.3 through graddle but hierarchy is still missing.

 Run the command with Include default bindings but the hierarchy is still not showing up.

Parent Object looks to me selected, Help!

THX again& HGD,

LA
ObjectHierarchyabsent_WithScript.png

micros...@gmail.com

unread,
Jun 7, 2018, 12:35:24 PM6/7/18
to QuPath users
The hierarchy does not look to be missing, but I can't see what you are placing in "targets," which is the most likely culprit.  If targets is empty, the printed message is correct.

Pete

unread,
Jun 8, 2018, 2:42:51 AM6/8/18
to QuPath users
This does look like quite an impossible task... I'm curious about what kind of image/staining that is, and indeed if there are any alternative ways of imaging that might make the task easier.  It's another world for me.

Relatedly, what is the file format, and is the image displaying correctly (i.e. the same as when you view it with other software)?  It looks grayscale, but it is being read by OpenSlide as RGB - and I can see in one of your screenshots and the red, green and blue channels don't have identical values... so it's not quite grayscale.

In any case, it would be great if you could also say a bit more about what the ideal output would be, and whether you have a small or very large number of images to contend with (i.e. if some kind of automation will be essential in the end, or if manual analysis is tolerable).

Am I correct in thinking that you are using the Brush tool mostly because there isn't a line drawing / polyline tool?  I occasionally wonder if QuPath needs a more flexible line-drawing tool, and if not all polygons should be closed.  Getting the length along the brushed area is not entirely easy.  I guess 'half the perimeter' should come close, and calculating the maximum straight line distance between points along the contour is possible - but I can't think of an easy way to get the length of the centerline.

As microscopyra notes, the key bit of the code seems cropped off in the screenshot... the earlier script posted in this thread works for me for a similar-looking image, and the contents of the 'Hierarchy' tab seen on the left of the screen indicates that the necessary information should be there and available to QuPath.

Best wishes,

Pete

Lavinia Alberi

unread,
Jun 8, 2018, 3:14:05 AM6/8/18
to QuPath users
Not really sure about the meaning of targets;(, my bad. As I was not able to use the cell counting, I have used the brush tool and then inside the ROI circled the nodes as objects.
I would need to know how many nodes are distributed across the length of the parent ROI area...thus the hierarchy is quite important.


THX for all the help,

LA

Lavinia Alberi

unread,
Jun 8, 2018, 3:26:42 AM6/8/18
to QuPath users
Dear Pete, 

This is a Sudan Black stain that can be used to visualized myelinated fibers of CNS or PNS nerves. https://onlinelibrary.wiley.com/doi/abs/10.1111/nan.12373

It is chromagen black staining, thus the choice of RGB.

Yes, as mentioned to microspyra: As I was not able to use the cell counting, I have used the brush tool and then inside the ROI circled the nodes as objects.
I would need to know how many nodes are distributed across the length of the parent ROI area...thus the hierarchy is quite important. I have looked for the line drawing tool, indeed, but not sure a hierarchy could be established as the nodes would not be contained. As you mentioned, I extracted the length from the perimeter.

I can see the hierarchy in the left Hierarchy panel, but when I go to show annotation measurement, I cannot see the list: Parent ROI1>Object 1,2,3,4; Parent ROI2>Object 1,2, 3. But those are all mixed up...excluding a density measurement.

In terms of sections, I have 2-3 sections/ biological replicate, 20 biological replicates total.

I was thinking that if I could measure the density of nodes over 50 tracts/section that would be good enough.

I think that as sizes differ largely, limits should be set for small, medium and large nodes...and assign intensity threshold and limits.

Even, if a solution cannot be found...I am really happy to follow up the Posts developing on this Forum....there is soo much to learn!

THX for all the help& HGD,

LA
  

micros...@gmail.com

unread,
Jun 8, 2018, 11:05:18 AM6/8/18
to QuPath users
"targets" is a variable in your script, line 7.  It is likely that there is nothing in it, so the output is correct, but we cannot see the rest of the code and do not know what you are attempting to put there.

micros...@gmail.com

unread,
Jun 8, 2018, 11:17:15 AM6/8/18
to QuPath users
And part of the reason that is important is because of the way some values are returned; not directly through the objects, but through their ROI.  For example, if I wanted to check the pixel size of the perimeter of several objects:
annotations = getAnnotationObjects()
longPerimeter
= annotations.findAll{it.getROI().getPerimeter() >300}
println
(longPerimeter)

So the two things to note are I needed to get the ROI of each annotation to get the perimeter, and the perimeter is returned in pixels, not um.  One of my objects had a perimeter of 44.5 um and I needed to bump the greater than cutoff to 45/0.2282=~200 to threshold it out.

Lavinia Alberi

unread,
Jun 9, 2018, 4:54:35 AM6/9/18
to QuPath users
Dear Microspyra,

THX for pointing this out. I have applied the "get all ROI" but there is no output generated, just info [] in the log window (see attached)...

the fact that I am not getting the results is a recurrent problem that might depend on my installation...which has prevented me to make any script work so far..Will have to work myself out where the problem is.

Anyway, THX a lot for all your help,

LA
ObjectHierarchyabsent_WithScriptTargetROI.png

Pete

unread,
Jun 9, 2018, 5:14:20 AM6/9/18
to QuPath users
I'm not sure what the problem is - I don't think it should be related to the installation, but would need to see the full text of any script.  A key bit is missing in the screenshot (the long line that isn't all visible)... but if I understand correctly the aim, I'm not sure if it's the best script for the purpose.

Here's another one you could try.

If your node annotations are always ellipses then this script aims to replace the 'annotations' with 'detections'.  This has several advantages:
  • The nodes no longer appear in the annotation measurement table
  • The nodes should be assigned to the correct parent annotation based on the centroid being inside the annotation... otherwise the entire ellipse needs to be inside your 'brushed' annotation (which is a harder criterion to meet, and means you need to use a thicker brush)
  • A count of nodes is automatically provided in the annotations table
Definitely save your data before running it - part of this script removes your node annotations, so just in case something goes wrong / you don't like the results, then it's good to have the old data file to return to.

(With v0.1.3 you may be able to recover things with Edit -> Undo, but with v0.1.2 your only option is File -> Revert to go back to the last saved version).

// Get all annotations with ellipse ROIs
def annotations = getAnnotationObjects()
def ellipses = annotations.findAll {it.getROI() instanceof qupath.lib.roi.EllipseROI}


// Create corresponding detections (name this however you like)
def classification = getPathClass('Node')
def detections = ellipses.collect {
   
new qupath.lib.objects.PathDetectionObject(it.getROI(), classification)
}


// Remove ellipse annotations & replace with detections
removeObjects
(ellipses, true)
addObjects
(detections)

Pete

unread,
Jun 9, 2018, 5:25:29 AM6/9/18
to QuPath users

Or here's an alternative that just assigns classifications, but keeps the nodes as annotations and not detections - and uses names and classifications to help distinguish them.  I've shown a screenshot of how the table can look with v0.1.3 (I suspect it's less useful with v0.1.2).


Whichever script you use, you could opt not to classify all ellipses simply as 'Node', but rather assign a different classification based on size - to incorporate more information into the results tables.



// Get all annotations with ellipse ROIs
def annotations = getAnnotationObjects()
def ellipses = annotations.findAll {it.getROI() instanceof qupath.lib.roi.EllipseROI}

// Assign classifications to nodes

def classification = getPathClass('Node')

ellipses
.each {it.setPathClass(classification)}

// Assign names to all other annotations
annotations
.removeAll(ellipses)
annotations
.eachWithIndex {annotation, i -> annotation.setName('Annotation ' + (i+1))}

fireHierarchyUpdate
()



annotation-table.jpeg

Lavinia Alberi

unread,
Jun 9, 2018, 5:49:00 AM6/9/18
to QuPath users
Dear Pete,

Unfortunately...I do not get your same result, ,if I launch the script...I  will need to reinstall my Qupath from scratch...and update the version from Graddle..

I kept all your scripts and will let you know whether there has been any improvement. On the Weeeken, I study for school... but from Monday on will be able to tackle this.

THX a lot for all the help& effort trying to solve this issue.

LA

Pete

unread,
Jun 9, 2018, 6:27:36 AM6/9/18
to QuPath users
No problem.  The first script (the one that converts the ellipse annotations to detections) should also work with v0.1.2 - I've attached a screenshot showing it.  The color applied to the nodes on the image will be random (and possibly hard to see), but can be changed if necessary.

The second script also works with v0.1.2, but it doesn't have 'Num annotation' and 'Num detection' columns - these columns were only added in my not-yet-fully-released v0.1.3 that still needs to be built with Gradle.
annotation-with-detection-table-v0.1.2.jpeg

Lavinia Alberi

unread,
Jun 9, 2018, 6:35:16 AM6/9/18
to QuPath users
THX for the spec, I will definitely will go for the Graddle version v1.3...as numbering is rather salient in my case.

THX again& HGWE,

LA
Reply all
Reply to author
Forward
0 new messages