Skip to content

Commit 698d74b

Browse files
authored
Update index.md
Following the Jython scripting tutorial as closely as possible. Work in progress
1 parent b7cf65e commit 698d74b

File tree

1 file changed

+189
-0
lines changed

1 file changed

+189
-0
lines changed

_pages/scripting/groovy/index.md

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,192 @@ The aim of this page is not to teach how to program in Groovy. This purpose is m
2626
### Use an IDE for Groovy scripting
2727

2828
As Groovy builds upon [Java](/develop/plugins), it can be use in a full fledged IDE with Fiji. If interested, follow this [tutorial](/scripting/groovy/ides).
29+
30+
## When to use Groovy
31+
32+
The following list will help you to decide if Groovy is the right choice for you to create scripts for ImageJ:
33+
34+
* If you have experience with Java, you can easily use Groovy for ImageJ scripting.
35+
36+
* If you want to be able to rapidly prototype something and make calls to external libraries, Groovy is a good choice.
37+
38+
* If you don't have experience with Java, but would like to get some, then scripting with Groovy can be a good way to learn.
39+
40+
* If you have very little or no experience in programming, you may like to explore [Jython](/scripting/jython) as it is an easy-to-read but feature-rich language.
41+
42+
43+
## Explanation
44+
At a basic level, Groovy is very similar to Java. As your familiarity with it grows, you will find it can do some things that Java can't.
45+
Like Java, Groovy can access any class libraries that are present in the classpath. This allows you to to include 3rd party libraries which may not immediately be present in Fiji/ImageJ, but which you can download. Examples would include database connections, libraries for communication purposes, The list is long!
46+
47+
## Groovy basics for ImageJ
48+
49+
{% include notice icon="info" content='For an introduction in ImageJ scripting visit the page [Scripting basics](/scripting/basics).' %}
50+
51+
### Hello, World!
52+
53+
#### - With print / println
54+
55+
The print and println commands send output to the console, with the difference being that println always appends a newline character at the end
56+
57+
```groovy
58+
println "Hello, World!"
59+
// Let's show it handling numbers too
60+
println "Result of 2 + 2: " + (2+2)
61+
62+
// what happens if we don't use the parentheses?
63+
print "Result of 2 + 2: " + 2+2
64+
```
65+
66+
Note - `print` and `println` will send their output to the standalone console if it's open. If not, it will go to the console of the Fiji Script Editor. Use cases would be where you want some sort of text output (to show values, progress etc), but you don't want it popping up for the user.
67+
68+
#### - With IJ.log()
69+
70+
`IJ.log()` is an example of an ImageJ java function (also called a method.
71+
It creates a window in ImageJ (if one isn't already open) and writes text to it.
72+
Newline characters are always appended with each call.
73+
74+
```groovy
75+
import ij.IJ
76+
77+
IJ.log("Hello, World!")
78+
// Let's show it handling numbers too
79+
IJ.log("Result of 2 + 2: " + (2+2))
80+
81+
// what happens if we don't use the parentheses?
82+
IJ.log("Result of 2 + 2: " + 2+2)
83+
```
84+
85+
If you tried out both sets of examples, the lines containing (2+2) will have evaluated as `4`, whereas the lines that don't have the brackets are treated as strings, giving `22`
86+
87+
Image selection using the GenericDialog class
88+
89+
This example script will create up to 10 new images and create a GenericDialog to select 3 of them. Finally the names of the selected images are printed to the Log window. It is recommended to copy the code to the [Script Editor](/scripting/script-editor) and run it by yourself.
90+
91+
```groovy
92+
// Import the classes that are needed.
93+
94+
import ij.IJ
95+
import ij.WindowManager
96+
import ij.gui.GenericDialog
97+
import ij.plugin.frame.RoiManager
98+
99+
// The IJ class contains a number of utilities. For this script, it provides the "log" functionality
100+
// A class which gives access to the window objects
101+
// A class which allows for creation of custom dialogs with relative ease.
102+
// The ROI Manager - useful for accessing ROIs.
103+
104+
// next we'll define some functions.
105+
106+
// Function to create a test image
107+
def createTestImage() {
108+
int imageWidth = 512 // here, we're using explicit types - int holds an integer.
109+
int imageHeight = 512
110+
int boxWidth = 128
111+
int boxHeight = 128
112+
int offsetX = (int) 192 * 2 * Math.random() // (int) causes the rest of the statement to be forced to an integer - no decimal places!
113+
int offsetY = (int) 192 * 2 * Math.random()
114+
int counts = 64
115+
int stdv = 16
116+
117+
// The following are nested definitions. They are not available outside the "createTestImage" function.
118+
// the following line is called a closure. It's a short-hand way of creating a function.
119+
// This one returns a string: makeTitle("Testing", 1, 2) will give 'Testing: 1, 2' as the output.
120+
def makeTitle = { prefix, x, y -> "${prefix}: ${x}, ${y}" }
121+
122+
// we'll now call the makeTitle function and store the result in a variable called "title"
123+
// note that it's not a pre-defined type, instead the interpreter will decide what to use.
124+
def title = makeTitle('TestImage', offsetX, offsetY)
125+
126+
// This closure looks a bit more like a java function. It's going to return either true or false.
127+
def checkExistence = { titleToCheck ->
128+
def idList = WindowManager.getIDList() // get the list of open images
129+
if (idList == null) return false // if the list is empty, return false.
130+
131+
// 'collect', in the next line, is a Groovy method that iterates through whatever it is attached to
132+
// and executes the code inside the curly brackets on each item it encounters.
133+
// In this case, it retrieves the title of each image into a list.
134+
def imageTitles = idList.collect { WindowManager.getImage(it).getTitle() }
135+
return imageTitles.contains(titleToCheck)
136+
}
137+
138+
// That's it for the nested definitions, now lets use them.
139+
140+
// Check if the image *doesn't* exist..
141+
if (!checkExistence(title)) {
142+
// if not, create an ImagePlus with the title, and image dimensions given
143+
def imp = IJ.createImage(title, "8-bit black", imageWidth, imageHeight, 1)
144+
imp.show()
145+
146+
// The following lines use calls to functionality that's already available - no need to reinvent the wheel.
147+
// Use the ImageJ mathematical function to add the value of "counts" to the current pixel values.
148+
IJ.run(imp, "Add...", "value=${counts}")
149+
// Create a simple rectangular ROI
150+
imp.setRoi(offsetX, offsetY, boxWidth, boxHeight)
151+
// and use the Add function again. This will only apply to the ROI
152+
IJ.run(imp, "Add...", "value=${counts}")
153+
// Select None removes the ROI - the whole image is now "active"
154+
IJ.run("Select None")
155+
// Add noise to the image
156+
IJ.run(imp, "Add Specified Noise...", "standard=${stdv}")
157+
// That was a groovy-styled way of building the required parameter string
158+
// In Java, you would use "standard=" + stdv)
159+
160+
// Tell ImageJ we're not interested in changes
161+
imp.changes = false
162+
// Display the image.
163+
imp.show()
164+
165+
}
166+
}
167+
168+
// Another function to help us to build a dialog to show to the user.
169+
// It uses the GenericDialog class and takes 3 arguments: titles, defaults and a string for the dialog title.
170+
def createSelectionDialog(imageTitles, defaults, dialogTitle) {
171+
// create a new instance of GenericDialog
172+
def gd = new GenericDialog(dialogTitle)
173+
174+
// A quick way to loop through an object, adding choices as we go.
175+
defaults.eachWithIndex { defVal, index ->
176+
gd.addChoice("Image_${index + 1}", imageTitles as String[], imageTitles[defVal])
177+
}
178+
179+
// show the dialog to the user
180+
gd.showDialog()
181+
if (gd.wasCanceled()) return null // if the user clicks cancel, return Null.
182+
183+
// the next line won't execute if the previous one evaluated as true, because the return statement causes the function to terminate.
184+
return defaults.collect { gd.getNextChoiceIndex() }
185+
}
186+
187+
// Main script execution
188+
def runScript() {
189+
while (WindowManager.getImageCount() < 10) { // create a test image as long as the count is less than 10
190+
createTestImage()
191+
}
192+
193+
// retrieve a list of the image titles using the WindowManager class.
194+
def imageTitles = WindowManager.getIDList().collect { WindowManager.getImage(it).getTitle() }
195+
196+
// now we'll pass this to the createSelectionDialog function that was defined earlier.
197+
def selectedIndices = createSelectionDialog(imageTitles, [0, 1, 2], 'Select images for processing')
198+
if (selectedIndices == null) { // check if the user clicked cancel - see above!!
199+
println "Script was canceled." // print this to the console (Not the log window)
200+
return // return without a value
201+
}
202+
203+
// if selectedIndices wasn't null, the following code will execute
204+
// get a list of the avilable images (as ImagePlus objects)
205+
def selectedImages = selectedIndices.collect { WindowManager.getImage(WindowManager.getIDList()[it]) }
206+
207+
// Display info on the ImageJ log.
208+
selectedImages.each { imp -> IJ.log("The image '${imp.getTitle()}' has been selected.") }
209+
}
210+
211+
// This is the only line of code that can actually be run - all the others have to be called.
212+
// So the "runScript" function is called, which subsequently calls other functions.
213+
runScript()
214+
215+
```
216+
217+
{% include notice icon="info" content='This page is under construction. Check back for updates.' %}

0 commit comments

Comments
 (0)