= Script Created During the QuPath Workshop =
Here is the collection of scripts that were produced during the workshop. In case you notice missing ones or have scripts to contribute yourself, please get in touch with either Romain or Oli.
== Reset Classification Of Cell Detections ==
```jang=java
resetIntensityClassification()
```
== Set The Classification For All Cells ==
```lang=java
// Define the classification with getPathClass (will create the classification if it does not exist
classification = getPathClass('Other')
getCellObjects().each {
it.setPathClass(classification)
}
fireHierarchyUpdate()
```
== Select All Child Objects In A Parent ==
```lang=java
hierarchy = getCurrentHierarchy()
// It is simply a matter of calling 'getChildObjects() from the currently selected one
annotations = getSelectedObject().getChildObjects()
// The line below makes the selection become active in the QuPath GUI
hierarchy.getSelectionModel().selectObjects(annotations)
```
== Prompting The User For The Location Where To Save a File ==
```lang=java
import qupath.lib.gui.QuPathGUI
// promptToSaveFile(title,base_directory,default_file_name, file_filter, extension)
def file = QuPathGUI.getSharedDialogHelper().promptToSaveFile("Title", null, null, "Text file", ".txt")
print file
```
== Create Detection Objects ==
```lang=java
/*
* Create detection objects.
* This is intended for use with OS-2.ndpi.
*/
import qupath.lib.roi.RectangleROI
import qupath.lib.objects.PathAnnotationObject
// Create a new rectangle annotation & add it to the hierarchy
def roi = new RectangleROI(55500, 35000, 5000, 5000)
def annotation = new PathAnnotationObject(roi)
addObject(annotation)
// Make sure the annotation is selected, and run nucleus detection
setSelectedObject(annotation)
runPlugin('qupath.imagej.detect.nuclei.PositiveCellDetection', '{"detectionImageBrightfield": "Hematoxylin OD", "requestedPixelSizeMicrons": 0.5, "backgroundRadiusMicrons": 8.0, "medianRadiusMicrons": 0.0, "sigmaMicrons": 1.5, "minAreaMicrons": 10.0, "maxAreaMicrons": 400.0, "threshold": 0.1, "maxBackground": 2.0, "watershedPostProcess": true, "excludeDAB": false, "cellExpansionMicrons": 0.0, "includeNuclei": true, "smoothBoundaries": true, "makeMeasurements": true, "thresholdCompartment": "Nucleus: DAB OD mean", "thresholdPositive1": 0.2, "thresholdPositive2": 0.4, "thresholdPositive3": 0.6, "singleThreshold": true}');
// Show what we've now got
print 'I now have ' + getDetectionObjects().size() + ' detection objects and ' + getAnnotationObjects().size() + ' annotation objects'
```
== Converting Detections To Annotations ==
```lang=java
Convert detection to annotations
/*
* Convert annotation objects to detections.
* Warning! This may be very slow, and a bad idea!
* It is intended to show the different behavior between
* detection & annotation objects.
*/
import qupath.lib.objects.PathAnnotationObject
// Create new annotations with the same ROIs and classifications as the detections
def detections = getDetectionObjects()
def newAnnotations = detections.collect {detection -> new PathAnnotationObject(detection.getROI(), detection.getPathClass())}
// Remove the detections, add the annotations
removeObjects(detections, false)
addObjects(newAnnotations)
```
== Fluorescence: Detect DAPI, Measure other channels ==
```lang=java
// Access Cells
cells = getCellObjects()
// Define Channel names and threshlold values
ch2Name = 'Nucleus: Channel 2 mean'
ch3Name = 'Nucleus: Channel 3 mean'
ch2Threshold = 20
ch3Threshold = 40
// Get or create classifications we will be using
doublePositive = getPathClass('Double-positive', getColorRGB(150,150,0))
ch2Positive = getPathClass('Ch2-Positive', getColorRGB(0,150,0))
ch3Positive = getPathClass('Ch3-Positive', getColorRGB(150,0,0))
negative = getPathClass('Negative')
// Loop through them and requestmeasurements
for(cell in cells) {
// Extract measurements for channels measurement(theAnnotation, measurementName)
ch2Measurement = measurement(cell, ch2Name)
ch3Measurement = measurement(cell, ch3Name)
if( ch2Measurement > ch2Threshold && ch3Measurement > ch3Threshold ) {
// Make double positive
cell.setPathClass(doublePositive)
} else if( ch2Measurement > ch2Threshold ) {
// Make ch2 positive
cell.setPathClass(ch2Positive)
} else if( ch3Measurement > ch3Threshold ) {
// Make ch3 positive
cell.setPathClass(ch3Positive)
} else {
// Make negative
cell.setPathClass(negative)
}
}
fireHierarchyUpdate()
```
== Save Cell Classification To Tab-Separated File ==
This script will add one row to the results file each time it is run with the count of each cell that matches the classifications we requested
```lang=java
// Create Output Path
outputPath = buildFilePath(PROJECT_BASE_DIR, 'export')
// Make directory in case it does not exist
mkdirs(outputPath )
// Give the results file a name
fileName = 'classification-result.txt'
// Get or create classifications and set colors
doublePositive = getPathClass('Double-positive', getColorRGB(150,150,0))
ch2Positive = getPathClass('Ch2-Positive', getColorRGB(0,150,0))
ch3Positive = getPathClass('Ch3-Positive', getColorRGB(150,0,0))
negative = getPathClass('Negative')
// Access Cells
cells = getCellObjects()
// User Groovy FindAll to get only the cells that match the desired classifications
doublePositiveCells = cells.findAll{ cell -> cell.getPathClass() == doublePositive }
ch2PositiveCells = cells.findAll{ cell -> cell.getPathClass() == ch2Positive }
ch3PositiveCells = cells.findAll{ cell -> cell.getPathClass() == ch3Positive }
negativeCells = cells.findAll{ cell -> cell.getPathClass() == negative }
// Write results in the desired directory to the desired filename
file = new File(outputPath, fileName)
// Define the delimiter to use, typically a comma or a tab as below
delimiter = '\t'
// Make sure the file exists, otherwise create and initialize it (write the column names)
if(!file.exists() ) {
file.text = 'Image Name' << delimiter <<
'Double Positive' << delimiter <<
'Ch2 Positive' << delimiter <<
'Ch3 Positive' << delimiter <<
'Negative' << delimiter << System.lineSeparator()
}
// Append the results to the end of the file
file << getProjectEntry().getImageName() << delimiter <<
doublePositiveCells.size() << delimiter <<
ch2PositiveCells.size() << delimiter <<
ch3PositiveCells.size() << delimiter <<
negativeCells.size() << delimiter << System.lineSeparator()
```
== Rename VSI Images ==
In the current version of QuPath, VSI files do not have their full names appended, so that when many files are imported onto a project, they all seem to have the same name. You can run this script to clean up the files. Note that you will need to run this script again the next time you open the project. this will be fixed in a coming release
```lang=java
guiscript=true
// solution from : https://github.com/qupath/qupath/issues/103
// Get QuPath & project
def qupath = getQuPath()
def project = qupath.getProject()
// Loop through images, setting the name
// (actually accessing a private field... therefore 'bad')
project.getImageList().each {
def path = it.getServerPath()
print " path=" + path
int ind = path.lastIndexOf(':')
if(ind>2) {
def scene = path[ind+1..-1]
def name = new File(path[0..ind-2]).getName()
it.putMetadataValue('Slide_ID', name)
it.imageName = name + ' (' + scene + ')'
}
}
```