Trying to script opening the TMA grid summary viewer

71 views
Skip to first unread message

Caleb Grenko

unread,
Jun 1, 2018, 10:51:48 AM6/1/18
to QuPath users
Hello all!

I'm trying to incorporate the TMA grid summary viewer opening after a script completes, but I've run into some issues. Heres a summary of the snippit:

import javafx.application.Platform
import javafx.stage.Stage
import qupath.lib.gui.tma.QuPathTMAViewer

Platform.runLater {
 
def stage = new Stage()
 
QuPathTMAViewer.launch(QuPathTMAViewer.class, stage)
}

When I run it, the log reads:

ERROR: QuPath exception
    at groovy
.lang.MetaClassImpl.invokeStaticMissingMethod(MetaClassImpl.java:1503)
    at groovy
.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1489)
    at org
.codehaus.groovy.runtime.callsite.StaticMetaClassSite.call(StaticMetaClassSite.java:53)
    at org
.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
    at org
.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
    at org
.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:133)
    at
Script72$_run_closure1.doCall(Script72.groovy:8)
    at
Script72$_run_closure1.doCall(Script72.groovy)
    at sun
.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun
.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun
.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java
.lang.reflect.Method.invoke(Method.java:498)
    at org
.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
    at groovy
.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
    at org
.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:294)
    at groovy
.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1024)
    at groovy
.lang.Closure.call(Closure.java:414)
    at groovy
.lang.Closure.call(Closure.java:408)
    at groovy
.lang.Closure.run(Closure.java:495)
    at com
.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
    at java
.security.AccessController.doPrivileged(Native Method)
    at com
.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294)
    at com
.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com
.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com
.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
    at java
.lang.Thread.run(Thread.java:745)

Any suggestions?

Caleb Grenko

unread,
Jun 1, 2018, 2:13:26 PM6/1/18
to QuPath users
update: I got it to launch by copying:


Platform.runLater {
   
QuPathGUI qupath = QuPathGUI.getInstance()
   
Stage stage = new Stage()
   
if (qupath != null)
        stage
.initOwner(qupath.getStage())
   
TMASummaryViewer tmaViewer = new TMASummaryViewer(stage)

   
ImageData<BufferedImage> imageData = qupath.getImageData()
   
if (imageData != null && imageData.getHierarchy().getTMAGrid() != null)
        tmaViewer
.setTMAEntriesFromImageData(imageData)

    tmaViewer
.getStage().show();
}

from the "TMAViewerCommand" run method. It works for now, but does anyone have any more elegant workarounds?

Pete

unread,
Jun 1, 2018, 4:09:16 PM6/1/18
to QuPath users
Not really - you could do

guiscript=true
new qupath.lib.gui.commands.TMAViewerCommand().run()

although I'm not sure if you really gain much, and you lose some control.

You also need guiscript=true to be the very first line of the script for it to have any impact... otherwise you will need the Platform.runLater part.

Caleb Grenko

unread,
Jun 1, 2018, 7:04:13 PM6/1/18
to QuPath users
Thanks for the reply! The good news is that your method works flawlessly when processing one image. However, when trying to do a batch process, the same window for the same image comes up multiple times, without any of the other TMAs being shown. The verbose way renders the same result, here's the code:

guiscript = true

import javafx.application.Platform
import javafx.stage.Stage
import qupath.lib.gui.QuPathGUI
import qupath.lib.gui.commands.TMAViewerCommand
import qupath.lib.gui.tma.TMASummaryViewer
import qupath.lib.scripting.QP
import java.awt.image.BufferedImage
import qupath.lib.images.ImageData



//Fetches image data, sets to Brightfield (other) and estimates stains if not set already
imageData
= QP.getCurrentImageData()
if(imageData.getImageType() != 'Brightfield (other)') {
 setImageType
('BRIGHTFIELD_OTHER')
 setColorDeconvolutionStains
('{"Name" : "H-DAB default", "Stain 1" : "Hematoxylin", "Values 1" : "0.5121 0.72726 0.45699 ", "Stain 2" : "DAB", "Values 2" : "0.30699 0.56046 0.76918 ", "Stain 3" : "Residual", "Values 3" : "0.11966 0.77495 0.62059 ", "Background" : " 255 255 255 "}');
}

//Dearrays TMA Cores
//Note: It is reccomended to manually set/inspect/correct the TMA cores, but if it has not been done already, it will approximate where they are
if (!isTMADearrayed()) {
 runPlugin
('qupath.imagej.detect.dearray.TMADearrayerPluginIJ', '{"coreDiameterMM": 0.7, "labelsHorizontal": "1-32", "labelsVertical": "A-Z", "labelOrder": "Row first", "densityThreshold": 35, "boundsScale": 105}')
}
selectTMACores
()

//Nucles detections + smooths features for less noise
runPlugin
('qupath.imagej.detect.nuclei.WatershedCellDetection', '{"detectionImageBrightfield": "Hematoxylin OD", "requestedPixelSizeMicrons": 0.5, "backgroundRadiusMicrons": 16.0, "medianRadiusMicrons": 1.5, "sigmaMicrons": 1.5, "minAreaMicrons": 10.0, "maxAreaMicrons": 400.0, "threshold": 0.1, "maxBackground": 2.0, "watershedPostProcess": true, "excludeDAB": false, "cellExpansionMicrons": 6.5, "includeNuclei": true, "smoothBoundaries": true, "makeMeasurements": true}');
runPlugin
('qupath.lib.plugins.objects.SmoothFeaturesPlugin', '{"fwhmMicrons": 15.0, "smoothWithinClasses": false, "useLegacyNames": false}')
runPlugin
('qupath.lib.plugins.objects.SmoothFeaturesPlugin', '{"fwhmMicrons": 50.0, "smoothWithinClasses": false, "useLegacyNames": false}')


//Run classifier stored in project directory
runClassifier
(getProjectBaseDirectory() + '\\classifiers\\CD8+CK TIL count (epithelium only).qpclassifier')

//Counting + Sorting positive versus negative tumor
tumorClass
= getPathClass("Tumor")
nTumor
= 0
nPositive
= 0

for (detection in getDetectionObjects()) {
 pathClass
= detection.getPathClass()
 
if (tumorClass.isAncestorOf(pathClass)) {
 nTumor
++
 
if(pathClass.toString() == "Tumor: Positive") {
 nPositive
++
 
}
 
}
}


//Calculate percentage of tumor positive for CD8
percentagePos
= (nPositive / nTumor) * 100

//ASCII Readout of total percent positive
print('\t\t --------------------------------------- ')
print('')
print("\t\t\t AVG CD8 TIL percentage: " + percentagePos + '%\t')
print('')
print('\t\t --------------------------------------- ')


//Launches TMA Summary Viewer
//new qupath.lib.gui.commands.TMAViewerCommand().run()

Platform.runLater {



 
Stage stage = new Stage()

 
QuPathGUI qupath = QuPathGUI.getInstance()


 
if (qupath != null)
 stage
.initOwner(qupath.getStage())
 
TMASummaryViewer tmaViewer = new TMASummaryViewer(stage)

 
ImageData<BufferedImage> imageData = qupath.getImageData()
 
if (imageData != null && imageData.getHierarchy().getTMAGrid() != null)
 tmaViewer
.setTMAEntriesFromImageData(imageData)

 tmaViewer
.getStage().show()

}

Is it possible to render a TMA Summary Table without having QuPath call up the image?

Pete

unread,
Jun 2, 2018, 11:16:02 AM6/2/18
to QuPath users
Possibly... I've never tried though, and I'm not sure it's necessary.

You can use File -> Export TMA data (and also use this in a script) to write a directory of TMA core images along with some summary results.  You can then open the TMA data viewer and just drag one of the directories onto the window.  If you've exported data from multiple images into the same directory, they should all be opened together in the data viewer.

That's the way it's intended to be used*.  It also has advantages in terms of memory; when the image is loaded, that means that all the cell data is being held in memory.  But if you export first, then only the summary data needs to be stored and shown in the table (and potentially the small exported images).

An extra benefit is that the data viewer can then group together cores that have the same Unique ID set (which you can set with File -> Import TMA map and Paste grid to paste from the system clipboard a rectangular grid containing identifiers, the same size as the TMA grid itself).


*-Admittedly, I don't recall if this is documented anywhere yet... one thing limiting the documentation is a lack of publicly available TMA datasets, based on whole slide images with associated survival information.  If you know of any, please do let me know... it would be great to be able to create a tutorial showing all this stuff, using data that is freely available for others to try.
Reply all
Reply to author
Forward
0 new messages