Variables
Irregular • File:
Variables.csv• Writer:LaboVariableDataWriter.cs
At a glance
Variables captures every variable write in the experience — one row per assignment, arithmetic modification, or list update. Each row describes a single write: the target variable, its data type and scope, value(s) before and after, and which variable / modifier produced the change (if any). Stamped at trigger time via Stamp(), so FrameNumber / MonotonicExecutionTime reflect the moment of the write.
Use Variables for:
- Reconstructing experiment state at any point in time.
- Debugging — "when did variable X change, and what did it change to?"
- Condition-dependent analyses — filter other streams based on variable state.
When it writes
Whenever variable infrastructure calls LaboDataCapture.Instance.VariableEntry(observation) — after a variable update in VariableManager or related code. Grep for VariableEntry call sites in the LABO source to see exact triggers.
File & location
- Default:
Variables.csvin the run directory. - Writer:
LaboVariableDataWriter.cs. - Observation:
Runtime/DataCapture/Observations/VariableObservation.cs.
Configuration
VariablesDataCapture SO (subclass of DataCaptureConfig). Fields:
| Field | What it does |
|---|---|
enabledLogging | Master enable/disable. |
fileName | Override the default name. |
flushEveryNRows | Batched flush cadence. Default 30. |
writeHeader | Write the header row on first emission. Default true. |
Auto-created on experience open. WindowUtility.OpenExperience() populates this slot if missing.
Columns
Shared prefix
See Column conventions — The shared prefix.
Domain columns
| Column | Type | Description |
|---|---|---|
Variable_Name | string | Target variable name — what was written. |
Variable_DataType | string | Int, Float, Bool, String, IntList, FloatList, StringList, etc. |
Variable_Scope | string | Global, Participant, Session, Epoch, etc. |
Variable_SingleValue | string | Post-write value for non-list variables. NaN for list updates. |
Variable_ListValues | string | Post-write list contents (semicolon-separated), for list variables. NaN for non-list. |
Variable_ModifyingVariable | string | If the write was driven by another variable (e.g. total = total + delta), the name of the driving variable. NaN if not. |
Variable_Modifier | string | The operation — Assign, Increment, Decrement, Multiply, Append, Remove, etc. |
Variable_UpdateValue | string | The delta / operand — e.g. 1 for Increment, the appended item for Append. |
Variable_Index | int | For list updates, the index affected. 0 for non-list writes. |
Sample rows
...shared...,Variable_Name,Variable_DataType,Variable_Scope,Variable_SingleValue,Variable_ListValues,Variable_ModifyingVariable,Variable_Modifier,Variable_UpdateValue,Variable_Index
...,trialIndex,Int,Global,3,NaN,NaN,Increment,1,0
...,responseTimes,FloatList,Participant,NaN,320;445;512,trialTimer,Append,512,2
Note the commas-in-list-values convention — [320, 445, 512] is serialised as 320;445;512 so the CSV parses correctly. See Column conventions — Value encoding.
Join with other streams
Standard FrameNumber join to attach per-frame context to each variable write:
import pandas as pd
exp = pd.read_csv("ExperienceState.csv")
vars_ = pd.read_csv("Variables.csv")
enriched = vars_.merge(exp, on="FrameNumber", how="left", suffixes=("_var", "_frame"))
# All writes to trialIndex during a specific epoch:
enriched[(enriched["Variable_Name"] == "trialIndex") & (enriched["EpochName_frame"] == "Trial")]
Gotchas
- One row per write, not per state change. If
trialIndexis incremented three times on the same frame, you get three rows. State reconstruction = play the rows back in order. Variable_SingleValueis post-write. To reconstruct the pre-write value, either look at the previous row for the sameVariable_Name, or apply the inverse ofVariable_ModifierwithVariable_UpdateValue.- Lists are serialised with semicolons. If a list element itself contains a semicolon (unusual but possible for string lists), there will be ambiguity. Treat
Variable_ListValuesas a best-effort representation; the canonical state reconstruction is replaying the operations, not parsing the list column. - Scope matters for reconstruction. A
Participant-scoped variable is per-participant; aSessionvariable is per-session. When replaying, filter by scope + identifying key before applying writes. - Stamped at trigger time. Same rule as Events — the
MonotonicExecutionTimereflects the real write moment, accurate to microseconds.
Analysis recipes
For condition-dependent filtering of other streams, see the stimulus-locked averaging recipe — the same joining pattern applies for using variable state to segment another stream.