Reading csv table in QuPath

Hello and Happy New Year!

I’m trying to write some scripts to draw randomly generated square annotations of fixed size within another larger annotation.

So far I’ve managed to:

  1. Extract ROI coordinates of the larger annotation as an array and export as a txt file from QuPath.
  2. Randomly generate any desired number of coordinates to draw squares of defined size constrained within the annotation, and exporting these coordinates as [x, y] in a csv using Python.

Now I am trying to get QuPath to read this csv and plug the coordinates into a modified version of Pete’s script to draw the squares.

My csv looks like this:


And the modified script will kind of look like this:

// Get location of csv
def file = getQuPath().getDialogHelper().promptForFile(null)

<insert code to read csv>  // I'm here

int sizePixels = 1000
int numSquares = 5 // or count number of data rows

for loop {  // sorry, I'm not fully proficient with groovy yet
   double cx = <read each row, column x>
   double cy = <read each row, column y>

   def roi = new RectangleROI(cx-sizePixels/2, cy-sizePixels/2, sizePixels, sizePixels)
   def annotation = new PathAnnotationObject(roi, PathClassFactory.getPathClass("Region"))
   imageData.getHierarchy().addPathObject(annotation, false)

I’ve Googled and tried using parseCsv by import static com.xlson.groovycsv.CsvParser.parseCsv but QuPath doesn’t seem to recognise it.

Is there a way for QuPath to read csv and extract data from rows/columns?

Just a quick check, but is there a particular need to export and import the coordinates rather than generating the random squares entirely inside QuPath?

Anyway, if you have the csv files already, I recommend looking up the Groovy read file syntax. You can strip out the first line, split the remaining lines by commas, and use the coordinates within each split to generate your squares.

This code should do!
It reads through all the rows of the CSV (except the header) and gets the x and y coordinates.

import qupath.lib.objects.PathAnnotationObject;
import qupath.lib.roi.RectangleROI;

def imageData = getCurrentImageData();

// Get location of csv
def file = getQuPath().getDialogHelper().promptForFile(null)

// Create BufferedReader
def csvReader = new BufferedReader(new FileReader(file));

int sizePixels = 1000
row = csvReader.readLine() // first row (header)

// Loop through all the rows of the CSV file.
while ((row = csvReader.readLine()) != null) {
    def rowContent = row.split(",")
    double cx = rowContent[1] as double;
    double cy = rowContent[2] as double;

    // Create annotation
    def roi = new RectangleROI(cx-sizePixels/2, cy-sizePixels/2, sizePixels, sizePixels);
    def annotation = new PathAnnotationObject(roi, PathClassFactory.getPathClass("Region"));
    imageData.getHierarchy().addPathObject(annotation, true);

The only reason is that I am re-using the Python script I already have for when I was working with ImageJ, and I didn’t want to re-invent the wheel… The QuPath documentation also mentioned that the Python interpreters were not that reliable when it comes to importing packages.

Amazing! Thank you for the extremely quick response! I will try your code and get back if there’s any issues.

1 Like