Values and Expressions
Values refer to the data assigned to a particular component, property or variable within an experiment. For example, if variable x = 12, then we can say the value of x is 12.
Expressions are formulas used as values in an experiment. When a value containing an expression is invoked, the formula is evaluated and the result is used as the value. For example, if variable x has a value defined as the formula 12 * 2, then the value of x is the result of that formula (24).
To assign an expression to a value field, we use the = sign.
This general approach to using = for expressions is common in other software tools, notably Microsoft Excel. Like in Excel, expressions in LabMaestro provide a variety of mathematical, logical and referential operations. They also use a specific syntax.
Values and expressions are powerful tools for creating dynamic experiments in LabMaestro. This page gives an overview of how to use expressions. At the end of the page is a comprehensive list of the operations currently supported in LabMaestro expressions, along with their proper syntax and examples. Use CTRL+F to search for a specific feature on this page, or use the table of contents below.
Using expressions to invoke other values
You can use expressions to invoke other values stored within an experiment. This can be combined with other kinds of operations to drive the progression of the experiment. When invoking other values via expressions, it is important to remember the following:
Variable and property names are not case-sensitive. E.g., Colour.RED, COLOUR.RED, colour.red and Colour.Red will all work. Similarly, boolean values (e.g., True or False) are also not case-sensitive.
Variable and property names do not use spaces.
String literals (e.g., text strings) should use double quotes, e.g., “my text”
LabMaestro provides several options for previewing experiment designs. Previews only have access to locally available information and may not always be complete. We suggest using the Launch Experiment feature to validate expressions.
In this section, we will review different types of variable and property values, and how they can be invoked within an expression. We will end with a short note regarding invoking values within a text field.
Custom variables
Custom variables are values not tied to a specific part of your experiment. Instead, they are ‘free-floating’ variables that can be modified as needed anywhere inside your Timeline. Custom variables are initialized by selecting the Timeline from the Project menu, and then selecting Custom Variables from the Properties menu. Custom variables can be edited within an epoch using the Set Variables Command. The following Custom Variable types are supported:
Variable Type | Description |
---|---|
Integer | Integers can be positive, negative, or zero. They do not include decimal places. Useful for counting, indexing and discrete data (e.g., Likert values) |
Floating | Positive, negative or zero. Supports decimal places. Useful when precise calculations involving decimals are required. |
Boolean | Logical, can be either “True” or “False.” Not case-sensitive. If used in a mathematical expression, True is interpreted as 1, and False is interpreted as 0. |
Text | A string of text characters. Should be formatted as =“text” to ensure a string literal is used. |
Custom variables are invoked directly within expressions by using their variable name. Let’s consider a common custom variable, trialCount, which tracks how many iterations of a trial have occurred. I want to update this value after each trial and exit an epoch when 20 trials have been completed.
I can create and subsequently update this custom variable in the following way:
To exit an epoch when the trialCount reaches a certain value, I modify the ExitCondition of that epoch. Specifically, I set the exit condition to be true if the current trial count is equal to 20. This uses the logical operator == which means “is equal to.” See the chart section on comparison operators below for more details.
Condition List variables
Condition List variables are implemented in the Method of an Experiment Design. They may be autogenerated, manually defined, or some combination of the two.
Consider a simple conditions list with four rows of colour values, stored as the independent variable ‘Colour.’
In my experiment timeline, I have an epoch with a single stimulus, an oval region called “myTarget.”
I want myTarget’s colour to update to the next colour value in the Condition List when I press a key.
I set myTarget’s RGB colour values as follows:
Red = Colour.red
Green = Colour.green
Blue = Colour.blue
I use the command WaitForInput to listen for a keypress. Since Colour is a list of conditions, the keypress causes the epoch to loop and we move to the next stored R, G and B value of Colour, which updates myTarget’s colour accordingly. Once all stored values have been processed, the epoch ends.
Note that the Condition List variable is invoked using the name of the variable (Colour) and its sub-properties are indexed via dot indexing (e.g., Colour.red). Below is a list of currently supported Condition List variable types, and the syntax for accessing their sub-properties, if any. If a Condition List variable does not have sub-properties, it is simply called via the variable name.
Variable Type | Description | Sub-properties |
---|---|---|
Integer | Integers can be positive, negative, or zero. They do not include decimal places. Useful for counting, indexing and discrete data (e.g., Likert values) | None |
Floating | Positive, negative or zero. Supports decimal places. Useful when precise calculations involving decimals are required. | None |
Boolean | Logical, can be either “True” or “False.” Not case-sensitive. If used in a mathematical expression, True is interpreted as 1, and False is interpreted as 0. | None |
Text | A string of text characters. Should be formatted as =“text” to ensure a string literal is used. | None |
Colour | A three-value list of red, green and blue components of a colour. Currently uses RGB255 (values between 0-255 supported) | .red |
Component properties
Properties are values attached to a component. For example, the Oval Region has the following properties, which can be accessed by selecting the component from the Project menu or Timeline, and checking the Properties menu.
These values are typically referenced via the following format:
myComponentName.PropertyName
Note the absence of spaces. Some property field labels have spaces for readability; these spaces should be omitted when calling a property value in an expression. E.g., Full Screen becomes myTarget.FullScreen.
Some properties have sub-properties. Consider the novel region property “Center,” which contains a pair of x and y coordinates that define the center of the oval region. Center also has the sub-properties System and Units, which are used to interpret the x and y values.
To index the sub-properties of a property, use an additional dot index. For example, this Oval Region is called “myTarget,” so to access the sub-property x, we would use the syntax: myTarget.Center.X
Tip: If you are assigning a value to a property or sub-property within a component (property A), and the value refers to another property within the same component (property B), you do not need to spell out the entire component name of B when assigning A.
For example, if I update myTarget.Center.X to be 50, and I want myTarget.Center.Y to equal myTarget.Center.X, in the y field I only need to write =x.
The exception to this is if you have a Conditions List variable or Custom variable that is also called x. If this happens, Y will prioritize Conditions List variables and then Custom variables over Center.X (in that order). In this case, you will need to spell out Center.X explicitly to ensure the right value is assigned.
Similarly, if you have a Conditions List variable or Custom variable with the name “center” you would not want to invoke “Center.X” when assigning the y value, since this will point to the Conditions List or Custom Variable called “Center” first and throw an error.
Special values
There are a few special components that exist in most experiments but are not represented explicitly in the timeline. These can still be accessed via expressions by using the right syntax. Below is a table of such special values and examples of how to invoke them:
Invoking values within a text field
To invoke an existing value or the result of an expression, within a text field, we use {}. Note that the = is not necessary in this case.
For example:
List of currently supported operations (as of version 1.8.0)
Operation | Syntax | Example |
---|---|---|
Arithmetic | ||
Addition | + | =1+5, =x+1 |
Subtraction | - | =4-9, =y-50 |
Multiplication | * | =2*6, =val*255 |
Division | / | =1920/2, =trialCount/10 |
Parentheses | ( ) | =(1+20)/3 |
Absolute | abs() | =abs(-5) |
Natural logarithm | log() | =log(2.718) |
Logarithm to the base 10 | log10() | =log10(value) |
Exponent | pow(base, power) | =pow(2,10), =pow(100, 0.5) Note: roots can be implemented as decimal powers |
Modulo | mod() % | =mod(10, 3), =10 % 3 The floating-point remainder of the division operation x/y calculated by this function is exactly the value The returned value has the same sign as |
Negation | ! | = !condition |
Sign | sign() | =sign(-7) Note: returns -1 for negative numbers, 1 for positive numbers (including 0) |
Comparison | ||
Equals | == | =x == (y + z) = LastEvent.Key.Value =='M' |
Does not equal | != | =x != (y - z) |
And | && | =(x > 1) && (y < 10) |
Or | || | =(x < 1) || (y > 10) |
Bitwise And | & | =5 & 3 |
Bitwise Or | | | =5 | 3 |
Greater than | > | =5 > 3 |
Less than | < | =5 < 3 |
Greater than or equal to | >= | =x >= (y * 2) |
Less than or equal to | <= | =x <= (y / 2) |
Conditional | ||
Ternary operator | condition? trueResult : falseResult | =condition ? "correct" : "incorrect" |
Reduction | ||
Minimum | min(var1, var2) | =min(3, 7), =min(a, min(b,c)) Note: Max and min operate on pairs of variables. Multiple nested calls can be used to handle larger lists of variables. |
Maximum | max(var1, var2) | =max(3, 7), =max(a, b) Note: Max and min operate on pairs of variables. Multiple nested calls can be used to handle larger lists of variables. |
Rounding (all functions round to the nearest integer) | ||
Floor | floor() | =floor(4.7), =floor(number) |
Ceiling | ceil() | =ceil(4.2), =ceil(rawValue) |
Round | round() | =round(4.5), =round(variable) |
Trigonometric (angles are in degrees) | ||
Sine | sin() | =sin(30), =sin(angle) |
Cosine | cos() | =cos(45), =cos(theta) |
Tangent | tan() | =tan(60), =tan(alpha) |
Arcsine | asin() | =asin(0.5), =asin(value) |
Arccosine | acos() | =acos(0.5), =acos(value) |
Arctangent | atan() | =atan(1), =atan(ratio) |
VPixx devices | ||
Fixation | fixation(ScreenX, ScreenY, Threshold) | =fixation(10, 50, 100) will return True if the GazeX (same value as returned by tracker.GazeX) is within 10 +/- 100, and GazeY is also within 50 +/- 100. Otherwise returns false. Note: As of 1.9, all values are in pixels. This function is based on the current gaze location. It does not matter if the gaze is fixed or moving. Consider checking that the fixation flag is also high whenever a true fixation inside the region of interest is required. |
List of common expression errors
LabMaestro will outline a field in red if it cannot interpret an expression. Hover your mouse over the expression to see the error code. The section below lists common error codes and their meanings.
Error Type | Description | Example/Error Message |
---|---|---|
Typecheck Error | There is an error with the type of values used in the expression. This occurs when operands have mismatched types or when compare operations have different types for true and false branches. | Operator did not have the same type. Left-hand side has type [ ], while right-hand side has type [ ]. Property expects an expression of Integral type, but was provided an expression of Numeral type. |
Token Error | This error occurs when a number is too large or when a string is found within a number, making conversion impossible. | Number is too big to fit. Lexer could not read literal starting with number value. |
Parser Error | This error happens when there is an issue with parsing the expression, such as missing parentheses. | Found conditional operator ? but no : for else branch. Missing closing parenthesis in function definition. |
Scope Error | Occurs when something does not exist within the scope of the expression, such as a nonexistent variable or function. | Identifier [ ] not found. Method [ ] must issue a result. A common error is failing to add quotation marks (“”) around a string. For example, =LastEvent.Key.Value=="Space" |
Cycle Error | Occurs when there is a cycle within the expression where the result of an expression is needed by something else which in turn is needed for the expression itself. | Identifier [ ] pointed to a property containing an expression that led to a cycle. |