Unable to set annotation names while looping through images

Hi all,
I have a project in Qupath-0.2.1 with multiple tissue regions per image, which I’ve annotated using a simple thresholder and assigned to class “Tissue”. I’m now trying to write a simple script that will loop through each annotation of class Tissue and assign it a unique name, so that annotations within the same tissue section can be grouped together based on the “Parent” field of the measurements table during downstream analysis.

The script works fine when running on a single image and using QPEx.getCurrentHierarchy(); however, when I try to do this for all images in the project using a for loop, the name changes are not preserved when the loop finishes running. There’s several workarounds for the purpose of this script, but I’m hoping to learn why the code breaks when using the loop in order to understand a bit more about the behavior of QuPath scripting.

Thanks!

import qupath.lib.gui.scripting.QPEx

def project = QPEx.getProject()

// assign unique names to each annotation of class "Tissue"
def counter = 1
for (entry in project.getImageList()){

    def hierarchy = it.readHierarchy()
    hierarchy.resolveHierarchy()

    def tissueAnnotations = hierarchy.getAnnotationObjects().findAll{
        it.getPathClass() == QPEx.getPathClass("Tissue")
    }
    tissueAnnotations.each{
        it.setName("Section-" + Integer.toString(counter))
        counter++
    }

    // name changes are remembered at this step...
    tissueAnnotations.each{
        print it.getName()
        counter++
    }
}

// but not after the loop finishes
for (entry in project.getImageList()){

    def hierarchy = it.readHierarchy()
    hierarchy.resolveHierarchy()

    def tissueAnnotations = hierarchy.getAnnotationObjects().findAll{
        it.getPathClass() == QPEx.getPathClass("Tissue")
    }
   tissueAnnotations.each{
      print it.getName()
   }
}

You haven’t saved the imageData.

This is the end of another script:

        def imageData = entry.readImageData()
//Lots of other stuff
        otherHierarchy.addPathObjects(newObjects)
        otherHierarchy.getAnnotationObjects().each{it.setLocked(true)}
        entry.saveImageData(imageData)

Where it is doing something to a particular entry, then saving the image data after the changes are made.

This is not the normal way to loop through a project however. Using getCurrentHierarchy() works for each image in turn when using “Run for project…” in the Run menu. Then the “current image” or “current hierarchy” is each image in turn, as QuPath cycles through them. So far I have only used the entries when moving objects back and forth between images, where I truly need to both access another project entry and the current entry at the same time.
https://qupath.readthedocs.io/en/latest/docs/scripting/workflows_to_scripts.html#running-a-script-for-multiple-images
When using Run for project you do not need to explicitly save the data. Though, you can use Run for project (without save) if you want to avoid saving the data.

Excellent, that makes a lot of sense! Thanks so much.

1 Like