imagej / pyimagej

Use ImageJ from Python
https://pyimagej.readthedocs.io/
Other
472 stars 82 forks source link

Support mixing Maven endpoints with local JARs #143

Closed tania-19 closed 3 years ago

tania-19 commented 3 years ago

I want to run pyimagej with my plugins with fiji on a remote server.

import imagej
import scyjava
plugins_dir = '/home/tania/programas/Fiji.app/plugins'
scyjava.config.add_option(f'-Dplugins.dir={plugins_dir}')
fiji_dep='sc.fiji:fiji:2.1.0'
scijava_command_dep = 'ch.epfl.biop:pyimagej-scijava-command:0.1.2'
ij = imagej.init([fiji_dep, scijava_command_dep], headless=False)

But it shows a warning:

17:12:27.633 [SciJava-5f577419-Thread-0] DEBUG loci.formats.ClassList - Could not find loci.formats.in.URLReader
java.lang.ClassNotFoundException: loci.formats.in.URLReader
    at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:419)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:352)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:264)
    at loci.formats.ClassList.parseLine(ClassList.java:196)
    at loci.formats.ClassList.parseFile(ClassList.java:258)
    at loci.formats.ClassList.<init>(ClassList.java:138)
    at loci.formats.ClassList.<init>(ClassList.java:122)
    at loci.formats.ImageReader.getDefaultReaderClasses(ImageReader.java:80)
    at io.scif.bf.BioFormatsFormat.cacheReaderClasses(BioFormatsFormat.java:538)
    at io.scif.bf.BioFormatsFormat.<init>(BioFormatsFormat.java:139)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at java.lang.Class.newInstance(Class.java:442)
    at org.scijava.plugin.PluginInfo.createInstance(PluginInfo.java:304)
    at org.scijava.plugin.DefaultPluginService.createInstance(DefaultPluginService.java:234)
    at org.scijava.plugin.DefaultPluginService.createInstances(DefaultPluginService.java:223)
    at org.scijava.plugin.DefaultPluginService.createInstancesOfType(DefaultPluginService.java:214)
    at io.scif.services.DefaultFormatService.lambda$initialize$0(DefaultFormatService.java:459)
    at org.scijava.thread.DefaultThreadService.lambda$wrap$1(DefaultThreadService.java:211)
    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:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
17:12:27.654 [SciJava-5f577419-Thread-0] DEBUG loci.formats.ClassList - Could not find loci.formats.in.SlideBook6Reader
java.lang.ClassNotFoundException: loci.formats.in.SlideBook6Reader
    at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:419)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:352)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:264)
    at loci.formats.ClassList.parseLine(ClassList.java:196)
    at loci.formats.ClassList.parseFile(ClassList.java:258)
    at loci.formats.ClassList.<init>(ClassList.java:138)
    at loci.formats.ClassList.<init>(ClassList.java:122)
    at loci.formats.ImageReader.getDefaultReaderClasses(ImageReader.java:80)
    at io.scif.bf.BioFormatsFormat.cacheReaderClasses(BioFormatsFormat.java:538)
    at io.scif.bf.BioFormatsFormat.<init>(BioFormatsFormat.java:139)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at java.lang.Class.newInstance(Class.java:442)
    at org.scijava.plugin.PluginInfo.createInstance(PluginInfo.java:304)
    at org.scijava.plugin.DefaultPluginService.createInstance(DefaultPluginService.java:234)
    at org.scijava.plugin.DefaultPluginService.createInstances(DefaultPluginService.java:223)
    at org.scijava.plugin.DefaultPluginService.createInstancesOfType(DefaultPluginService.java:214)
    at io.scif.services.DefaultFormatService.lambda$initialize$0(DefaultFormatService.java:459)
    at org.scijava.thread.DefaultThreadService.lambda$wrap$1(DefaultThreadService.java:211)
    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:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
17:12:27.655 [SciJava-5f577419-Thread-0] DEBUG loci.formats.ClassList - Could not find loci.formats.in.ScreenReader
java.lang.ClassNotFoundException: loci.formats.in.ScreenReader
    at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:419)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:352)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:264)
    at loci.formats.ClassList.parseLine(ClassList.java:196)
    at loci.formats.ClassList.parseFile(ClassList.java:258)
    at loci.formats.ClassList.<init>(ClassList.java:138)
    at loci.formats.ClassList.<init>(ClassList.java:122)
    at loci.formats.ImageReader.getDefaultReaderClasses(ImageReader.java:80)
    at io.scif.bf.BioFormatsFormat.cacheReaderClasses(BioFormatsFormat.java:538)
    at io.scif.bf.BioFormatsFormat.<init>(BioFormatsFormat.java:139)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at java.lang.Class.newInstance(Class.java:442)
    at org.scijava.plugin.PluginInfo.createInstance(PluginInfo.java:304)
    at org.scijava.plugin.DefaultPluginService.createInstance(DefaultPluginService.java:234)
    at org.scijava.plugin.DefaultPluginService.createInstances(DefaultPluginService.java:223)
    at org.scijava.plugin.DefaultPluginService.createInstancesOfType(DefaultPluginService.java:214)
    at io.scif.services.DefaultFormatService.lambda$initialize$0(DefaultFormatService.java:459)
    at org.scijava.thread.DefaultThreadService.lambda$wrap$1(DefaultThreadService.java:211)
    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:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

And when I open the gui and try to use the plugin Action Bar this appears: image

I also try this:

import imagej
import scyjava
plugins_dir = '/home/tania/programas/Fiji.app/plugins'
scyjava.config.add_option(f'-Dplugins.dir={plugins_dir}')
fiji_dep='sc.fiji:fiji:2.1.0'
ij = imagej.init([fiji_dep], headless=False)

and the error is the same

hinerm commented 3 years ago

@tania-19 I would try to avoid manually setting the plugins.dir.. is there a maven endpoint that contains Action Bar?

Or, if your local /home/tania/programas/Fiji.app has the plugins you want, what happens if you just do a local PyImageJ initialization?

ij = imagej.init('/home/tania/programas/Fiji.app/', headless=False)
ctrueden commented 3 years ago

@tania-19 Could you see whether this does the job for you?

import imagej
import jpype
plugins_dir = '/home/tania/programas/Fiji.app/plugins'
jpype.addClassPath(f'{plugins_dir}/*') # add all .jar files in the local Fiji installation's plugins folder (non-recursive)
ij = imagej.init('sc.fiji:fiji:2.3.1', headless=False)
ctrueden commented 3 years ago

The only thing I see to do, possibly, on the PyImageJ/scyjava side would be to add a scyjava.add_classpath_recursive(...) function or similar, that is just a transplanted version of PyImageJ's currently internal _search_for_jars function. I am personally in favor; then we could recommend people to call such a function on their Fiji plugins folder locally, and it would include JARs in subfolders of plugins. However, there is a problem in that plugins will contain many JARs locally that already get brought in by Maven, and then the classpath will have duplicate classes at potentially different versions. So one must do this with care!

ctrueden commented 3 years ago

@tania-19 It looks like the Action Bar only depends on ImageJ 1.x, SciJava Common, and BeanShell, all of which are already part of sc.fiji:fiji. So it might be enough to do:

import imagej
import jpype
action_bar = '/home/tania/programas/Fiji.app/plugins/action_bar-2.0.4.jar' # or whatever the filename is
jpype.addClassPath(action_bar)
ij = imagej.init('sc.fiji:fiji:2.3.1', headless=False)

Does it work?

Otherwise, I agree with @hinerm that you could simply go "all local":

import imagej
ij = imagej.init('/home/tania/programas/Fiji.app', headless=False)

(I'm curious why you need to mix and match the styles.)

tania-19 commented 3 years ago

Thanks for your answers!!

If I do my local PyImageJ initialization as @hinerm mention, it works.

However, my goal is to usefiji+action bar plugin+ScijavaCommand decorator(like this notebook), and I haven't been able to install the necessary dependencies on my local fiji. That is why I was trying to use a remote fiji with scijava_command_dep+ action bar plugin.

I try the suggestion of @ctrueden but it didn't work for me :cry:

hinerm commented 3 years ago

@tania-19 I see so I assume you have a local Fiji.app with Action Bar but not pyimagej-scijava-commad? Unfortunately I don't see any update sites hosting either of these, but you can manually download a pyimagej-scijava-command release and copy it to your Fiji.app/plugins directory. If you have both locally then just use the local initialization method I pasted above.

NicoKiaru commented 3 years ago

Oh, nice, somebody's using it! pyimage-scijava-command is not in an update site, but it is on maven : https://maven.scijava.org/#nexus-search;quick~pyimagej

@hinerm : can't this maven artifact be used ch.epfl.biop:pyimagej-scijava-command:0.1.3, instead of an update site ?

ctrueden commented 3 years ago

@NicoKiaru Yes, I think the issue is that @tania-19 wants to combine pyimagej-scijava-command with the ActionBar. But pyimagej-scijava-command is not available to local Fijis via an update site, and ActionBar is not available as a Maven artifact. So @tania-19 was trying to launch Fiji+pyimagej-scijava-command the Maven way, and then use a plugins.dir pointing to a folder containing the Action_Bar plugin as well. @hinerm's suggestion is to do it all from a local installation: download Fiji, drop in the pyimagej-scijava-command JAR, drop in the Action Bar, then initialize locally. I'm disappointed my idea of augmenting the Maven-based environment with addClassPath isn't working, though!

ctrueden commented 3 years ago

Relatedly: as part of closing this issue, we will need to update the documentation here:

https://github.com/imagej/pyimagej/blob/31f60c8c3cc25340aa70d2095b8dd69175339326/doc/Initialization.md#plugins-without-maven-endpoints

Option (2) outlined there is exactly what this issue description describes as attempted but non-working. So the documentation there is currently wrong, since it doesn't work.

imagesc-bot commented 3 years ago

This issue has been mentioned on Image.sc Forum. There might be relevant details there:

https://forum.image.sc/t/use-fiji-update-in-pyimagej/52137/7

tania-19 commented 3 years ago

I want to use Fiji+Action Bar+ ScijavaCommand decorator.

@tania-19 I see so I assume you have a local Fiji.app with Action Bar but not pyimagej-scijava-commad? Unfortunately I don't see any update sites hosting either of these, but you can manually download a pyimagej-scijava-command release and copy it to your Fiji.app/plugins directory. If you have both locally then just use the local initialization method I pasted above.

If I use the local initialization and install pyimagej-scijava-command as @hinerm suggested, this plugin works fine!! However, the Action Bar plugin don't, and I think it is related with the directory.

When I want to create a new menu, I can go to plugins->Action Bar and the window below is open: image However then i get this exception:

(Fiji Is Just) ImageJ 2.3.0/1.53m; Java 1.8.0_302 [64-bit]; Linux 5.4.0-84-generic; 156MB of 3532MB (4%)

java.lang.RuntimeException: Cannot find resource '/ActionBar/new_action_bar_3.txt'
    at Action_Bar.getURL(Action_Bar.java:355)
    at Action_Bar.run(Action_Bar.java:152)
    at ij.IJ.runUserPlugIn(IJ.java:243)
    at ij.IJ.runPlugIn(IJ.java:204)
    at ij.Executer.runCommand(Executer.java:151)
    at ij.Executer.run(Executer.java:69)
    at ij.IJ.run(IJ.java:325)
    at ij.IJ.run(IJ.java:336)
    at ij.macro.Functions.doRun(Functions.java:692)
    at ij.macro.Functions.doFunction(Functions.java:98)
    at ij.macro.Interpreter.doStatement(Interpreter.java:281)
    at ij.macro.Interpreter.doBlock(Interpreter.java:715)
    at ij.macro.Interpreter.doStatement(Interpreter.java:326)
    at ij.macro.Interpreter.doIf(Interpreter.java:1116)
    at ij.macro.Interpreter.doStatement(Interpreter.java:302)
    at ij.macro.Interpreter.doStatements(Interpreter.java:267)
    at ij.macro.Interpreter.run(Interpreter.java:163)
    at ij.macro.Interpreter.run(Interpreter.java:93)
    at ij.macro.MacroRunner.run(MacroRunner.java:139)
    at java.lang.Thread.run(Thread.java:748)

And I can't use the created menu.

hinerm commented 3 years ago

java.lang.RuntimeException: Cannot find resource '/ActionBar/new_action_bar_3.txt'

@tania-19 it looks like the ActionBar plugin was written with the assumption that the current working directory is the Fiji.app directory.

You can work around this by starting your python interpreter from the Fiji.app directory. I did this and tested action_bar and can confirm it fixes the issue.

I also opened a new issue (#150) to discuss if we should automatically set the working directory on startup

hinerm commented 3 years ago

@tania-19 I'm closing the issue for now since I was able to get Action Bar running in pyimagej locally. If you run into any other issues please feel free to reopen! And thank you for taking the time to report and troubleshoot with us. 😄

tania-19 commented 3 years ago

Thanks @hinerm, I try to change the directory on the notebook, but it didn't work out. I run this macro script:

exec("ls")
run("Action Bar","/plugins/ActionBar/new_action_bar.txt");
exit();

To ensure I was in the correct directory(on the log window we see the Action Bar folder), and here are the results: image But the problem persist

NicoKiaru commented 3 years ago

Just in case this is still relevant, the update site https://biop.epfl.ch/Fiji-ABBA-Exp/ now contains a pyimagej-scijava-command

hinerm commented 3 years ago

@tania-19 You likely need to re-run Plugins > Action Bar > Action Bar to create the re-action bar.

When you ran it before, it would have created a folder called Action Bar in whichever directory you had started python from. For example, if you start python in the Desktop directory, you would have ended up with a Desktop/Action Bar/new_action_bar.txt, which is then not found when you run the macro pointing to plugins/Action Bar/new_action_bar.txt.

You could also just move the Action Bar folder manually to the Fiji.app/plugins directory, instead of re-creating it.

Just to summarize everything, I'm using this python script (which can be run from anywhere because of the os.chdir line):

fiji_path='C:\\Users\\hiner\\Desktop\\Fiji.app'
import os
os.chdir(fiji_path)
import imagej
ij = imagej.init(fiji_path, headless=False)
ij.ui().showUI()

When Fiji opens I use Plugins > Action Bar > Action Bar to create and show the action bar, and also brings up the script editor with an IJ Macro starting with:

run("Action Bar","/plugins/ActionBar/new_action_bar.txt");
exit();
...

This macro is just used to show an existing action bar - it won't create a new one if the specified path doesn't already exist. At this point, I can now close the action bar and run the macro to show it again.

tania-19 commented 3 years ago

Thanks for everything @hinerm. Now It works for me too!!