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

SyntaxDescription
{$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: sourcefilter (optional, chainable) → columnoperator (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

OperationDescription
sumSum numeric column
avgArithmetic mean
minMinimum
maxMaximum
countCount non-null values
uniqueDistinct values (CSV)
uniquecountCount 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 places
  • f — float

Works on combined expressions: {expr1 / expr2 * 100:,.2f}.

Virtual geometry columns

ColumnDescription
geomareaPolygon area from geometry
geomlengthLine 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

  1. Expressions substitute before markdown compile.
  2. Missing source, column, or row → empty string.
  3. Non-numeric values in aggregations are skipped or treated as 0.
  4. 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