Batch export annotation measures - m5

Does anyone have updated scripts for batch exporting annotation measurements, merging annotation results, importing/exporting annotation coordinates? The current scripts I have unfortunately are not compatible with milestone 5.

Please see the scripts below:
Exporting annotation measures

/*
 * QuPath v0.1.2 has some bugs that make exporting annotations a bit annoying, specifically it doesn't include the 'dot' 
 * needed in the filename if you run it in batch, and it might put the 'slashes' the wrong way on Windows.
 * Manually fixing these afterwards is not very fun.
 * 
 * Anyhow, until this is fixed you could try the following script with Run -> Run for Project.
 * It should create a new subdirectory in the project, and write text files containing results there.
 *
 * @author Pete Bankhead
 */
 
def name = getProjectEntry().getImageName() + '.txt'
def path = buildFilePath(PROJECT_BASE_DIR, 'STAIN PARAMETERS LASTNAME')
mkdirs(path)
path = buildFilePath(path, name)
saveAnnotationMeasurements(path)
print 'Results exported to ' + path

Combine annotation measurments

import qupath.lib.gui.QuPathGUI

// Some parameters you might want to change...
String ext = '.txt' // File extension to search for
String delimiter = '\t' // Use tab-delimiter (this is for the *input*, not the output)
String outputName = 'STAIN PARAMETERS LASTNAME.txt' // Name to use for output; use .csv if you really want comma separators

// Prompt for directory containing the results
def dirResults = QuPathGUI.getSharedDialogHelper().promptForDirectory()
if (dirResults == null)
    return
def fileResults = new File(dirResults, outputName)

// Get a list of all the files to merge
def files = dirResults.listFiles({
    File f -> f.isFile() &&
            f.getName().toLowerCase().endsWith(ext) &&
            f.getName() != outputName} as FileFilter)
if (files.size() <= 1) {
    print 'At least two results files needed to merge!'
    return
} else
    print 'Will try to merge ' + files.size() + ' files'

// Represent final results as a 'list of maps'
def results = new ArrayList<Map<String, String>>()

// Store all column names that we see - not all files necessarily have all columns
def allColumns = new LinkedHashSet<String>()
allColumns.add('File name')

// Loop through the files
for (file in files) {
    // Check if we have anything to read
    def lines = file.readLines()
    if (lines.size() <= 1) {
        print 'No results found in ' + file
        continue
    }
    // Get the header columns
    def iter = lines.iterator()
    def columns = iter.next().split(delimiter)
    allColumns.addAll(columns)
    // Create the entries
    while (iter.hasNext()) {
        def line = iter.next()
        if (line.isEmpty())
            continue
        def map = ['File name': file.getName()]
        def values = line.split(delimiter)
        // Check if we have the expected number of columns
        if (values.size() != columns.size()) {
            print String.format('Number of entries (%d) does not match the number of columns (%d)!', columns.size(), values.size())
            print('I will stop processing ' + file.getName())
            break
        }
        // Store the results
        for (int i = 0; i < columns.size(); i++)
            map[columns[i]] = values[i]
        results.add(map)
    }
}

// Create a new results file - using a comma delimiter if the extension is csv
if (outputName.toLowerCase().endsWith('.csv'))
    delimiter = ','
int count = 0
fileResults.withPrintWriter {
    def header = String.join(delimiter, allColumns)
    it.println(header)
    // Add each of the results, with blank columns for missing values
    for (result in results) {
        for (column in allColumns) {
            it.print(result.getOrDefault(column, ''))
            it.print(delimiter)
        }
        it.println()
        count++
    }
}

// Success!  Hopefully...
print 'Done! ' + count + ' result(s) written to ' + fileResults.getAbsolutePath()

Exporting annotation coordinates

//this script exports annotation coordinates to the project directory
def path = buildFilePath(PROJECT_BASE_DIR, 'annotations-' + getProjectEntry().getImageName() + '.txt')
def annotations = getAnnotationObjects()
new File(path).withObjectOutputStream {
    it.writeObject(annotations)
}
print 'Done!'

Importing annotation coordinates

//this script exports annotation coordinates to the project directory
def path = buildFilePath(PROJECT_BASE_DIR, 'annotations-' + getProjectEntry().getImageName() + '.txt')
def annotations = getAnnotationObjects()
new File(path).withObjectOutputStream {
    it.writeObject(annotations)
}
print 'Done!'

All of the default export and import scripts shouldn’t have changed with M5 or 6. Those look to be straight off of the blog, so they should work as long as your version of QuPath hasn’t been modified. Could you explain where you are getting errors, provide an error log, or something similar?

I quickly checked, and I have run at least the first two scripts many times now for M5 projects. And I coped and pasted those two straight from your post into an M5 project and they worked for me, so I can’t currently reproduce this.

1 Like