BAR

BAR (ImageJ/Fiji)
Maintainer Tiago Ferreira
Source on GitHub
Initial release June 2014
Latest version 1.1.13 March 2017 (Changelog)
Category Analysis, Annotation, Filtering, Segmentation, Scripting


BAR: A collection of Broadly Applicable Routines.

The collection contains Macros, Scripts and Plugins focused on Data Analysis, Image Annotation and Image Segmentation. It is curated using GitHub and distributed as an optional update site.

Contents

Installation

Run Help ▶ Update... and choose Manage update sites. Activate the BAR checkbox in the alphabetically-sorted list of update sites. Press OK, then Apply changes. Restart ImageJ. That's it. Enjoy BAR!

Description

BAR files are accessible through a dedicated top-level menu subdivided in task-oriented categories. All routines should be documented on GitHub.

Some of the scripts have a dedicated documentation page, others feature built-in help, while a handful were deemed too simple to require dedicated instructions. Nevertheless, all files contain useful commentary at the top of the source code file. Remember: You can open all the scripts using the Shift key.

List of BARs

Overview of BAR (v1.0.0)
Analysis
LoG-DoG Spot Counter, Multi ROI Profiler, Multichannel Plot Profile, Multichannel ZT-axis Profile, Smoothed Plot Profile
Annotation
Combine Orthogonal Views, Cumulative Z Project, ROI Color Coder
Data Analysis
Create Boxplot, Create Polar Plot, Distribution Plotter, Find Peaks, Fit Polynomial, Interactive Plotting
Segmentation
Shen-Castan Edge Detector, Apply Threshold To ROI, Clear Thresholded Pixels, Remove Isolated Pixels, Threshold From Background, Wipe Background
Snippets, BAR lib and Tutorials
Described in Scripting BARs
Tools and Toolsets
Calibration Menu, List Folder Menu, Segment Profile, Shortcuts Menu, ROI Manager Tools, Toolset Creator
Utilities
Commander

Accessing BARs

As with all ImageJ commands, BAR scripts can be accessed in multiple ways: 1) through the BAR▷ menu, 2) the Context Menu, 3) Keyboard Shortcuts, 3) the Shortcuts Menu Tool (BAR▷ Tool Installers▷ Install Shortcuts Menu), that registers frequently used commands in the ImageJ toolbar, 4) by pressing L, or 5) from other scripts, macros and plugins.

Tip: You can open any BAR script by holding Shift while selecting its name from the BAR▷ menu. For pre-compiled java plugins, the source code is available through the About BAR... command.


Context Menu

BAR features a neat mechanism that allows BAR▷ commands to shuttle between the main menu bar and the image's context menu.

BAR▷ submenus can be appended to the image's context menu (the menu that pops up when right-clicking on the image canvas) by running BAR▷ Submenu▷Move Menu (Context<>Main). The transfer is bidirectional: once in the context menu, running the same command will place the submenu back in the main menu bar.

The shuttling mechanism is not permanent, i.e., it will not be remembered across restarts. However, it is macro recordable which means it can be imposed at startup, using the ImageJ macro language. So, e.g., to install BAR▷ Segmentation▷ in the context menu, one would:

  1. Start the Macro Recorder ( Plugins▷ Macros▷ Record...)
  2. Run BAR▷ Segmentation▷ Move Menu (Context<>Main)
  3. Open the Edit▷ Options▷ Startup... window and paste the string generated by the Macro Recorder into its text area so that ImageJ can run the command at every startup.


It may be wise to allow ImageJ enough time to register all scripts before triggering transfers to the context menu. This can be achieved through the built-in macro function wait(). For a slow setup requiring at least 1 second (1000 milliseconds), the pasted code would look something like this:

StartupBAR.png


Notes

  • The several Move Menu (Context<>Main) commands across BAR▷ submenus do not use the same label and are distinguishable by extra trailing spaces. This is intentional because all ImageJ commands must have unique names.
  • Any toolset loaded via the ">>" More Tools drop down menu can define its own contextual menu (as detailed in the ImageJ User Guide, the contextual menu is controlled by a macro called Popup Menu that gets loaded at startup). To have BARs immediately available when such toolsets are loaded, just append the same run("Move Menu (Context<>Main)"); call described above for StartupMacros.

Commander

Commander overview (BAR 1.1.2).

Since the majority of BARs are scripts stored in dedicated files, BAR features Commander (BAR ▶ BAR Commander...), a keyboard-based file browser that produces filtered lists of directory contents.

It is a productivity tool that applies the principles of Command Launcher to file browsing, providing instant access to files just by typing abbreviations of filenames. It serves two purposes: 1) to expedite the opening of files and 2) to produce filtered lists of directory contents. Features include: drag-and-drop support, interaction with native file manager, regex filtering, and a built-in console for common operations.

Console mode is triggered by typing !, which evokes a list of searchable commands so that all file navigation can be done exclusively with the keyboard. Some of these (cd, ls, pwd, etc.) are reminiscent of commands found in most command-line interfaces. Here are some examples:

To access ImageJ's LUT folder
Type !+L+U+T+ Enter
To access all JavaScript lib files
Type !+L+I+B+ Enter, then .+J+S
To reveal the directory of active image
Type !+I+M+P+ Enter, then choose Reveal Path.
To access Commander's built-in help
Type !+H+E+L+P+ Enter
To extract the paths of all TIFF images in a directory
Drag and drop the desired folder into the Commander list
Type T+I+F+ Enter
Choose Print Current List in the Options Menu or press ^ Control+P ( Command+P in Mac OS).

Keyboard Shortcuts

You can use Plugins▷ Shortcuts▷ Create Shortcut... to assign hotkeys (e.g., keyboard key that you do not use frequently such as 0 or F7) to any script registered in the BAR▷ menu. These shortcuts will be listed in Plugins▷ Shortcuts▷ and are remembered across restarts.

Alternatively, keyboard shortcuts can be defined in macros that call BAR commands by placing the shortcut key within square brackets at the end of the macro name. Such macros can pass specific options to BAR commands, allowing scripts to run without prompt. Example:

macro "Remove Round Structures [0]" {
    run("Wipe Background", "size=100 circ.=0.75-1.00"); // Runs Wipe_Background.ijm with the specified parameters
}

As mentioned, such macros can then be pasted into the text area of Edit▷ Options▷ Startup... so that they can be executed when ImageJ starts up.

Tip: Two other expedite ways of retrieving commands include: 1) Pressing L, the shortcut for the Command Launcher and 2) Pressing 9, the default shortcut for the Recent Commands list.

Scripting BARs

Although BARs can be used as standalone commands, the scripts and plugins in BAR become more useful when incorporated into other routines.

You can use BARs as a starting point for your own workflows. Whether you are just looking to automate a simple task or you are an advanced developer, you can use BAR to achieve your analysis goals more easily, by means of Snippets - source code templates - and libs - scripting additions to be shared across routines.

Snippets

BAR ▶ Snippets ▶ NewSnippet... (BAR 1.1.0)

BAR contains a directory, plugins/Scripts/BAR/Snippets/, containing multi-language examples that you can customize and recycle in your own scripts. You can, of course, also retrieve code and inspiration from the more complete BARs in the remaining plugins/Scripts/BAR/ subdirectories. Any script or macro file stored in the Snippets/, folder with an underscore "_" in the filename will be listed in BAR▷ Snippets▷. The Snippets▷ menu contains some utilities to help you manage your scripts:

List Snippets
Prints a table listing all scripts in plugins/Scripts/BAR/Snippets/. Files can then be opened in the Script Editor by double-clicking on their filename.
New Snippet
A java plugin that speeds up the creation of new scripts, pre-configured to use BAR lib.
Reveal Snippets
Opens plugins/Scripts/BAR/Snippets/ in the file browser of the operating system.
Search BAR
Searches the contents of BAR files.
Tip: BAR provides several utility methods that simplify the creation of Snippets and BAR lib usage. These are documented in the BAR API, that can be accessed using BAR ▶ About BAR.... About BAR... also provides links to several online resources including the ImageJ Search Portal, ImageJ Javadocs, and the GitHub documentation of BAR.


BAR lib

Learn
Topics
Introduction
Getting Started
User Guides
Tutorials
Tips and Tricks
Presentations
Plugins
Techniques
All Techniques
Colocalization
Deconvolution
Registration
Segmentation
Stitching
Tracking
Visualization
Scripting
Overview
Parameters
Basics of script writing
Batch processing
Script Editor
Auto Imports
Templates
Running headlessly
Comparisons
Toolbox
Multithreading in Clojure
Multithreading in JavaScript
Chess in Jython
Languages
BeanShell
Groovy
ImageJ Macro
JavaScript
Lisp (Clojure)
MATLAB
Python (Jython)
R (Renjin)
Ruby (JRuby)
Scala

BAR libs (stored in the /BAR/lib/ directory) are centralized libraries (BeanShell, IJM and Python, etc.) that can be shared across files. These libraries serve as scripting additions to Snippets and other routines.

Do you find yourself copy and pasting functions from one file to the other? Do you keep on writing the same lines of code? Do you have some key code written across different languages? Would you like to make side-by-side comparisons of scripting languages? Then, BAR lib is for you.

The idea is quite simple: Reusable functions and methods are written to a lib file that gets loaded at execution time so that it can be called by the running script. BAR▷ Snippets▷ New Snippet... exemplifies how to use these scripting add-ons. Here is a BeanShell example:

// Add BAR/lib to classpath
addClassPath(bar.Utils.getBARDir()); // See http://tferr.github.io/Scripts/apidocs/index.html?bar/Utils.html for details
importCommands("lib/");
// Load BARlib.bsh
BARlib();
// Confirm availability of BARlib
lib = new BARlib();
lib.confirmLoading();

Run it in the Script Editor (File ▶ New ▶ Script...), and you should be greeted by a "BAR lib successfully loaded" message. Further details are provided on the GitHub lib page and on the documentation of the bar.Utils class.

Batch Processors

Some of the scripts included in /BAR/Snippets/ are scripts that apply a common operation to a directory. These batch processors are implemented in different languages and perform the following operations:

  1. Take an input folder specified by the user
  2. Apply a series of operations to individual files of matched extension(s)
  3. Save processed files as TIFF to a dedicated directory, so that no files are overwritten

Typically each of these tasks is handled by separated functions so only the function processing single files needs to be edited. In the Python and IJM implementation, this processing function is called myRoutines(). Note that when editing myRoutines() we do not need to worry about opening, closing or saving the image without overriding the original file, because those tasks are already performed by other functions.

Processing Functions

The file-processing function can include your own code, code generated by the Macro Recorder (Plugins▷ Macros▷ Record...), pre-existing snippets or methods/functions defined in a common BAR lib file.

IJM example, running a macro and a python script in the Snippets/ (another example below exemplifies how to call a macro function from BARlib.ijm):

function myRoutines() {
	snippetsPath = call("bar.Utils.getSnippetsDir");
	runMacro(snippetsPath + "MyCoolestMacro.ijm");
	eval("python", File.openAsString(snippetsPath + "Median_Filter.py"));
}

Jython example, demonstrating how to 1) load BAR lib (in this case BARlib.py, using code generated by Bar▷ Snippets▷ New Snippet...) and 2) how to run a Snippet (in this case Median_Filter.py):

def myRoutines():
    import sys, ij, bar

    # 1) Call a lib function:
    # 1.1) Extend the search path to /BAR/lib/
    sys.path.append(bar.Utils.getLibDir())
    # 1.2) Import all functions in /BAR/lib/BARlib.py
    import BARlib as lib
    # 1.3) Call a function from the file
    lib.confirmLoading()

    # 2) Run a script directly:
    from org.python.util import PythonInterpreter
    script = bar.Utils.getSnippetsDir() + "Median_Filter.py"
    PythonInterpreter().execfile(script)

Tip: Note also that there is an easier (but less flexible) way to batch process a folder: The built-in Process▷ Batch▷ Macro... command.

In this case, you only need to paste the contents of your myRoutines() function into the text area of the command. However, by default, Process▷ Batch▷ Macro... assumes you want to process all the files in a directory. If that is not the case, i.e., you want to restrict the processing to certain file types, you will have to use regex to instruct the built-in command on the file extensions to be considered (see Commander's built-in help for several regex examples). E.g., typing the following in the File name contains field of Process▷ Batch▷ Macro..., would restrict processing to .tif, .stk and .oib files (the default extensions specified in the validExtension() function of Process_Folder_IJM.ijm):

(.*(\.(?i)(tif|stk|oib))$)


Example: Batch Randomization of Filenames

The default task of both the Python and IJM implementation of BAR Process Folder scripts is filename randomization: 1) They copy images from one folder to another, 2) Rename their filenames using a random string and 3) Log changes to a CSV table (so that id of randomized filename can be traced back to the original file). This approach allows for blind analyses of datasets that are sensitive to user interpretation. Below are the descriptions of Process_Folder_PY.py and Process_Folder_IJM.ijm.

Python

In Python we can use the uuid module to generate a random filename (rational here). The result is an impressively succinct function:

def myRoutines(image):
    import uuid
    image.setTitle( str(uuid.uuid4()) )

In more detail: Pass the active image - an ImagePlus object - to myRoutines(). Retrieve a random UUID (e.g., f7dfd6a9-f745-42c2-8874-0af67380c3f5), convert it to a string, then use that string to rename the image using the setTitle() method in ij.ImagePlus.

But because BAR libs already contain such a function, we can just call the randomString() function in BARlib.py, after loading the file:

def myRoutines(image):
    import sys, bar
    sys.path.append(bar.Utils.getLibDir())
    import BARlib as lib
    image.setTitle( lib.randomString() )

To log filename changes, we could use the same strategy used for the IJM implementation. The simplest way to generate a CSV list would be to use ImageJ's Log window:

def myRoutines(image):
    import uuid
    from ij import IJ

    # Remember original filename before changing it
    log_row = image.getTitle()
    # Rename image
    image.setTitle( str(uuid.uuid4()) )
    # Append modified filename to CSV row
    log_row += ", " + image.getTitle()
    # Print row
    IJ.log(log_row)

However, we can use the csv module to achieve a more robust implementation:

import csv, os

# Create a CSV table documenting processed files
csvPath = out_dir + "_ProcessedFileList.csv"
csvExists = os.path.exists(csvPath)
csvFile = open(csvPath, 'a')
csvWriter = csv.writer(csvFile)

# Specify column headings
if not csvExists:
    headers = ['Original path','Processed path']
    csvWriter.writerow(headers)

As such, we only need to add the following, every time a file is processed:

csvWriter.writerow([old_filename, new_filename])

Visit the BAR repository to check how the assembled script (Process_Folder_PY.py) looks like.

IJ Macro Language

In an ImageJ macro (IJM) we will need to define first a function that produces a random filename. The IJM language does not feature an equivalent to the UUID module used previously in the Python implementation. So, we are left with two approaches: 1) call java.util. randomUUID directly, or 2) write an ad-hoc function.

For the former, we take advantage of the IJM language built-in call() function, that calls public static methods in any Java class that ImageJ is aware of:

function myRoutines() {
	randomString = call("java.util.UUID.randomUUID");
	rename(randomString);
}

or even shorter:

	rename(call("java.util.UUID.randomUUID"));

But discovering which methods can be called by the IJM language may not be trivial. Typically, it will require access to an IDE and some Java experience. So what about writing an ad-hoc function?

The approach used in Process_Folder_IJM.ijm is the following: 1) Take a template string containing the characters A-Z and digits 0-9; 2) Pick a random position between the first and last character of the string template. Extract the character at that position; 3) Repeat the last step several times, assembling extracted characters into a concatenated string:

function randomString() {
	// We define the template and measure the number of positions
	template = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	nChars = lengthOf(template);
	// We define an empty string that will hold the result
	string = "";
	// We will want a final string to be 10-characters long
	for (i=0; i<10; i++) {
		// Define a random position between 0 and the penultime character in template
		idx = maxOf(0, round(random()*nChars-1));
		// Extract and concatenate characters
		string += substring(template, idx, idx+1);
	}
	// return result
	return string;
}

This would create e.g., NHH6KG30C9. However, a lengthier filename may be required. Larger filenames would be harder to read, so we can insert hyphens at fixed positions. We will improve the function by passing two arguments to it: the length of the desired filename and a boolean flag to instruct on the usage of hyphens:

function randomString(length, spacers) {
	template = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	nChars = lengthOf(template);
	string = "";
	for (i=0; i<length; i++) {
		idx = maxOf(0, round(random()*nChars-1));
		string += substring(template, idx, idx+1);
		if (spacers && i%5==0) string += "_";
	}
	return string;
}

As such, calling randomString(50, true) would produce e.g., E_ZXTQO_8E9XM_45WG7_8S39. As with the Python implementation, we could also use BAR lib (in this case BARlib.ijm). First, we need to load the file before running our macro, using the code generated by Bar▷ Snippets▷ New Snippet:

libPath = call('bar.Utils.getLibDir') + 'BARlib.ijm';
libContents = File.openAsString(libPath);
call('ij.macro.Interpreter.setAdditionalFunctions', libContents);

// Press 'Run' twice to confirm availability of new additions
confirmLoading();

Once lib/BARlib.ijm is in memory, the function can be called directly:

rename( randomString(50, true) );

Now that we are capable of generating a random filename, we just need to monitor filename changes. We could use the print() function (that outputs to the Log window), or create a two-column table describing the changes. Here is how the final Process_Folder_IJM.ijm looks like:

function myRoutines() {

	// Note that functions can contain other functions
	function randomString(length, spacers) {...}

	// Since we'll be logging filename changes to the Results table, we
	// need to keep track of the table's measurement counter. We'll assume
	// that the Results table was closed when myroutines() was first called
	availableRow = maxOf(0, nResults);
	// Log original filename before changing it
	setResult("Original filename", availableRow, getTitle());
	// Rename image and log changes
	rename(randomString(20, true));
	setResult("Randomized filename", availableRow, getTitle());
}

FAQ

What is the rationale behind BAR?
The motivation behind bar is quite simple: To collect snippets of code that can be incorporated into any workflow. So rather than performing fully fledged procedures, BARs tend to produce single tasks. The advantages are two-fold: 1) Scripts are easier to understand and maintain and 2) they can be used to complement any other ImageJ add-on, let it be the simplest macro or the most sophisticated plugin.
Will I find BAR useful?
Probably. But it is likely that you will need to delve a bit into the BAR philosophy.
Can I contribute to BAR?
Yes, please do! If you have some suggestions on how to improve it, do let us know.
Nothing happens when I run a BAR. What's going on?
In a case of premature termination BARs tend to exit rather silently. The best way to have insights on an unexpected error is to run it directly from the Script Editor: Open the script by holding Shift while selecting it from the BAR▷ menu, press Run and have a look at the editors' s console, where all sort of useful messages will be printed to. Do let us know if you have found a bug.
Does BAR work outside Fiji/ImageJ2?
Yes, but with limitations. ImageJ1 (see ImageJ Flavors if you have doubts about existing ImageJ distributions) will only register scripts saved in the plugins/ folder or on one of its immediate subfolders. For this reason, some of the BAR submenus will appear as empty, and it may not be possible to navigate the BAR/ directory using menu commands (Commander could still be used, nevertheless). Another important aspect is that, without access to the built-in updater, you will have to manually update BAR (by monitoring its rpository), and to manually install (and update) the dependencies (i.e., third-party plugins and third-party libraries) used by BAR).
How do I uninstall BAR?
Run the Updater (Help ▶ Update...). Choose Advance Mode then Manage update sites. Deactivate the BAR checkbox in the alphabetically-sorted list of update sites. Press OK, then Apply changes. All BAR files will be deleted. Note that you can install and uninstall BAR as you see fit. See How to follow a 3rd party update site for more details.
I get an error when I try to load BAR lib (IJM). Why?
Macro functions from a IJ macro lib may only be available once a new instance of the macro interpreter is initiated (this is not the case for other scripting languages). This means you have to call ij.macro.Interpreter.setAdditionalFunctions before running your macro. You can test this by running the default macro generated by BAR▷ Snippets▷New Snippet...:
// Load BARlib.ijm
libPath = call('bar.Utils.getLibDir') + 'BARlib.ijm';
libContents = File.openAsString(libPath);
call('ij.macro.Interpreter.setAdditionalFunctions', libContents);
The first time you run confirmLoading(); ImageJ will complain about confirmLoading being an undefined identifier, but it will successfully recognize the call the second time you run the code above.

Citation

BAR scripts can be cited using the DOI associated with the repository:

  • Tiago Ferreira et al., (2016) 10.5281/zenodo.28838

License

These scripts are free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.