How to Batch process Sholl Analysis (Tracings)

imagej
batch-processing
sholl-analysis
simpleneuritetracer

#1

I’m trying automate analysis of tracings made in simple neurite tracer using sholl analysis(Analysis ▷ Sholl ▷ Sholl Analysis (Tracings)…). I’ve tried following the Sholl Analysis wiki but can’t figure it out. When I record a macro for the Sholl Analysis (Tracings) plugin I get this code:

run("Sholl Analysis (Tracings)...",
    "traces/(e)swc=[/Volumes/EZ Ext HD1/Quantification/^CSPG Coating Quant/98137 trace & sholl/B2-1-1//B2-1.50CSPG+RM.CS56.traces]
     image=[/Volumes/EZ Ext HD1/Quantification/^CSPG Coating Quant/98137 trace & sholl/B2-1-1//B2-1.50CSPG+RM.CS56.tif]
     center=[Center of soma] radius=1 enclosing=1 #_primary=1 infer linear polynomial=[Best fitting degree] most
     normalizer=Area/Volume show save
     directory=[/Volumes/Macintosh HD/Users/X/Desktop]");
selectWindow("Sholl profile (Log-log) for B2-1.50CSPG+RM.CS56.traces no-filtering (407.522,482.246,0.000)");

I’m wondering how I can make my life easier by making the file directory a generic one so I can just plug in files and not have to click all the options for each individual trace. Or even better, I would like to batch process this but that seems difficult with .tracings files.


#2

Hi @Eric_Zluhan

So - I’ll just point you to an example script that uses Script Parameters to ask the user for input/output directories… You can find this example script in the Script Editor > Templates > ImageJ 1.x > Examples > Process Folder (IJ1 Macro). There is also a python example in there too!

With some modifications to grab your images and traces by adjusting the Script Parameters at the top to something like this:

// @File(label = "Input directory", style = "directory") input
// @File(label = "Output directory", style = "directory") output
// @String(label = "Traces suffix", value = ".traces") traces
// @String(label = "Image suffix", value = ".tif") image

So essentially - you can modify that code example and into your run() call, add something like this:

run("Sholl Analysis (Tracings)...", "traces/(e)swc=[" + input + "/" + traces + "] image=[" + input + "/" + image + "] center=[Center of soma] radius=1 enclosing=1 #_primary=1 infer linear polynomial=[Best fitting degree] most normalizer=Area/Volume show save directory=[" + output + "]");
selectWindow("Sholl profile (Log-log) for " + traces + " no-filtering (407.522,482.246,0.000)");

Again - you have to run/test it yourself… but maybe this will work for you.

eta :slight_smile:


#3

This seems to be working for me. Thank you so much!


#4

Hello, upon revisiting this code I’m having an issue with batch processing. Any idea why I’m getting this “Invalid image or invalid Traces file” prompt?

// @File(label = "Input directory", style = "directory") input
// @File(label = "Output directory", style = "directory") output
// @String(label = "Traces suffix", value = ".traces") traces
// @String(label = "Image suffix", value = ".tif") image

run("Sholl Analysis (Tracings)...", "traces/(e)swc=[" + input + "/" + traces + "] image=[" + input + "/" + image + "] center=[Center of soma] radius=1 include_only (basal) apical enclosing=1 #_primary=1 infer linear polynomial=[Best fitting degree] most normalizer=Area/Volume save directory=[" + output + "]");


#5

Hi @Eric_Zluhan,

In your recent snippet the input variable is a directory path, and the traces variable an extension, so when you do input + "/" + traces you are effectively creating a file path that does not exist. E.g.,

input = "/path/to/my/home/directory"
traces = ".traces"
print(input + "/" + traces) // will print '/path/to/my/home/directory/.traces'

#6

Hi I don’t quite understand the solution to your point. I’ve updated the code below to my best guess. The input parameter has to be called in this function as far as I can tell?

// @File(label = "Input directory", style = "directory") input
// @File(label = "Output directory", style = "directory") output
// @String(label = "Traces suffix", value = ".traces") traces

processFolder(input)

function processFolder(input) {
	list = getFileList(input);
	for (i = 0; i < list.length; i++) {
		if(File.isDirectory(input + File.separator + list[i]))
			processFolder(input + File.separator + list[i]);
		if(endsWith(list[i], traces))
			processFile(input, output, list[i]);
	}
}
function processFile(input, output, file) {
setBatchMode(true);
run("Sholl Analysis (Tracings)...", "traces/(e)swc=[" + input + "/" + traces + "] center=[Center of soma] radius=1 include_only (basal) apical enclosing=1 #_primary=1 infer linear polynomial=[Best fitting degree] most normalizer=Area/Volume save directory=[" + output + "]");


#7

I think I had that code above written incorrectly @Eric_Zluhan… sorry for that! This script searches for .traces files and uses them for processing… so your processFile() function should look something like this:

function processFile(input, output, file) {
setBatchMode(true);
run("Sholl Analysis (Tracings)...", "traces/(e)swc=[" + input + "/" + file + "] center=[Center of soma] radius=1 include_only (basal) apical enclosing=1 #_primary=1 infer linear polynomial=[Best fitting degree] most normalizer=Area/Volume save directory=[" + output + "]");
}

If you are ever not sure what file is being used at what point… especially in this case where the error is pointing to a file issue - add print() statements of the variable names - the directories and files themselves… to be sure the correct things are being called, etc. so… add

print("Input directory = " + input);
print("File = " + file);
print("Output directory = " + output);

to your processFile() function.

Is that more clear??

eta


#8

Thanks, eta. Yes that makes more sense but still having an issue. When I put the print functions after the processFile function nothing happens (same as when I run the normal code). When I put the print functions right after the parameters i get an error for the file :

 |Error:||Undefined variable in line 10:|
|---|---|---|
|||print ( "File = " + <file> ) ;|
// @File(label = "Input directory", style = "directory") input
// @File(label = "Output directory", style = "directory") output
// @String(label = "Traces suffix", value = ".traces") traces

processFolder(input)

function processFolder(input) {
	list = getFileList(input);
	for (i = 0; i < list.length; i++) {
		if(File.isDirectory(input + list[i]))
			processFolder(input + list[i]);
		if(endsWith(list[i], traces))
			processFile(input, output, list[i]);
	}
}

function processFile(input, output, file) {
setBatchMode(true);
run("Sholl Analysis (Tracings)...", "traces/(e)swc=[" + input + "/" + file + "] center=[Center of soma] radius=1 include_only (basal) apical enclosing=1 #_primary=1 infer linear polynomial=[Best fitting degree] most normalizer=Area/Volume save directory=[" + output + "]");

#9

@Eric_Zluhan

Put the print() statements WITHIN the processFile() function call… the code only knows what the file variable is within the scope of that function.

eta