Using a variable in another macro

Hello everyone,

To start with, I’m new in the world of macros so excuse me if the question is trivial !

In a first macro, I determined the center of an object with 2 variables X0, Y0 and I want to re-use these two coordinates in a second macro, which will be run separately.

I took a look at some discussions, espcially the following one :
http://imagej.1557.x6.nabble.com/User-input-for-a-global-variable-in-a-macro-td3694344.html
but it seems to be a little bit different from what I’m looking for.

How to do that?
Thanks !
Julien

@julien.jurczak

You can save those coordinates into a new Results Table… and then open/access that results table in your following script.

Here is an example with two scripts (they are ‘dumb’ examples - but you can adapt them as you need):

Script # 1 (makes a .csv table from the Results table and saves it to a specified output folder):

#@ File (label = "Input directory", style = "directory") input
#@ File (label = "Output directory", style = "directory") output
#@ String (label = "File suffix", value = ".tif") suffix


count = 0;
processFolder(input, count);
saveAs("Results", output + File.separator + "XYcoordinates.csv"); 

// function to scan folders for files to find files with correct suffix
function processFolder(input, count) {
	list = getFileList(input);
	list = Array.sort(list);
	count = list.length;
	for (i = 0; i < count; i++) {
		if(endsWith(list[i], suffix)) {
			processFile(input, output, list[i], i);
		}
	}
	
}

function processFile(input, output, file, count) {
		setResult("Image", count, file);
		setResult("X", count, 10*count);
		setResult("Y", count, 10*count);
		// NOTE - you have to set those X/Y values however you do it... I just hard-coded them here for an example.
}

Script # 2 (opens the .csv file as a Results table ands reads/uses the coordinates):

#@ File (label = "Input directory", style = "directory") input
#@ File (label = "Output directory", style = "directory") output
#@ File(label="Coordinates", description="Select the csv file containing XY coordinates") coordinates
#@ String (label = "File suffix", value = ".tif") suffix

// First - we open the coordinate file as a Results table and rename it
open(coordinates);
IJ.renameResults("Results");


processImages(input); // assumes input folder contains ONLY images you want to process

function processImages(input) {
	list = getFileList(input);
	list = Array.sort(list);
	for (i = 0; i < list.length; i++) {
		if(endsWith(list[i], suffix)) {
			numValues = getValue("results.count");
			// scan through IDs to look for file name match and then collect xy coordinates
			for (i = 0; i < numValues; i++) {
				id = getResultString("Image", i);
					if (endsWith(list[i], id)) {
						x = (getResult("X", i));
						y = (getResult("Y", i));
						print("x and y coordinates are: " + x + ", " + y); // now can do something with x&y for that image
					}
			}
		}
	}
}

I based the two above scripts off the code example available via the Script Editor in Templates > ImageJ 1.x > Batch > Process Folder (IJ1 Macro). :slight_smile: And using the Built In Macro Functions list

@etadobson

Thanks for the answer :blush:.
Out of curiosity (and for others if they would looking for that), how can you fix it in a single macro run with 2 or more macro inside ?

Thanks !
Julien

Hi @julien.jurczak,

What objections do you have to using functions instead of macros?

Within one macro (or function) you can call as many functions as you like. So after the ProcessFolder function the results are in the Results table, and you can call processImages which uses the Results table as data source; you store the intermediate results in the Results table and use that as a multi-dimensional variable.

Alternatively, in @etadobson’s example’s processFolder function you call processFile, use an array to store the results of processFile and call processImage with that array as an argument to immediately get the final results. Results can be returned in an array if you need multple results returned (functions return one variable but that variable can be an array).

For debugging purposes you can always Debug a macro (in ImageJ1 at least) and you can also have that macro command just call a (ie. one) function.

Or do I miss your point; in other words, why do you (seem to) insist on calling multiple macros?

1 Like

You can use the runMacro(); function to execute other macros within a macro and pass on variables: https://imagej.nih.gov/ij/developer/macro/functions.html#runMacro

So you would say:

runMacro(“path/to/Macro.ijm”, “stringArg1,stringArg2”);

which you could replace with variables by:

stringArg1 = "FirstArg";
stringArg2 = "AnotherArg";

runMacro("path/to/Macro.ijm", stringArg1 + "," + stringArg2);

this calls the macro and passes the arguments as strings, which you then need to split in order to get the individual arguments within the called macro:

args = split(getArgument(),",");
valueArg1 = args[0];
valueArg2 = args[1];

I used it for running the same macro with different sets of configurations for different users, with each config file saved separately instead of different versions of the script.

But I agree with @eljonco for most applications you rather go for better programming paradigms. Maybe once you start to pass this threshold you might want to think of using proper scripting languages.

1 Like