The Custom Hanging Protocol feature allows you to write a script that will programmatically define the visual layout of your Annotation Tool at the Project level.
Pre-configuring parameters such as Windowing settings, Thresholding settings, the number of viewports in a Layout Tab, which views display by default, etc., is both an easy way to save time for your annotators and makes for a much smoother overall annotation experience.
Script Usage Guide
This guide provides an overview of the available functions and types to help you effectively manage these settings. At present, you can control the following:
The dimensions of a Layout Tab (setDimensions):
REQUIRED: the number of columns in a Layout Tab (numColumns)
REQUIRED: the number of rows in a Layout Tab (numRows)
The contents of each viewport in a Layout Tab (setViews):
REQUIRED: an array describing each viewport's content (views)
REQUIRED: Which series to show (seriesIndex)
REQUIRED: Which way to view the series (plane)
Flip the view horizontally (flippedHorizontally)
Flip the view vertically (flippedVertically)
Activate Intellisync (synchronized)
Maximize a single viewport in a Layout Tab (expanded)
The default Windowing setting for each Series (setWindowing):
REQUIRED: the number of the Series (seriesIndex)
REQUIRED: the desired Windowing Level (level)
REQUIRED: the desired Windowing Width (width)
The default Thresholding setting for each Series (setThresholding):
REQUIRED: the number of the Series (seriesIndex)
REQUIRED: the lower limit of the Thresholding range (min)
REQUIRED: the upper limit of the Thresholding range (max)
Create and configure a new Layout Tab in your Task (nextTab)
Disable certain viewports (disableViewType)
The Custom Hanging Protocol script takes the available Series for a particular Task as input and returns the layout dimensions and list of views to display.
Custom Hanging Protocol Format Reference
functionsetViews(views:View[]) {//...}functionsetDimensions(numColumns:number, numRows:number) {// ...}functionsetWindowing(seriesIndex:number, level:number, width:number){// ...}functionsetThresholding(seriesIndex:number, min:number, max:number) {// ...}functionnextTab()functiondisableViewType(seriesIndex:number, typeName:'AXIAL'|'SAGITTAL'|'CORONAL'|'3D'|'MIP') { }// this function has been replaced by the Tool Settings page of Project SettingsfunctionsetSegmentationSettings( [ { toolName: ToolOptions; enabled: boolean; modes?: ToolModes[]; defaultMode?: ToolModes; defaultTool?: boolean; } ]);// When a user uploads a Task and enables Hanging Protocols, // the hangingProtocol() function takes Series[] and the following parameters as inputinterfaceSeries { seriesIndex:number; is2DImage:boolean; isVideo:boolean; numFrames:number; name:string; // User defined name if available, else "A", "B", ... imagingAxis:'AXIAL'|'SAGITTAL'|'CORONAL';}interfaceView { plane:'AXIAL'|'SAGITTAL'|'CORONAL'|'3D'|'MIP'; seriesIndex:number; flippedHorizontally?:boolean; flippedVertically?:boolean; synchronized?:boolean; expanded?:boolean; // Only applicable to a single view in a given Layout Tab}
Examples
Default Script
This default script uses some defined macros to make setting the view easier.
functionhangingProtocol(allSeries:Series[]) {// This is the default layout scriptif (allSeries.length>1) {setMultiSeries(); } elseif (allSeries[0].is2DImage) {setSingleView(); } else {setMPR(); }}
The following script creates 2 Layout Tabs, each containing 2 Series.
if (allSeries.length===4) { // executes when there are 4 total Series in a TasksetDimensions(2,1); // set 2x1 layout for Layout Tab 1setViews( // adding the first and second image/volume to Layout Tab 1 [ { seriesIndex:0, plane:'SAGITTAL' }, { seriesIndex:1, plane:'SAGITTAL' } ]);nextTab(); // create and configure Layout Tab 2setDimensions(2,1); // set 2x1 layout for Layout Tab 2setViews( // add third and fourth image/volume to Layout Tab 2 [ { seriesIndex:2, plane:'SAGITTAL' }, { seriesIndex:3, plane:'SAGITTAL' } ] )
Disable a Specific Viewport
The following script will disable all 3D viewports in the RedBrick Annotation Tool.
We can then use the information that has been parsed by the hangingProtocol() function to generate a script that sorts our views, displays the imaging axis and activates Intellisync.
// sort series by Namelet priorities = ['t1','t1ce','t2','flair'];allSeries.sort((a, b)=>priorities.indexOf(a.name.toLowerCase()) -priorities.indexOf(b.name.toLowerCase()));// display Series along the imaging axislet imagingAxis = allSeries[0].imagingAxis;// filter out views that were imaged in a different axislet eligibleSeries =allSeries.filter((series) =>series.imagingAxis === imagingAxis);// Configure viewportssetViews(eligibleSeries.map((series) => {return { seriesIndex:series.seriesIndex, plane:series.imagingAxis, synchronized:true, };}));