Skip to main content
Skip table of contents

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.

image-20240722-205959.png

Example of setting the X coordinate of the rectangle region’s center to 250/3

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:

image-20240725-152028.png

Adding a custom variable trialCount to a Timeline. Initialized to a value of 0.

image-20240725-152304.png

Updating trialCount using the Set Variables command. The simple expression = trialCount + 1 adds one to the current value of trialCount

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.

image-20240725-152609.png

Set the ExitCondition of an epoch to when the trialCount reaches 20. This expression evaluates whether the statement trialCount = 20 is true or false. If it is true, the exit condition is met and the epoch ends. Otherwise, the epoch starts over.

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.’

image-20240725-163327.png

Custom conditions list inside the Constant Stimuli method

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

image-20240725-163738.png

Defining a stimulus property via an expression that invokes our independent variable

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
.green
.blue

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.

image-20240725-171837.png

Properties of the Oval Region

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.

image-20240725-172114.png

Details of the Center property of the oval region component

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:

LastEvent

General component that stores the absolute last input event recorded during the experiment.

Shares the same structure and properties as WaitForInput.LastEvent. The difference is that WaitForInput stores the LastEvent for that specific command, which is time-bound and is not overwritten.

Calling LastEvent directly will invoke the general component, which is not time-bound and is overwritten with each new input.

Time

Time, in seconds, since the experiment was launched. Uses double precision.

Tracker

Component for the TRACKPixx3. This is available whenever a TRACKPixx3 is added to a project. Note that only one TRACKPixx3 can be used at a time, and the component name is always ‘Tracker.’

Currently, Tracker has the following properties:

Property

Type

Description

isAwake

Boolean

Returns true if Tracker is awake, false otherwise

gazeX

Float

Current average X position of the left and right eyes. Uses the VPixx coordinate system (Cartesian and in pixels, where 0,0 is the center of the screen). If a single eye is tracked, gazeX reports the x position for that eye. Note that this value updates at an approximate rate of 15 - 20 Hz and should only be used for online experiment management, not for offline data analysis.

gazeY

Float

Current average Y position of the left and right eyes. Uses the VPixx coordinate system (Cartesian and in pixels, where 0,0 is the center of the screen). If a single eye is tracked, gazeY reports the y position for that eye. Note that this value updates at an approximate rate of 15 - 20 Hz and should only be used for online experiment management, not for offline data analysis.

More properties will be added in future releases.

TrialNumber

An integer that keeps track of the number of trials executed so far. Only available when using a Method (e.g., Constant Stimuli).

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:

image-20240725-193521.png

Example of expressions within a text field

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
Note: some programming languages interpret the sign of modulo differently (e.g., Python vs. C++). LabMaestro follows C++ convention:

The floating-point remainder of the division operation x/y calculated by this function is exactly the value x - n*y, where n is x/y with its fractional part truncated.

The returned value has the same sign as x and is less or equal to y in magnitude.

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.

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.