Find Peaks Data List & Read and Write Excel Macro

Hi,

I am new to ImageJ and writing code. I would appreciate any help regarding how to create a macro utilizing the BAR Plugin and Read and Write Excel.

I am trying to analyze the distance between two lines in an image. I can do this by running the Find Peaks through the BAR plugin. My question is when creating a Macro, I cannot figure out how to export the minima and maxima data into excel. I do have the Read and Write Excel Plugin.

Ideally, I would like to run a Batch Process utilizing these plugins.

Below is my code for the steps that I have so far, just for analyzing the picture and not for exporting the data, as I am not sure where to start for that.

makeLine(2478, 1113, 2628, 1113);
run(“Invert”);
run(“Plot Profile”);
run(“Find Peaks”, “min._peak_amplitude=10.12 min._peak_distance=0 min._value= max._value=”);

Thanks!

Bri

Hi Bri,

This is quite embarrassing, but I just noticed a(nother) silly error in the Read and Write Excel plugin that makes its implementation here a little more arduous than it should be. Regardless, I have coded a solution using the plugin:

makeLine(4278, 1113, 2628, 1113);
run("Invert");
setBatchMode(false);
run("Plot Profile");
run("Find Peaks", "min._peak_amplitude=10.12 min._peak_distance=0 min._value=[] max._value=[] list");
setBatchMode(true);
Table.rename("Plot Values", "Results");

headingsArray = split(Table.headings, "\t");
for (i = 1; i < headingsArray.length; i++) {
	for (j = 0; j < nResults; j++) {
		if (isNaN(getResult(""+headingsArray[i], j))==true) {
			setResult(""+headingsArray[i], j, "x");
		}
	}
}
run("Read and Write Excel");
setBatchMode("exit and display");
run("Close All");
close("Results");

which exports the results list generated by the BAR Find Peaks function to your desktop (the default export location). If you want the .xlsx file to be elsewhere, then you’ll need to pass an argument to the plugin, like ‘run(“Read and Write Excel”, “file=[/Users/antinos/Desktop/My_file.xlsx]”);’, which will also allow you to name the file.

I have also written the macro so that it can be batched. Ideally you would want all windows hidden during processing (which is the default mode for batch processing), but the Find Peaks plugin does not like running in full batch mode, so the macro temporarily shows windows as it proceeds. The easiest way for you to implement batch processing is to copy the macro code into the Process>Batch>Macro… window. There you will be able to select a folder to process.

Side note:
As you might be able to tell, the above macro manipulates the Find Peaks results table before export. This is to work-around the Excel plugin bug, which otherwise doesn’t complete the export if there are empty Results table cells. It also makes your macro longer than it should be. I definitely coded the Excel plugin to export these cells in an earlier release, but I must have introduced the problem with a subsequent feature update. Therefore your macro replaces empty cells with ‘x’. Sorry about that. I will update the Excel plugin this weekend to fix that issue.

Finally, just a reminder that you can export the BAR table without the Excel plugin. As per the Find Peaks Wiki:

run("Find Peaks", "min._peak_amplitude=10.12 min._peak_distance=0 min._value=NaN max._value=NaN list");
saveAs("Results", "/Path/to/Output/Directory/Plot Values.csv");
run("Close");

Although, in the above implementation it will replace the file during batching. By adding a minor edit to procedurally edit the file name during batching, it will instead create new files in the specified location. It is also possible to import the .csv file into imagej, to add data to, before export.

Kind regards.

1 Like

Apologies, but I just noticed that the Process>Batch>Macro… implementation did not actually export all the data properly. I suspect using the batch GUI is not compatible with the Find Peaks plugin.
This is a version that doesn’t require the GUI batch window:

setBatchMode(true);
dir = getDirectory("Choose a Directory");
filesArray = getFileList(dir);
for (k=0; k<filesArray.length; k++) {
	open(dir+File.separator+filesArray[k]);
	makeLine(2478, 1113, 2628, 1113);
	run("Invert");
	setBatchMode(false);
	run("Plot Profile");
	run("Find Peaks", "min._peak_amplitude=10.12 min._peak_distance=0 min._value=[] max._value=[] list");
	setBatchMode(true);
	Table.rename("Plot Values", "Results");
	
	headingsArray = split(Table.headings, "\t");
	for (i = 1; i < headingsArray.length; i++) {
		for (j = 0; j < nResults; j++) {
			if (isNaN(getResult(""+headingsArray[i], j))==true) {
				setResult(""+headingsArray[i], j, "x");
			}
		}
	}
	run("Read and Write Excel");
	setBatchMode("exit and display");
	run("Close All");
	close("Results");
}

If you run this as a regular macro, you will instead be prompted for the folder to process. I have actually tested this version, and it seems to work.

Kind regards.

1 Like

Hi antinos,

Thank you so much for the help, it works perfectly! I also really appreciate the fast response!
I do have one more quick question for you, I would like to learn to code (Python or Java). Do you have any recommendations on books/websites that are good starting places for beginners?

Thank you again!
Bri

Hi Bri,
I’m glad that I could help.
Not that I am the best qualified to respond to your query, but this youtube channel came to mind:


I’m not sure if the creator is still active and some of his tutorials may be a little dated (using older versions of java), but i remember it being very accessible. After you setup the platform(s), try making a few simple scripts/programs. It’s a lot like lego when you get into it. For java (and other laguages) just reading the APIs can be informative. Finally stackoverflow (website) has a huge back catalogue of user questions from basic to complex, which i used to go to to get answers whilst coding.

Kind regards.

Hi antinos,

Thanks for the recommendation, I’ll definitely look them up.

I do have a follow up question for you. I tried for a couple hours, with the code you provided, to add the Standard Deviation of the data to the list that is exported to excel. I know you can do it through the Plot Profile. I have had no success so far and feel that my understanding is just too limited. Could you help me with this and also explain each of the lines of code in the above code?

I know I am asking a lot and understand if you can’t.
Thank you so much!
Bri

Hey Bri,

Apologies for the delay getting back to you. The following macro script may do what you want:

	headingsArray = split(Table.headings, "\t");
	writeRow = nResults;
	for (i = 0; i < headingsArray.length; i++) {
		columnArray = Table.getColumn(headingsArray[i]);
		Array.getStatistics(columnArray, min, max, mean, stdDev);
		Table.set(headingsArray[i], writeRow, stdDev);
	}

I wasn’t actually sure of which values you wanted the standard deviation of, so I defaulted to column computations.

Also, today I updated the Excel plugin such that it can now handle all empty cells without the ResultsTable manipulation ‘work-around’ from before. Feel free to leave the work-around in your macro but you can now also remove it if you prefer to (reducing its overall size).

I don’t mind going through each line of the macro code, and I will do so since you asked, but it may not be an ideal learning activity for you to read my notes (especially as there are already good, curated, resources available, such as the ImageJ wikis: e.g. https://imagej.nih.gov/ij/developer/macro/macros.html and https://imagej.nih.gov/ij/developer/macro/functions.html). Regardless, below I have tried to annotate the macro extensively:

setBatchMode(true); //function to put imagej into a 'batch' mode of operation. This function is passed a 'Boolean' value (true or false) in the parethesis. In batch-mode, ImageJ will open and manipulate images without displaying them, reducing the processing overhead, which should make things run faster
dir = getDirectory("Choose a Directory"); //'dir' is a variable. It could be named anything. It is assigned a value by the 'getDirectory()' command. See macro functions webpage.
filesArray = getFileList(dir); //'filesArray' is another variable that cuold have been named anything. Technically, each variable should also have a 'type'. In the Imagej macro language, the type is automatically defined by the passed data type. In this case, the 'getFileList()' command will always provide an array. An array is a special list of values, where each list item is given a space within a defined list length (this isn't the technical definition btw)... so an array of length 3, will have 3 spaces that can be occupied with values (e.g. myarray[24, 99, 101]). The getFileList command is part of the imagej macro command functions. It expects to be given a file path to a folder in the parenthesis. It will then search the folder and generate a list of files therein.
for (k=0; k<filesArray.length; k++) { //this is the beginning of a 'loop'. Loops are a very common construction in scripting and programming languages. Everything in curly braces braces will be cycled through a number of times. defined in the loop parameters here. Briefly, 'k' is created as a changing variable. It will begin as k=0, and for every loop it will increase by 1 (the ++ part), until it reaches the specified condition, which here is k < the length of our array... note '<' means that the k will reach 1 value before the actual length, as otherwise it would not be 'less than' the length, but equal to it. The changing value of 'k' can now be used in each cycle of the loop.
	open(dir+File.separator+filesArray[k]); //the 'open()' command (again see imagej macro functions web-page) will attempt to open an image that it is directed to in the parenthesis. Here we construct the file-path to our file bu joining our 'dir' variable with the filesArray value in 'k' position of the array (i.e. one of the file names found by the earlier getFileList() command).
	makeLine(2478, 1113, 2628, 1113); //imageJ makeLine() command.
	run("Invert"); //imageJ run() command will run a plugin or imagej menu option. Here it runs the 'invert' command.
	setBatchMode(false); //This exits the batch-mode that we entered earlier. Normally you shouldn't need to do this, but the upcoming FindPeaks plugin cannot run properly wihout interacting with displayed imageJ windows
	run("Plot Profile"); //runs the 'Plot Profile' command
	run("Find Peaks", "min._peak_amplitude=10.12 min._peak_distance=0 min._value=[] max._value=[] list"); //runs the 'Find Peaks' plugin and passes it run parameters in a line of text after the comma
	setBatchMode(true); //Here we return to batch-mode to try to save on processing overhead
	Table.rename("Plot Values", "Results"); //an imageJ macro function to change the name of the specified table (here the 'Plot Values' table) to another specified name ('Results'). We do this because the 'Read and Write Excel' plugin can only harvest data from the imagej Results Table (which in ImageJ, is a kind of master table called 'Results').

	headingsArray = split(Table.headings, "\t"); //a variable is created called 'headingsArray' and this is turned into an array and assigned values by the 'split()' function. The 'split()' function expects to be fed a line of text (also called a string) which it will then split into seperate positions of an array (remember that special list with individual units). The 'split()' function will segment the string/text accoring to the defined paramters. Here, the string will be split after every tab (/t). See the built-in macro functions web-page for the other options. The Table.headings functions provides the split() function with a string of the ResultsTable headings, with tabs between each entry.
	writeRow = nResults; //Here we assign a new vairable 'writeRow' value dfined by the nResults macro command. The nResults macro command gives us the number of rows in our results table.
	for (i = 0; i < headingsArray.length; i++) { //We are here, starting another loop within our still ongoing loop (remmeber us starting it in line4). Again we create a chaning variable, this time 'i', which will increase by 1 (++) every loop until we reach a number equal to the number of results table headings. When this number is reached, then loop will stop. Again, as the '<' operator is used, 'i' will never reach the number equivalent to the number of resultstable headings.
		columnArray = Table.getColumn(headingsArray[i]); //We create a variable 'columnArray', which is simultaneously turned into an array and filled with values of each column by the 'Table.getColumn()' function. On each loop, a different column referenced as defined by 'i'.
		Array.getStatistics(columnArray, min, max, mean, stdDev); //This macro function takes a provided array (here our newly populated 'columnArray') and computes some key statistics 'min', 'max', 'mean', 'stdDev'. Each of these statistics are created as separate variables of the smae name (you can actually give them any name you want here by changing it in the parenthesis , as the position is the key factor)
		Table.set(headingsArray[i], writeRow, stdDev); //Here we use the 'Table.set()' macro function to add the stdDev value (from the line above) to a new cell underneath each correesponding column. 'The Table.set' function is fed the column heading and the row number, to know where to plavce the 'stdDev' value. Remember we can access each table heading from our 'headingArray' array, by specifying the position within the array, here defined by 'i', our loop changing varialble.
	} //This curly brace finishes our second (nested) loop. Remeber, our main loop is still proceeding.

	run("Read and Write Excel"); //runs the 'Read and Write Excel' plugin. By default this plugin will export the contents of the current Results Table to the user's desktop.
	setBatchMode("exit and display"); //The 'setBatchMode' built-in macro function can also be passed this argument "exit and display", to both exit the batch-mode and to display any batc-mode hidden windows that may be open in the background. This may not be a necessary function here for the macro to work, but it was added to keep things organised and neat (maybe not the best reason in truth)
	run("Close All"); //this imageJ command closes all image windows. Here called to reset the imagej space, ready for the next image to process in the main loop.
	close("Results"); //this closes the window named 'Results', which is here (and usually) the Results table
} //Finally, this curly brace represents the end of the main (first) loop code. Everything between this closing brace and the first open loop brace will be cycled through until all files within our chosen folder are processed

Kind regards.