Semi-random script errors when adding/removing objects

I am using a script to demonstrate both removing and adding objects, ideally for new coders (dun dun dunnn). The setting is a small rectangular annotation with cells generated inside of it, which is also divided into tumor/stroma annotations.
image

The purpose of the script is to remove the cells in one area, run an analysis that adds measurements based only on the cells in the second area, and then restore the cells that were removed.

//Load the LuCa object data before running!
resolveHierarchy() //let's make sure all of the cells are child objects of their annotations!
tumorAnnos = getAnnotationObjects().findAll{it.getPathClass() == getPathClass("Tumor")}
tumorCells = getCellObjects().findAll{it.getParent().getPathClass() == getPathClass("Tumor")}

//Remove the tumor annotations and their cells
removeObjects(tumorAnnos,false)
removeObjects(tumorCells,false)
//Analyze->Spatial analysis->Detect centroid distances 2D

detectionCentroidDistances(true)
//Add everything back, and make sure the hierarchy is resolved!
addObjects(tumorAnnos)
addObjects(tumorCells)
resolveHierarchy()

The code works most of the time. Probably 70%? I lack my usual variety of computers to test out whether it is based on my computer - but I do have a project file hosted online I can make available to run the test.

Errors include: Null pointer exception popup in the lower right,

INFO: Starting script at Sat Jun 05 20:54:28 CDT 2021
WARN: Resolving hierarchy that contains 3 annotations and 1236 detections - this may be slow!
ERROR: QuPath exception
WARN: Resolving hierarchy that contains 3 annotations and 1236 detections - this may be slow!
INFO: Script run time: 0.25 seconds

The log file is not hugely informative on that one.

Alternatively, I sometimes see a TMA core error.

ERROR: QuPath exception: Cannot invoke "qupath.lib.objects.PathObject.isTMACore()" because "child" is null
    at qupath.lib.gui.panes.PathObjectHierarchyView$PathObjectTreeItem.getChildren(PathObjectHierarchyView.java:516)
    at qupath.lib.gui.panes.PathObjectHierarchyView$PathObjectTreeItem.isLeaf(PathObjectHierarchyView.java:544)
    at javafx.controls/javafx.scene.control.skin.TreeCellSkin.updateDisclosureNode(Unknown Source)
    at javafx.controls/javafx.scene.control.skin.TreeCellSkin.updateChildren(Unknown Source)
    at javafx.controls/javafx.scene.control.skin.LabeledSkinBase.lambda$new$5(Unknown Source)
    at javafx.controls/com.sun.javafx.scene.control.LambdaMultiplePropertyChangeListenerHandler.lambda$new$1(Unknown Source)
    at javafx.base/javafx.beans.value.WeakChangeListener.changed(Unknown Source)
    at javafx.base/com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(Unknown Source)
    at javafx.base/com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(Unknown Source)
    at javafx.base/javafx.beans.property.ObjectPropertyBase.fireValueChangedEvent(Unknown Source)
    at javafx.base/javafx.beans.property.ObjectPropertyBase.markInvalid(Unknown Source)
    at javafx.base/javafx.beans.property.ObjectPropertyBase.set(Unknown Source)
    at javafx.graphics/javafx.css.StyleableObjectProperty.set(Unknown Source)
    at javafx.base/javafx.beans.property.ObjectProperty.setValue(Unknown Source)
    at javafx.controls/javafx.scene.control.Labeled.setGraphic(Unknown Source)
    at qupath.lib.gui.panes.PathObjectHierarchyView$PathObjectCell.updateItem(PathObjectHierarchyView.java:423)
    at qupath.lib.gui.panes.PathObjectHierarchyView$PathObjectCell.updateItem(PathObjectHierarchyView.java:413)
    at javafx.controls/javafx.scene.control.TreeCell.updateItem(Unknown Source)
    at javafx.controls/javafx.scene.control.TreeCell.lambda$new$3(Unknown Source)
    at javafx.base/javafx.beans.WeakInvalidationListener.invalidated(Unknown Source)
    at javafx.base/com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(Unknown Source)
    at javafx.base/com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(Unknown Source)
    at javafx.base/javafx.beans.property.ObjectPropertyBase.fireValueChangedEvent(Unknown Source)
    at javafx.base/javafx.beans.property.ObjectPropertyBase.markInvalid(Unknown Source)
    at javafx.base/javafx.beans.property.ObjectPropertyBase.set(Unknown Source)
    at javafx.controls/javafx.scene.control.TreeView.setRoot(Unknown Source)
    at qupath.lib.gui.panes.PathObjectHierarchyView.hierarchyChanged(PathObjectHierarchyView.java:563)
    at qupath.lib.gui.panes.PathObjectHierarchyView.lambda$hierarchyChanged$11(PathObjectHierarchyView.java:559)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(Unknown Source)
    at java.base/java.security.AccessController.doPrivileged(Unknown Source)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(Unknown Source)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(Unknown Source)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(Unknown Source)
    at java.base/java.lang.Thread.run(Unknown Source)

Still other times I see another error:

ERROR: QuPath exception
    at java.base/java.util.LinkedHashMap$LinkedHashIterator.nextNode(Unknown Source)
    at java.base/java.util.LinkedHashMap$LinkedKeyIterator.next(Unknown Source)
    at qupath.lib.objects.PathObject.nDescendants(PathObject.java:475)
    at qupath.lib.objects.PathObjectTools.countDescendants(PathObjectTools.java:200)
    at qupath.lib.objects.PathObject.objectCountPostfix(PathObject.java:190)
    at qupath.lib.objects.PathObject.toString(PathObject.java:224)
    at qupath.lib.gui.panes.PathObjectListCell.updateItem(PathObjectListCell.java:66)
    at qupath.lib.gui.panes.PathObjectListCell.updateItem(PathObjectListCell.java:36)
    at javafx.controls/javafx.scene.control.ListCell.updateItem(Unknown Source)
    at javafx.controls/javafx.scene.control.ListCell.lambda$new$2(Unknown Source)
    at javafx.base/javafx.collections.WeakListChangeListener.onChanged(Unknown Source)
    at javafx.base/com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(Unknown Source)
    at javafx.base/com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(Unknown Source)
    at javafx.base/javafx.collections.ObservableListBase.fireChange(Unknown Source)
    at javafx.base/javafx.collections.ListChangeBuilder.commit(Unknown Source)
    at javafx.base/javafx.collections.ListChangeBuilder.endChange(Unknown Source)
    at javafx.base/javafx.collections.ObservableListBase.endChange(Unknown Source)
    at javafx.base/javafx.collections.ModifiableObservableListBase.setAll(Unknown Source)
    at qupath.lib.gui.panes.AnnotationPane.hierarchyChanged(AnnotationPane.java:382)
    at qupath.lib.gui.panes.AnnotationPane.lambda$hierarchyChanged$7(AnnotationPane.java:352)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(Unknown Source)
    at java.base/java.security.AccessController.doPrivileged(Unknown Source)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(Unknown Source)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(Unknown Source)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(Unknown Source)
    at java.base/java.lang.Thread.run(Unknown Source)

I am at a loss. The script never seems to actual fail, despite the errors. No objects end up missing, the measurements are created in the correct cells.

Sometimes it will run 7 times in a row. Sometimes it will fail 3 times in a row with the same error.
The region itself is small and shouldn’t cause any problems for my computer.
image
Just the upper left corner of the LuCa FoV image.

I have tried adding fireHierarchyUpdates() everywhere I can think or, and tried Thread.sleep(1000) along with setting the number of CPU cores to 1, as well, with no change to the behavior.

Is there something wrong with the script code itself?

1 Like

Oh dear, looks to be very much a QuPath multithreading bug rather than an issue with your code.

Does the guiscript=true hack help? I’d rather not recommend it since at best it patches over the issue, but I think it should work.

The good news is that the problems are all related to UI components (which fits with the script not ‘failing’), the bad news it that it seems to include both the annotation list and the hierarchy view.

I believe the problem is that the ‘children’ of objects are being modified too quickly, before the UI has updated. But QuPath should be protecting against these errors.

If you can share a minimal failing example project that would be very helpful.

2 Likes

(Also, feel free to open an issue on GitHub for this, or else I can open one)

1 Like

Yes, the guiscript=true works. I was trying to remember that and went with setting the processors to 1… which did not work.

1 Like