3.3 Expression Syntax
Markdown variable expressions use { } curly braces in Series, themes, memos, and docs. They are evaluated and replaced before markdown-to-HTML runs. Build them with the Expression Syntax Helper or copy patterns from 3.4 Expression Examples.
Data comes from sourceDataStore (loaded layer features) unless you pass custom variables to the Markdown component.
Custom context variables
{ "page": 12, "idParcel": "1.KA.12" }
Page {$page} — Parcel {$idParcel}
→ Page 12 — Parcel 1.KA.12
Variable chains
| Syntax | Description |
|---|---|
{$var.split(', ')} | Split string to CSV list |
{$var.split(', ').join('--')} | Split then rejoin |
{$var.split(', ').lookup("table",'lookupcol','outcol').join(', ')} | Lookup each token in a table column |
sourceDataStore — procedural syntax (preferred)
{"sourceId"[.filter('col','val','op')]."column"[.op][.join('sep')]}
Flow: source → filter (optional, chainable) → column → operator (optional) → join / getitem / getindex (optional).
- sourceId — layer or table key in double quotes, e.g.
"Kallang - LU||LandUse","csvtable". - filter('col','val','op') — row filter; operators:
==,!=,<,>. Chain multiple filters. - column — attribute name in double quotes, placed after filters and before operators.
- Operators — see table below.
- join('sep') — join column values:
{"source"."col".join('-')}→a-b-c.
No operator — outputs column values as CSV: {"source"."col"} → a,b,c.
Legacy syntax (still supported)
{"sourceId"."columnName".filter(...).operation}
Column before filter — prefer procedural syntax for new content.
Operations
| Operation | Description |
|---|---|
sum | Sum numeric column |
avg | Arithmetic mean |
min | Minimum |
max | Maximum |
count | Count non-null values |
unique | Distinct values (CSV) |
uniquecount | Count distinct values |
n-0, n-1, … | Value at 0-based index |
lookup("table",'lookupcol','outcol') | Replace values via lookup table |
join('sep') | Join values with separator |
getitem('key') | JSON object key; empty key '' expands all values (see GG GFA) |
getindex(n) | Array slot (0-based; negative from end) |
Arithmetic and comparisons
Combine sub-expressions with + - * / ^ % //. Parentheses allowed.
{(10 + 2)/3}
{"source"."area".sum / 100}
{"Open"."Area_Ha".sum / "Total"."Area_Ha".sum * 100:,.1f}
Comparisons >, <, >=, <=, ==, != render as inline true/false icons:
{10 > 5}
{"Layer".filter('TYPE','A','==')."Area".sum > 1000}
Number formatting
Append Python-style specifier after the expression:
{"source"."area".sum:,.2f}
,— thousands separator.2— decimal placesf— float
Works on combined expressions: {expr1 / expr2 * 100:,.2f}.
Virtual geometry columns
| Column | Description |
|---|---|
geomarea | Polygon area from geometry |
geomlength | Line length from geometry |
Total (ha): {"Network||Service"."geomarea".sum / 10000:,.2f}
GG GFA column (gg_gfa|Layer name)
When a layer uses gg_fill-extrusion-floors, features carry a JSON property gg_gfa (space-type → [floors, m²] tuples). In the Expression Syntax Helper, pick gg_gfa|Your Layer Name — the |Layer suffix is display-only; data reads column gg_gfa.
Chain JSON accessors after the column:
{"Parcels||Building"."gg_gfa|Kallang Building".getitem('').getindex(1).sum:,.0f}
getitem('')— all tuple values from the JSON object (flattened for aggregation)getindex(1)— second element of each tuple (floor area m²)getindex(0)— floor count
See 3.5 Geometry Generated (GG) and Vertical Zoning & Extrusion.
Processing rules
- Expressions substitute before markdown compile.
- Missing source, column, or row → empty string.
- Non-numeric values in aggregations are skipped or treated as 0.
- Evaluation is sandboxed — no arbitrary code execution.
Keywords
expression, syntax, source, filter, column, sum, avg, join, lookup, getitem, getindex, geomarea, geomlength, gg_gfa, format, variables, markdown