I am writing an imageJ/Fiji plugin in Jython using the Fiji script editor. I need to import external numerical libraries such as ParallelColt to help me handle multidimensional matrices.
I began with ParallelColt by placing its jar file in the java folder inside Fiji: "Fiji.app/java/macosx-java3d/Home/lib/ext” Then I tried importing it by writing: "import ParallelColt” or more specifically "from ParallelColt import jplasma" And I get an error of module not found.
I tried placing the jar inside the Fiji plugins folder instead but with still no success. I also tried by using the folder with all the java classes of ParallelColt instead of the jar file and I still was not able to import the classes from my script.
The question perhaps that I am simply asking is how to import java libraries from a Jython script. Any help will be greatly appreciated.
There are two issues here.
In order to depend on a complex third party software project with multiple JAR files, you need to make sure you have placed all the dependencies of the project (i.e., all the JAR files it needs) into ImageJ.app/jars
.
One way to do it is to find the dependencies on Maven Central and then use a build tool such as Maven or Gradle to download them.
In your case, you can do this with Maven by crafting the following pom.xml
file:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>dummy</groupId>
<artifactId>dummy</artifactId>
<version>0.0.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>net.sourceforge.parallelcolt</groupId>
<artifactId>parallelcolt</artifactId>
<version>0.10.1</version>
</dependency>
<dependency>
<groupId>net.mikera</groupId>
<artifactId>vectorz</artifactId>
<version>0.34.0</version>
</dependency>
</dependencies>
</project>
Then executing:
mvn dependency:copy-dependencies
This will result in the following files in the target/dependencies
folder:
29087 AMDJ-1.0.1.jar
8687 BTFJ-1.0.1.jar
19900 COLAMDJ-1.0.1.jar
55638 JKLU-1.0.0.jar
1194003 arpack_combined_all-0.1.jar
31162 core-lapack-0.1.jar
212836 csparsej-1.1.1.jar
88639 edn-java-0.4.4.jar
91793 jplasma-1.2.0.jar
762778 jtransforms-2.4.0.jar
237344 junit-4.8.2.jar
8693 mathz-0.3.0.jar
131210 netlib-java-0.9.3.jar
66134 optimization-1.0.jar
4111744 parallelcolt-0.10.1.jar
14028 randomz-0.3.0.jar
593015 vectorz-0.34.0.jar
Move these into your ImageJ.app/jars
folder, and you should be good to go—though beware of multiple versions of the same library, since ImageJ cannot handle that right now.
The line from ParallelColt import jplasma
is not valid. That is, there is no ParallelColt.jplasma
Java class or package. You can verify this yourself from the command line:
$ find-class() { for f in *.jar; do result=$(jar tf "$f" | grep -l "$@"); if [ "$result" != "" ]; then echo $f; fi; done; }
$ cd ImageJ.app/jars
$ find-class jplasma
Two JAR files have classes containing that string:
core-lapack-0.1.jar
jplasma-1.2.0.jar
And taking a look inside of them quickly reveals that the package names do not start with ParallelColt
:
$ jar tf jplasma-1.2.0.jar | grep jplasma
edu/emory/mathcs/jplasma/
edu/emory/mathcs/jplasma/benchmark/
edu/emory/mathcs/jplasma/test/
edu/emory/mathcs/jplasma/tdouble/
edu/emory/mathcs/jplasma/example/
edu/emory/mathcs/jplasma/benchmark/DgelsBenchmark.class
edu/emory/mathcs/jplasma/benchmark/DposvBenchmark.class
edu/emory/mathcs/jplasma/benchmark/DgesvBenchmark.class
edu/emory/mathcs/jplasma/Barrier.class
edu/emory/mathcs/jplasma/test/DposvTest.class
edu/emory/mathcs/jplasma/test/DgelsTest.class
edu/emory/mathcs/jplasma/test/DgesvTest.class
edu/emory/mathcs/jplasma/tdouble/Dgels.class
edu/emory/mathcs/jplasma/tdouble/Dgeqrf.class
edu/emory/mathcs/jplasma/tdouble/Dglobal$Dplasma_cntrl.class
edu/emory/mathcs/jplasma/tdouble/Dplasma.class
...
edu/emory/mathcs/jplasma/tdouble/Dglobal$Dplasma_aux.class
edu/emory/mathcs/jplasma/tdouble/Pdormqr.class
edu/emory/mathcs/jplasma/example/DposvExample.class
edu/emory/mathcs/jplasma/example/DgesvExample.class
edu/emory/mathcs/jplasma/example/DgelsExample.class
Rather, if you would like to use, e.g., edu.emory.mathcs.jplasma.tdouble.Dplasma
, you need to import it as:
from edu.emory.mathcs.jplasma.tdouble import Dplasma
Here is a port of DgelsExample.java from the JPlasma distribution which works in the ImageJ Script Editor:
from edu.emory.mathcs.jplasma.tdouble import Dplasma
from java.lang import Math
import jarray
M = 15;
N = 10;
NRHS = 5;
A = jarray.zeros(M * N, 'd')
B = jarray.zeros(M * NRHS, 'd')
# Initialize A
for i in range(0, M):
for j in range(0, N):
A[M * j + i] = 0.5 - Math.random()
# Initialize B
for i in range(0, M):
for j in range(0, NRHS):
B[M * j + i] = Math.random()
# Plasma Initialize
Dplasma.plasma_Init(M, N, NRHS)
# Allocate T
T = Dplasma.plasma_Allocate_T(M, N)
# Solve the problem
INFO = Dplasma.plasma_DGELS(Dplasma.PlasmaNoTrans, M, N, NRHS, A, 0, M, T, 0, B, 0, M)
# Plasma Finalize
Dplasma.plasma_Finalize()
if INFO < 0:
print("-- Error in DgelsExample example !")
else:
print("-- Run successfull !")
See the Jython Scripting page of the ImageJ Wiki for further information on writing Jython scripts.
One final parting comment: the ImageJ Script Editor was really designed as a tool to develop single-class scripts and plugins that rely on components already present in the installation. My suggestion for a project like this with many dependencies would be to instead code in Java using an IDE such as Eclipse, because such IDEs offer many more productivity enhancing features. You can use AST-based auto-complete to explore the API of the libraries you're using, and browse javadocs and sources easily without doing web searches.