/* ROI Manager Tools.ijm
* IJ BAR: https://github.com/tferr/Scripts#scripts
*
* ImageJ toolset that renames selections stored in the ROI Manager. Supersedes the
* 'Rename and Save ROI Set.txt' macro. Save this file in ImageJ/macros/toolsets/,
* then use the '>>' drop down menu to activate it. Requires IJ 1.50b or newer.
*
* TF, 2015.08, Change log: See https://github.com/tferr/Scripts/releases
*/
var labels= getPrefList("labels");
var prefixs= getPrefList("prefixes");
var suffixs= getPrefList("suffixes");
var oldstr= "", newstr= "", usenames;
macro "AutoRun" {
requires("1.50b");
setOption("Display label", true);
run("ROI Manager...");
}
macro "Unused Tool-" {}
var bCmds= newMenu("Settings Menu Tool", newArray("Define tags...", "Define prefixes...",
"Define suffixes...", "-", "Remove all prefixes", "Remove all suffixes", "-",
"Select ROIs by pattern...", "Rename ROIs by pattern...", "-",
"Toggle \"ROI names as labels\""));
macro "Settings Menu Tool - C037D3eD4eD5eD6bD6cD6dD7aD89D98Da7Db6Dc6Dd6De4De5D2aD5dDa2Dd5D59D68D69D77D78D86D87D96D1aD1bD1cD29D2bD39D49D4bD4cD4dD58D67D76D85D92D93D94Da1Db1Db2Db4Dc1Dc4Dd4De3D5aD6aD79D88D95D97Da5Da6D19D91D4aD5bDa4Db5D3aD5cDa3Dc5" {
setBatchMode(true);
cmd= getArgument();
n= roiManager("count");
bools= newArray("true", "false");
if(cmd=="Define tags...") {
createNewList("labels", "Label");
} else if(cmd=="Define prefixes...") {
createNewList("prefixes", "Prefix");
} else if(cmd=="Define suffixes...") {
createNewList("suffixes", "Suffix");
} else if(endsWith(cmd, "pattern...")) {
rplc= (cmd=="Rename ROIs by pattern...");
help= "Search is case sensitive. Regex patterns can also be used, e.g.,
"
+"\"[0-9&&[^1]]\\" to find a digit that is not 1, or \"-.*-\\" to "
+"find
any character sequence flanked by hyphens. You may need to
"
+"escape metacharacters ('.', '[', ']', '^', '$', etc.) by a backslash.";
Dialog.create(cmd);
Dialog.addString("Find:", oldstr, 18);
if (rplc)
Dialog.addString("Replace:", newstr, 18);
Dialog.addString("Range:", 1 +"-"+ n, 9);
items = newArray("Contains", "Starts with ", "Ends with", "Regex");
Dialog.addRadioButtonGroup("Find options:", items, 2, 2, "Contains");
Dialog.addHelp(help);
Dialog.show();
findString= Dialog.getString();
choice= Dialog.getRadioButton();
if (choice==items[0])
findString= ".*"+ findString +".*";
else if (choice==items[1])
findString= "^"+ findString +".*";
else if (choice==items[2])
findString= ".*"+ findString +"$";
if (rplc)
replaceString= Dialog.getString();
else
replaceString= "";
range= parseRange(Dialog.getString);
if (rplc)
renamePattern(range[0], range[1], findString, replaceString);
else
selectPattern(findString, range[0], range[1]);
} else if(cmd=="Remove all prefixes") {
renamePattern(0, n-1, ".*\\[", "");
} else if(cmd=="Remove all suffixes") {
renamePattern(0, n-1, "\\].*", "");
} else if(cmd=="Toggle \"ROI names as labels\"") {
roiManager("UseNames", bools[usenames]);
usenames= !usenames;
roiManager("Show All with labels");
} else if (cmd!="-")
run(cmd);
}
var cCmds= newMenu("Rename Menu Tool", Array.concat(labels, "-","Custom..."));
macro "Rename Menu Tool - C037T0b11T T6b10a Tab10g Tfb10s" {
setBatchMode(true);
cmd= getArgument(); i= roiManager("index");
renameROI(cmd, "Label", i);
walkList(i, 0);
}
var dCmds= newMenu("Add prefix Menu Tool", Array.concat(prefixs, "-","Custom..."));
macro "Add prefix Menu Tool - C037T0b10PT6b10rTab10fTeb10x" {
setBatchMode(true);
cmd= getArgument(); i= roiManager("index");
renameROI(cmd, "Prefix", i);
walkList(i, 0);
}
var eCmds= newMenu("Add suffix Menu Tool", Array.concat(suffixs, "-","Custom..."));
macro "Add suffix Menu Tool - C037 T0b10ST6b10fTab10fTeb10x" {
setBatchMode(true);
cmd= getArgument(); i= roiManager("index");
renameROI(cmd, "Suffix", i);
walkList(i, 0);
}
macro "Selection cycler [Shift click: Previous] [Alt click: First] Action Tool - C037L020dL0268L0d68Lf2fdLf298Lfd98" {
if (roiManager("count")==0) {
showStatus("ROI Manager is empty.");
exit;
}
setBatchMode(true);
i= roiManager("index");
if (isKeyDown("alt") || i<0)
roiManager('select', 0);
else if (isKeyDown("shift"))
walkList(i, 1);
else
walkList(i, 0);
}
var fCmds= newMenu("Save all regions Menu Tool", newArray("In image directory", "Elsewhere..."));
macro "Save all regions Menu Tool - C037D11D12D13D14D15D16D17D18D19D1aD1bD1cD21D27D28D29D2aD2bD2cD2dD31D33D35D37D38D39D3aD3bD3cD3dD3eD41D43D45D47D48D4eD51D53D55D57D58D5aD5bD5cD5eD61D63D65D67D68D6aD6bD6cD6eD71D73D75D77D78D7eD81D83D85D87D88D8eD91D93D95D97D98D9eDa1Da3Da5Da7Da8DaeDb1Db7Db8DbeDc1Dc2Dc3Dc4Dc5Dc6Dc7Dc8Dc9DcaDcbDccDcdDce" {
if (roiManager("count")==0)
exit("The ROI Manager contains no items.");
if (nImages==0)
exit(" No images open. Alternatively, use the\nROI Manager \"More>>Save...\" command.");
cmd= getArgument();
if (cmd=="In image directory") {
path= getDirectory("image");
if (!File.exists(path)) exit("Could not retrieve path of image.");
} else if (cmd=="Elsewhere...")
path= getDirectory("Select a Directory");
roiManager('save', path + getTitle +'-ROIset.zip');
showStatus("All ROIs in Manager have been saved...");
}
macro "Help Action Tool - C037T3e16?" {
help= "The ROI Manager Rename... command requires user input each time it is used,
"
+"becoming combersome when working with multip ROIs. This set of tools addresses
"
+"this issue by using 3 types of predefined labels: \"Tags\", \"Prefixes\" and \"Suffixes\",
"
+"specified in the Settings Menu. Tags rename ROIs, prefixes and suffixes are
"
+"appended to the ROI name.
"
+"To rename multiple ROIs, press Deselect in the ROI Manager, and choose a label
"
+"from one of menus. Alternatively, choose Rename by pattern... from the Settings
"
+"menu. In both cases, you can specify the range of ROIs to be renamed, as when
"
+"using the ROI Manager Properties... command.
"
+"To rename single ROIs, use the Selection cycler to walk through the listed ROIs
"
+"one item at a time.
"
+"Use the Save menu to store all ROIs in a .zip file named after the active image.";
showMessage("ROI Manager Tools", help);
}
/*
* Retrieves the array containing the specified list of strings of
* "labels", "prefixes" or "suffixes" using the IJ preferences mechanism.
* Default lists are generated if pre-existing ones cannot be retrieved
*/
function getPrefList(type) {
prefs= call("ij.Prefs.get", "rmtools."+type, "no"+type);
if (startsWith(prefs,"no")) {
if (type=="labels")
prefs= "Cortex|DG|CA3|CA1|Striatum";
else if (type=="prefixes")
prefs= "WT|KO";
else if (type=="suffixes")
prefs= "Anterior|Posterior|Ventral|Medial|Dorsal";
call("ij.Prefs.set", "rmtools."+type, prefs);
}
return split(prefs, "|");
}
/*
* Prompts the user for a new list of strings of "labels", prefixes
* "prefixes" or "suffixes", saving it using the IJ preferences mechanism.
* is an alternative string to describe in the dialog prompt
*/
function createNewList(type, prompt) {
help= "None of the "+ type +" should contain \"|\", \"[\" and \"]\" as these are
"
+"used to define word boundaries. Entries defined by a single
"
+"hyphen are interpreted as menu separators.
The last entry in the drop-down"
+" menu will be set to \"Custom...\",
allowing you to input ad-hoc strings.";
prefs= "";
items= getPrefList(type);
Dialog.create('Define '+ type);
for (i=1; i<=items.length; i++)
Dialog.addString(prompt +" "+ i +":", items[i-1], 20);
Dialog.addCheckbox("Add more "+type, false);
Dialog.addCheckbox("Reset all entries", false);
Dialog.addHelp(help);
Dialog.show();
add= Dialog.getCheckbox();
res= Dialog.getCheckbox();
for (i=1; i<=items.length; i++)
prefs+= Dialog.getString() +"|";
call("ij.Prefs.set", "rmtools."+type, prefs); // Store new list
if (res) { // Reset all items
add = false; // Stop asking for new items
call("ij.Prefs.set", "rmtools."+type, "no"+type);
createNewList(type, prompt); // Display prompt with reseted list
}
if (add) { // Keep prompting for new items
prefs+= "-";
call("ij.Prefs.set", "rmtools."+type, prefs);
createNewList(type, prompt); // Display appended list
}
// Reload toolset. When downloaded independently from BAR, this file may have
// ".ijm", ".txt", or a ".ijm.txt", so we'll try to find the file w/o extension
path= getDirectory("macros")+"toolsets/";
list= getFileList(path);
for (i=0; i
* (0-based index). If position is negative, user is prompt for a range of
* of indices. If is "Custom..." user is prompt for new ROI name.
* If is "Prefix", is prepended to existing name. If
* "Suffix", it is appended to existing name.
*/
function renameROI(newname, placement, item) {
custom= (newname=="Custom...");
if (item<0) { // multiple ROIs selected
n= roiManager("count");
if (custom) {
Dialog.create("Rename Multiple ROIs");
Dialog.addString(placement +":", "", 18);
Dialog.addString("Range:", "1-"+ n, 9);
Dialog.show;
newname= Dialog.getString();
rg= parseRange(Dialog.getString);
} else
rg= parseRange(getString("\""+ newname +"\"; ROI range:", "1-"+ n));
for (i=rg[0]; i<=rg[1]; i++)
renameROI(newname, placement, i);
roiManager("Deselect");
return;
}
oldname= call("ij.plugin.frame.RoiManager.getName", item);
if (custom) newname= getString(placement +":", "");
if (placement=="Prefix") {
sep= indexOf(oldname, "[");
if (sep!=-1)
oldname= substring(oldname, sep+1);
newname+= "["+oldname;
} else if (placement=="Suffix") {
sep= lastIndexOf(oldname, "]");
if (sep!=-1)
oldname= substring(oldname, 0, sep);
newname= oldname +"]"+ newname;
} else // rename
newname= IJ.pad(item+1, 2) +":"+ newname;
roiManager("select", item);
roiManager("rename", newname);
}
/*
* Selects the next ROI in the ROI Manager (or the previous if
* "backwards" is true) by looping through the ROI Manager list
*/
function walkList(idx, backwards) {
lngth= roiManager("count");
if (idx<0)
return;
if (backwards) {
idx-= 1;
if (idx<0) idx= lngth-1;
} else {
idx+= 1;
if (idx>=lngth) idx= 0;
}
roiManager("select", idx);
}
/*
* Renames ROIs in the ROI Manager list within the specified range
* (0-based indices) by replacing all occurrences of the string
* "old" with the string "new" in the ROI name
*/
function renamePattern(first, last, old, new) {
for (i=first; i<=last; i++) {
name= call("ij.plugin.frame.RoiManager.getName", i);
name= replace(name, old, new);
roiManager("select", i);
roiManager("rename", name);
}
roiManager("Deselect");
}
/*
* Selects ROIs in the ROI Manager list within the specified range
* (0-based indices) whose name matches the specified pattern
*/
function selectPattern(pattern, first, last) {
indexes = newArray(last-first+1);
k = 0;
for (i=first; i<=last; i++) {
name = call("ij.plugin.frame.RoiManager.getName", i);
if (matches(name, pattern))
indexes[k++] = i;
}
indexes = Array.trim(indexes, k);
roiManager("select", indexes);
}
/*
* Retrieves a two-element array containing the range of ROI Manager
* indices (0-based positions) from a hyphen containing string. E.g.,
* "1-71" returns {0, 70}. Macros calling this function will be aborted
* if the parsed range is invalid.
*/
function parseRange(string) {
range= split(string, "-");
if (range.length==1) {
min= 0;
max= parseFloat(range[0]);
} else {
min= parseFloat(range[0]);
max= parseFloat(range[1]);
}
min= maxOf(0, min-1);
max= minOf(max, roiManager("count")-1);
if (min>max || max==0)
exit("Invalid ROI range.");
return newArray(min, max);
}