Using runMacro(...) on a macro with Script Parameters

scriptparameters
macro
Tags: #<Tag:0x00007fd542a1ccb8> #<Tag:0x00007fd542a1cb78>

#1

Hi all,

If we use the wonderful scripting parameters, as far as I understand we can no longer use “Install Macros” or “Run Macro…”.

I know that IJM is a bit deprecated and we’re moving towards scripting languages, but I was just curious if it was possible to do the following.

  1. Get the full path to a macro, which contains SciJava Scripting Parameters
  2. Programatically execute this macro (ideally from another macro)

Right now it just executes it, ignoring the script parameters, just like Run"Macro".

Any thoughts are more than welcome.

Oli


#2

I suppose you’re talking about the menu commands Macros > Install Macros and Macros > Run Macro available from an ImageJ 1.x Text Window? If so, you’re probably right, because this text window is created by the ij.plugin.frame.Editor class and is deep in ImageJ1 land (i.e. it has its own logic for script languages and has hard-coded calls to ij.plugin.macro.Interpreter).

If you use the (ImageJ2) script editor, you have the Run button as well as the Run > Run menu command that allow to run the current macro.

The Install functionality (i.e. Macros > Install Macros from the text window, or Plugins > Macros > Install… in the main menu) is indeed something that currently doesn’t support script parameters. Those parameters are parsed only once before the script is being run. Using the macro {} syntax with parameters would require parameter harvesting to be performed each time a macro snippet is run. (@ctrueden and @stelfrich might want to comment on this.) However, if you split each macro into a separate .ijm file, you can achieve the same functionality, see my suggestions below.

It’s not deprecated: ImageJ2 supports the IJ1 Macro language as a first-class citizen among all the supported scripting languages. I would rather say the macro language has its limitations by supporting only text and numerical variable types, and no objects that would allow to use the Java API (e.g. File objects, or services such as OpService).


What do you mean? From the menu path, getting the path on the file system? You don’t need this, as you can call scripts both from files or via their menu path.

From script languages that support Java objects (i.e. all but IJ1 macro), you can use SciJava services to run other scripts. For example, given a macro My_Macro.ijm:

#@ String text
print (text)

you can call this from other scripts as follows:

  • for script files anywhere on your file system:

    #@ ScriptService scripts
    // show a new dialog to harvest script parameters
    scripts.run(new File("/path/to/My_Macro.ijm"), true)
    // or use the given parameter(s) in key, value pairs
    scripts.run(new File("/path/to/My_Macro.ijm"), true, "text", "given text parameter")
    
  • for scripts anywhere in your menu (where the path might be unknown):

    #@ ModuleService modules
    modules.run(modules.getModuleById("script:Plugins/My Menu/My_Macro.ijm"), true)
    

(See the javadoc for ScriptService and ModuleService.)

That means that if you save your macro in e.g. ./Fiji.app/scripts/Plugins/My_Menu, it will be callable just like any other command. From other macros (where ScriptService and ModuleService are not available), you can then still run the macro recorder to get the required command, such as:

run("My Macro", "text=[given text parameter]");

Hope that helps.


#3

While ImageJ2’s ScriptLanguage plugin for the IJ1 macro language enables execution of macros as SciJava modules, there is no logic to support the macro {} syntax. Without digging deeply in the code, my intuition is that supporting that would require some more ImageJ Legacy surgery.

I am reluctant to invest time supporting things like “Install Macros” and “Run Macro” because you can mostly achieve them in other ways. And to be honest, I never use them. For those who find them really useful, it would be good to have a discussion about why, and then we can figure out the best way to improve the situation. My guess is that the most useful missing thing is the keyboard shortcut customization, which I bet we could add to ImageJ2 in a more general way—that is something I’ve wanted for a long time but had no time to work on.


#4

I vaguely remember a discussion about defining the menuPath in #@ annotation. Maybe we can combine that with the option that drag&dropping an IJM on the toolbar “installs” it to the ImageJ/Fiji scripts folder s.t. it is located at Plugins > Macros > filename. That way, we could at least emulate the behavior of “Install Macros” (without supporting multiple macros in a file). It would, however, mean that drag&drop behavior changes.

Also, @ctrueden, is there a reason why we don’t have a Script Editor menu entry? (sorry, a little of topic)


#5

Yeah, we were discussing about this on gitter (though not exactly menuPath, but Commands from scripts in general), and subsequently in Dresden, part of this is summarized in this issue:

https://github.com/scijava/scijava-common/issues/261#issuecomment-310598849

The original focus was on other script languages, but if we create a #@script annotation:

#@script (name = "my-utils", menuPath = "Plugins>My Cool Script")

this would work for IJ1 macros as well, of course.


#6

Hi!

[quote=“imagejan, post:2, topic:6401”]
I suppose you’re talking about the menu commands Macros > Install Macros and Macros > Run Macro available from an ImageJ 1.x Text Window?
[/quote]I was talking about both the menu entries and the IJ1 Macro command runMacro(path, args).

To describe why this became a question, we were trying to run a macro from another macro, and it so happened that this second macro had some script parameters that did not get recognized with the runMacro() command.

Thank you for that bit of information, but here we were talking about a macro that does not have a menu entry and resides in a user’s folder somewhere on a server.

Great! That is exactly what I needed to know!

I know this is rather hacky, but for the proof of concept of what I was going for (call another macro inside another IJ1 Macro, I chose this alternative.

  1. I made a simple ImageJ2 Command that has a @File parameter, which then runs scripts.run()
  2. This command is macro record-able and effectively works with the script parameters from within an ImageJ1 Macro

Here is the tiny Command that does this

package ch.epfl.biop.macrorunner;

import java.io.File;
import java.io.FileNotFoundException;

import javax.script.ScriptException;

import org.scijava.command.Command;
import org.scijava.log.LogService;
import org.scijava.plugin.Parameter;
import org.scijava.plugin.Plugin;
import org.scijava.script.ScriptService;

@Plugin(type= Command.class, menuPath="Plugins>BIOP>BIOP Run Macro...")
public class B_Run_Macro implements Command {
	
	@Parameter
	private File macro_file;
	
	@Parameter
	private LogService logService;
	
	@Parameter
	private ScriptService scriptService;
	
	@Override
	public void run() {
		try {
			scriptService.run(macro_file, true);
		} catch (FileNotFoundException | ScriptException e) {
			// TODO Auto-generated catch block
			logService.error(e.toString());
		}
	}

}

Effectively for us, it replaces the runMacro() command, without having to modify anything else in ImageJ/Fiji.

Knowing that this is a rather niche need, we are satisfied with this hacky solution, though comments and throughs are always welcome!

And thank you all for your time and support!


Scripting parameters in Action Bar plugin
#7

@oburri Cute hack! I was wondering though why you need a Command rather than e.g. a script like:

#@File macro_file
#@ScriptService scriptService
scriptService.run(macro_file, true)

And then save it as scripts/Plugins/BIOP/BIOP_Run_Macro.groovy.

Was there some obstacle to that working?


#8

@ctrueden :blush:

There was no particular need, it was more of a way to make a usefully minimalest-est imageJ2 Command, so that I could work it in Eclipse from scratch in 30 minutes. In practice, it really helped me get a better feel for SciJava.