Scripting is an important aspect of Phaedra, as it adds a degree of flexibility to the application that is needed to support:
- Data capture: different types of instruments and file formats
- Feature calculation: different types of assays and feature calculation formulae
- Misc scripting: for example, automatisation of day-to-day tasks, such as validation and workflow execution
Scripts are written by users or administrators, and can be triggered in various ways in Phaedra. Out of the box, Phaedra supports the following scripting languages:
- JEP (Java Expression Parser)
An addon is available that allows you to script in Python as well, see the Python Addon.
The rest of this document assumes you are familiar with scripting in general, including concepts such as function calls, variables, etc.
To test a script snippet, you can use the Console view. To open this view:
Select Window > Show View > Other... > General > Console.
In the Console's toolbar, click on the blue screen icon and select the language you want to script in.
To view the list of services available in the API, type:
To obtain a particular service, use the
get function, for example:
plateService = API.get("PlateService") plate = plateService.getPlateById(1)
All services that are exposed by the API, are documented in the Javadoc pages.
Phaedra's data capture component is heavily scripted. The primary reason for this is the fact that data capture is very much dependent on the user's infrastructure and data file formats. Phaedra offers a number of generic data capture scripts out of the box, but in a real life scenario it is very likely that at some point, you will have to customize or write your own data capture script.
Data capture scripts are stored on the file server, and can only be uploaded or modified by an administrator. To view or edit a data capture script as an administrator, click Administrator > File Server Browser.
The folder 'data.capture.modules' contains all the scripted modules that are currently known to Phaedra. Double-click on a file to open it.
You will notice that most data capture scripts start with this line:
This is a reference to the script catalog, to a script named 'common.js'. To see the contents of this common.js script (and the whole script catalog), navigate to script.catalog > dc > common.js
The purpose of the common.js script is to provide a number of convenience functions, for example to find files or folders based on regular expressions, or to parse XML or CSV files.
Data capture scripts are only called during a data capture job; they cannot be called directly. When they are called, they receive several additional objects to work with:
- ctx: a reference to the DataCaptureContext
- config: a reference to the ModuleConfig
- task: a reference to the DataCaptureTask
- monitor: a reference to the data capture job's progress monitor
When setting up or editing a Protocol Class, you can attach calculation formulae to well features.
This piece of script will be evaluated for every well, and thus expects one return value (numeric or string) for each invocation. For example, the below JEP expression returns a division of two other well features:
For most simple calculations, the JEP language is recommended as it is the most compact language. However, you can choose another language from the list, and enter a much more complex formula if you like. Custom calculation scripts have access to these additional objects:
- data: a reference to the PlateDataAccessor
- well: a reference to the Well
- feature: a reference to the Feature
Some additional notes on calculated well features:
- After adding or modifying a feature calculation formula, remember to save the protocol class and recalculate your plates. This is not done automatically.
- If a formula generates an error, the well's value will be NaN (Not a Number, for numeric features) or null (for string features).
- Keep in mind that the formula is evaluated against each well. Avoid repeating expensive calculations, use the StatService instead.
JEP (Java Expression Parser) is a compact language for writing one-liner expressions. They are well suited for writing feature calculation formulae that refer to other features, and do not involve extensive coding.
You can write JEP expressions using references, functions, operators and literals.
References are just that: references to values. Phaedra supports 3 types of references:
Well feature references are delimited by the hash character (#), and refer to a single well value. For example,
#CellCount#refers to the value of the 'CellCount' feature for the current well.
Subwell feature references are delimited by the dollar character ($), and refer to a vector of values with one value per subwell item. For example,
$AvgNucInt$refers to the values of the 'AvgNucInt' subwell feature, and will return a vector with one value per cell in the current well.
Well property references are delimited by the at character (@), and refer to static well properties. For example,
@Well Number@refers to the well's number, starting from 1 in the top left of the plate.
In addition, references can be extended in two ways:
Scopes change the scope of the reference. For example, well feature references refer to a feature value for a single well, so their scope is 'well', and they return a single value. But by changing the scope to 'plate', you will get a vector of values instead (one value for each well in the plate). To set a scope, use the arrow notation (->) and set the scope in front of the reference. For example:
#plate->CellCount#will return a vector with 384 values when evaluated against a well of a 384-well plate.
Normalizations can be applied only to well feature references, and will translate raw feature values into normalized feature values. To apply a normalization, use the arrow notation (->) and set the normalization at the end of the reference. For example,
CellCount->%EFFECTwill return the '%EFFECT' normalized value of the 'CellCount' well feature.
JEP comes with a predefined set of common mathematical functions, such as
mean() and many more.
These functions often accept one or more arguments, which are usually references to single values or vectors.
For example, when the function call
med($AvgNucInt$) is evaluated against a well, it will compute the median of
the vector containing the 'AvgNucInt' values for all cells in the well.
To get more information about a particular function, open the JEP Expression dialog and hover the mouse cursor over a function in the function list.
In addition to the scenarios described above, you can also write and run arbitrary scripts on plates, at any time. There are two ways to go about this: Console Scripting and Catalog Scripting.
The Script Console
You can write scripts on the fly in the Console view. For example, to modify a plate's barcode:
plateService = API.get("PlateService") plate = plateService.getPlateById(1) plate.setBarcode(plate.getBarcode() + "_modified") plateService.updatePlate(plate)
This is most suited for small, one-off scripts. For more complex scripts that can be reused, use the Catalog approach below.
The Script Catalog
Scripts can also be uploaded into the script catalog, but this requires administrator privileges. To view or modify the catalog, select Administrator > File Server Browser > script.catalog > misc
Catalog scripts can be run by any user on any plate they have access to. To do this, select one or more plates, right-click and select Scripts > Run Script from Catalog.
Scripts that are uploaded into the Script Catalog, can also be used to generate plots. To view such plots, open the Scripted Chart view: select Window > Show View > Other... > Scripted Chart.
For more information on scripted charts, take a look at the scripting tutorials (see below).
A number of tutorials on the above script types can be found on GitHub.