Exporting annotations between different versions of QuPath

Hello,
I have made manual annotations on czi files in v0.2.0-m2.
I was wondering if there was a way to transfer the annotations to the same files in v0.1.2?

Have you tried this?
https://groups.google.com/d/msg/qupath-users/UvkNb54fYco/heaFghrFAQAJ

I haven’t yet so I’m not sure if the scripts still work in 0.2.0

Hi, yes I did but the script did not run

Hi, the script did run this time however I received an error message saying the system cannot find the file specified. Could this be because my file is stored on a shared drive instead of an ‘image’ folder in the project folder ?

I also received the following error message:

ERROR: Script error
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.(FileInputStream.java:138)
at org.codehaus.groovy.runtime.ResourceGroovyMethods.newObjectInputStream(ResourceGroovyMethods.java:166)
at org.codehaus.groovy.runtime.ResourceGroovyMethods.withObjectInputStream(ResourceGroovyMethods.java:208)
at org.codehaus.groovy.runtime.dgm$1021.invoke(Unknown Source)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:274)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:56)
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:125)
at Script2.run(Script2.groovy:4)
at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:343)
at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:152)
at qupath.lib.scripting.DefaultScriptEditor.executeScript(DefaultScriptEditor.java:765)
at qupath.lib.scripting.DefaultScriptEditor.executeScript(DefaultScriptEditor.java:695)
at qupath.lib.scripting.DefaultScriptEditor.executeScript(DefaultScriptEditor.java:677)
at qupath.lib.scripting.DefaultScriptEditor.access$400(DefaultScriptEditor.java:136)
at qupath.lib.scripting.DefaultScriptEditor$2.run(DefaultScriptEditor.java:1029)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)

Which script were you working with? There are at least two scripts, one to write out the annotations, and another to read them back into the file.

Also be aware that even this might not work well if you are using an OpenSlide server, as some of the coordinates may have changed.

I just went ahead and tested it and was able to transfer annotations into the same image between two projects, one in 0.2.0m2 and the other in 0.1.3. You do need to have a project for both. If you want to run this for multiple images, you will need to adapt the script because it only saves a single file called “annotations.” If you run for project, you will overwrite the same file many times.

And to specify, though it is fairly straightforward, the file with the annotations that you are copying needs to be in that same exact place in each project folder, unless you change the “path” variable.

@clare it would be helpful if you could provide more details about what exactly you want to do and what is the end goal. The type of solution (and how complex it would be to create) really depends on the details.

For example:

  • it will be easier to handle a project with 10-20 images than one with 1000 images
  • if your CZI files contain a single image it will be easier than if they contain multiple images
  • it’s also easier if you just need to get the entire data files into a v0.1.2-compatible form. If you need to merge annotations from v0.2.0-m2 with other data generated in an earlier version (e.g. cell detection) then that may be a lot more complicated.

I used this script for copying the annotations in an image in 0.2.0m2:

def path = buildFilePath(PROJECT_BASE_DIR, ‘annotations’)

def annotations = getAnnotationObjects()

new File(path).withObjectOutputStream {

it.writeObject(annotations)

}

print ‘Done!’

and then this one for pasting the annotations in the same image in 0.1.2:
def path = buildFilePath(PROJECT_BASE_DIR, ‘annotations’)

def annotations = null

new File(path).withObjectInputStream {

annotations = it.readObject()

}

addObjects(annotations)

print 'Added ’ + annotations

Hi Pete,
The project with the annotations in 0.2.0m2 has 19 files. They are single image czi files. I want to tranfer the same annotations to the same images in another project in v0.1.2. The project in the old version is larger as it also contains czi files with multipple images, which I couldn’t open in m2. So I’m trying to compile all the images into a single project in the old version.
There are only manual annotations, no cell detection has been done.

Just to clarify, each time you run the script on the image, you have moved the “annotations” file from the 0.2.0m2 project into the 0.1.2 project before running the second script?
*It doesn’t matter where the images are, I think, just where the exported file ends up. I get exactly that error message if I don’t copy the file over.

@smcardle Didn’t you guys have a script from the LJI event that saved and loaded a whole project of annotations? I took a quick look to dig it up by email but failed to find it. Figured why reinvent the wheel…

By annotations file, do you mean the data file?

The file the first script creates is called “annotations” with no extension. That is the file that needs to be transferred.

I ran the first script on the annotated image, copied the annotations file that was generated and pasted it in the folder which has the m2 project file (onto which I want to paste the annotation), then ran the second script on the corresponding image in the m2 project.
Got the following error message:
ERROR: Error: startup failed:
Script1.groovy: 8: expecting ‘’’, found ‘\n’ @ line 8, column 29.
print 'Added ’ + annotations
^

1 error

ERROR: Script error
at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:310)
at org.codehaus.groovy.control.ErrorCollector.addFatalError(ErrorCollector.java:150)
at org.codehaus.groovy.control.ErrorCollector.addError(ErrorCollector.java:120)
at org.codehaus.groovy.control.ErrorCollector.addError(ErrorCollector.java:132)
at org.codehaus.groovy.control.SourceUnit.addError(SourceUnit.java:360)
at org.codehaus.groovy.antlr.AntlrParserPlugin.transformCSTIntoAST(AntlrParserPlugin.java:140)
at org.codehaus.groovy.antlr.AntlrParserPlugin.parseCST(AntlrParserPlugin.java:111)
at org.codehaus.groovy.control.SourceUnit.parse(SourceUnit.java:237)
at org.codehaus.groovy.control.CompilationUnit$1.call(CompilationUnit.java:167)
at org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:931)
at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:593)
at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:569)
at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:546)
at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:298)
at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:268)
at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:254)
at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:211)
at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.getScriptClass(GroovyScriptEngineImpl.java:363)
at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:150)
at qupath.lib.scripting.DefaultScriptEditor.executeScript(DefaultScriptEditor.java:765)
at qupath.lib.scripting.DefaultScriptEditor.executeScript(DefaultScriptEditor.java:695)
at qupath.lib.scripting.DefaultScriptEditor.executeScript(DefaultScriptEditor.java:677)
at qupath.lib.scripting.DefaultScriptEditor.access$400(DefaultScriptEditor.java:136)
at qupath.lib.scripting.DefaultScriptEditor$2.run(DefaultScriptEditor.java:1029)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)

I can’t tell without seeing the exact script, but I have a feeling that is a copy and paste error. Try removing the “print” line entirely.

This is the script I’m using (the second one):
def path = buildFilePath(PROJECT_BASE_DIR, ‘annotations’)
def annotations = null
new File(path).withObjectInputStream {
annotations = it.readObject()
}
addObjects(annotations)

I removed the print line as you suggested and recieved a new error:
ERROR: Error: startup failed:
Script2.groovy: 2: Invalid variable name. Must start with a letter but was: ‘annotations’
. At [2:44] @ line 2, column 44.
ildFilePath(PROJECT_BASE_DIR, ‘annotatio
^

1 error

ERROR: Script error
at org.codehaus.groovy.control.ErrorCollector.failIfErrors(ErrorCollector.java:310)
at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:1073)
at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:591)
at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:569)
at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:546)
at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:298)
at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:268)
at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:254)
at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:211)
at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.getScriptClass(GroovyScriptEngineImpl.java:363)
at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:150)
at qupath.lib.scripting.DefaultScriptEditor.executeScript(DefaultScriptEditor.java:765)
at qupath.lib.scripting.DefaultScriptEditor.executeScript(DefaultScriptEditor.java:695)
at qupath.lib.scripting.DefaultScriptEditor.executeScript(DefaultScriptEditor.java:677)
at qupath.lib.scripting.DefaultScriptEditor.access$400(DefaultScriptEditor.java:136)
at qupath.lib.scripting.DefaultScriptEditor$2.run(DefaultScriptEditor.java:1029)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)

Should I remove the print line from the first script as well and try again? Also, should the annotations file be added to a specific folder (the data folder) or no?

The file needs to be in the base project folder, the same place it was taken from.

Sorry, I should have specified, you need to post the script as a script, not as text. That is frequently part of the problem since things like quotation marks are changed during posting if you don’t select it as preformatted text. See here for more details.

This also might be an OS thing, maybe Pete has more experience if certain lines of code don’t copy over well onto a Mac or something like that. On a PC I was able to directly copy and paste the code from the old forum into m2 and 0.1.3 and have it work. Maybe a snipped image of the code in the Script editor window would show what is going on.

def path = buildFilePath(PROJECT_BASE_DIR, 'annotations')
def annotations = null
new File(path).withObjectInputStream {
    annotations = it.readObject()
}
addObjects(annotations)

Sorry, here’s the second script posted selecting the preformatted text.
Also, I’m working on a PC too.

Script

it worked!!!

1 Like

Thank you so much!!!