Importing annotations

Hi Everyone,

I have a list of x-y coordinates of the boundary of different regions and their name of a WSI.
What is the best way to import these regions as annotations in QuPath keeping the names?
Ideally I would like QuPath to read it from a file, csv etc.
I have seen that GeoJSON could be a nice way QuPath friendly of proceeding (like explained here Drawing custom annotations)… but where can i find the JsonSlurper class?

Thank you for your help !

Hi @TreyRollit,

This script should import GeoJSON format back into QuPath:


// Instantiate tools
def gson = GsonTools.getInstance(true)

// Prepare template
def type = new<List<qupath.lib.objects.PathObject>>() {}.getType();
def json_fp = promptForFile(null)

// Read annotations
bufferedReader = new BufferedReader(new FileReader(json_fp))
deserializedAnnotations = gson.fromJson(bufferedReader.text, type)

// Add to dataset

// Resolve hierarchy

print "Done!"

I can’t quite remember if names are kept during the import though.

Thank you @melvingelbard !
is it the right template/content which should be in a json file?

    "type": "Feature",
    "id": "PathAnnotationObject",
    "geometry": {
      "type": "Polygon",
      "coordinates": [
          [15992, 6551],
          [10451, 18011],
          [16118, 21159],
          [9569, 31485],
          [17503, 24937],
          [37526, 13225],
          [15866, 16625],
          [15992, 6551]
    "properties": {
      "name": "ROI1",
      "color": [
      "isLocked": false,
      "measurements": []

I got that from a polygonal annotation created within QuPath:

def annotations = getAnnotationObjects()
def gson = GsonTools.getInstance(true)
def json = gson.toJson(annotations)

println json

That I have naively copy-pasted in a text editor and saved as a *.json file. However when I use your code I have the following error:

ERROR: IllegalStateException at line 13: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $

ERROR:$$$fromJson$ Source)
java.base/java.util.concurrent.Executors$ Source)
java.base/ Source)
java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
java.base/java.util.concurrent.ThreadPoolExecutor$ Source)
java.base/ Source)

Do you have any idea? What am I doing wrong?

Thank you!!!

Yes, you need to add [ at the beginning of the file and ] at the end!

Gosh… :slight_smile: I feel stupid!
A big thank you for your help @melvingelbard !!!
It works like a charm now.

1 Like

I believe both are valid GeoJSON :slight_smile: Surrounded by [...] you have an array of objects, otherwise just a single object. But if you just have a single object, then you’d have to change your type to

def type = qupath.lib.objects.PathObject

(Haven’t actually tested this to confirm no other changes are needed… but that’s the right idea anyway)

Thank you @petebankhead for the clarification!