Skip to content

Context Map Syntax

Context maps provide a runtime-only mapping layer that is applied after spec and transform resolution. They are used to customize metadata, control conversion selection, and define output layout behavior without modifying installed specs or rules.

Context maps are supplied explicitly at runtime and are not installed as addons.


Experimental / lightly tested

Context maps are currently an early-stage, conceptual model that was introduced for brkraw-bids development and has not yet been extensively tested across diverse datasets. Expect sharp edges and potential breaking changes in syntax/behavior. Validate outputs carefully before relying on context maps in production pipelines.

Purpose and scope

Context maps are intended for:

  • project-specific subject, session, or run mapping
  • conditional metadata overrides
  • scan selection based on mapped values
  • output layout and naming customization

They are not intended to replace specs or rules. Instead, they operate on top of spec outputs.

Key properties:

  • runtime only (not stored in the config root)
  • applied after spec and transform evaluation
  • scoped to a single invocation or script
  • optional but powerful
  • designed to live alongside a raw dataset as a small “manifest” that captures project-specific conversion and organization intent for reproducibility

High-level model

The evaluation order is:

  1. Rules select specs and converter hooks
  2. Specs and transforms produce structured outputs
  3. Context map rules are applied to those outputs
  4. Output selection, metadata sidecars, and layout rendering use the final values

Context maps never affect rule matching. They operate on the resolved outputs.


File format

A context map is a YAML mapping.

Top-level keys correspond to output keys produced by specs, or define new keys.

<OutputKey>:
  <rule definition>

Each value may be either:

  • a single rule object
  • a list of rule objects (evaluated top to bottom)

meta section

The optional __meta__ section defines layout-related defaults.

__meta__:
  layout_entries:
    - key: Study.ID
      entry: study
      sep: "/"
    - key: Subject.ID
      entry: sub
      sep: "/"
  layout_template: "study-{Study.ID}/sub-{Subject.ID}/{Protocol}"
  slicepack_suffix: "_sl{index}"

Notes:

  • __meta__ affects layout rendering only
  • it does not affect mapping rules
  • values here act as defaults and may be overridden elsewhere
  • you may define both layout_entries and layout_template; if both are present, layout_template takes precedence (it overrides layout_entries)

Rule object schema

Each rule object supports the following fields.

cases (hierarchical rules)

OutputKey:
  when:
    Subject.ID: "XXX"
  type: const
  override: true
  cases:
    - when:
        ScanID: 1
      value: "A"
    - when:
        ScanID: 2
      value: "B"

Behavior:

  • cases is a list of rule objects evaluated only after the parent rule matches
  • each case is merged with the parent rule (case fields override parent fields)
  • cases are evaluated top to bottom; the first matching case is applied
  • if no case matches, the parent rule is applied only when it defines a value, mapping, or an unconditional default

Using cases for per-scan metadata (short)

Use cases when a single dataset must be converted in one run, but scan-level metadata or naming needs to diverge. This is common in retrospective BIDS standardization where subject IDs, sessions, or modality suffixes depend on ScanID.

Example:

Subject.ID:
  type: mapping
  values:
    "MouseA": "001"
    "MouseB": "002"
  override: true

Modality:
  selector: true
  type: const
  override: true
  cases:
    - when:
        ScanID: 3
      value: "T1w"
    - when:
        ScanID: 7
      value: "bold"

BIDS-focused example (short)

Use a context map to normalize subject/session naming, generate per-scan metadata, and control BIDS layout in a single pass.

Session:
  type: mapping
  values:
    "baseline": "01"
    "followup": "02"
  override: true

Suffix:
  type: const
  override: true
  cases:
    - when:
        ScanID: 3
      value: "T1w"
    - when:
        ScanID: 7
      value: "bold"

__meta__:
  layout_template: "sub-{Subject.ID}/ses-{Session}/{Suffix}/sub-{Subject.ID}_ses-{Session}_run-{Counter}_{Suffix}"

Notes:

  • Counter helps disambiguate repeated acquisitions with the same parameters.
  • Suffix (or Modality) can be driven by cases to vary per scan.
  • selector: true may be set on the parent or a case; only scans that map a value pass selector filtering.

selector

selector: true

When true, the key must produce a mapped value for a scan to be eligible for conversion.

Selector evaluation uses the merged info and metadata outputs, regardless of the target field.

Selectors can be declared on parent rules or nested cases; any selector: true in the rule tree marks the key for selection.

Example (Subject + ScanID selection):

Subject.ID:
  type: mapping
  values:
    "MouseA": "001"
  selector: true
  cases:
    - when:
        ScanID: 3
      value: "001"

target

target: info_spec

Controls which spec output the mapping applies to.

Valid values:

  • info_spec (default)
  • metadata_spec

type

type: mapping

Valid values:

  • mapping
  • const

Notes (implementation):

  • type may be omitted when it can be inferred:
    • values: implies type: mapping
    • value: implies type: const

mapping rules (type: mapping)

Subject.ID:
  type: mapping
  values:
    "JohnDoe's rat no1": "JD01"
    "JohnDoe's rat no2": "JD02"
  default: "unknown"
  override: true

Behavior:

  • the current value of Subject.ID (from the selected spec output) is looked up in values
  • if a match is found, the mapped value replaces Subject.ID
  • if no match is found:
    • default is used if provided (e.g., unknown)
    • otherwise the original value is preserved
  • override controls whether an existing non-null value may be replaced (layout typically adds the BIDS entity prefix, e.g. sub-{Subject.ID}).

Notes (implementation):

  • If the current value is a list/tuple, mapping is applied element-wise and the container type is preserved.
  • If the current value does not match directly, BrkRaw also tries str(value) as a lookup key (useful when the current value is numeric but YAML keys are strings).

constant rules (type: const)

type: const
value: "pilot"
override: true

Behavior:

  • the constant value is assigned directly
  • override controls whether existing values are replaced

override

override: false

Controls whether this rule may replace an existing value.

Default behavior:

  • true: replace existing value
  • false: fill only if the value is missing

when (conditional rules)

when:
  ScanID: 3
  Subject.ID: "TEST"

The when field restricts rule application based on already-resolved values.

Supported operators include:

  • exact match
  • in
  • regex
  • not

Notes (implementation):

  • when is evaluated as an AND across keys (all conditions must match).
  • Each condition may be:
    • a scalar (exact match), or
    • an operator mapping (all operators inside the mapping must match)
  • Reserved IDs are available in when (case-insensitive):
    • ScanID, scan_id, scanid
    • RecoID, reco_id, recoid
  • in accepts either a scalar or a list; if the actual value is a list/tuple, it matches when any element is in the expected list.

Rules are evaluated against the original spec outputs, not against values modified by earlier context map rules.

When cases is used, the parent when is evaluated first and each case when is evaluated against the same original outputs. The effective when for a case is the combination of parent + case conditions.


Rule lists and evaluation order

When a key maps to a list of rules:

Modality:
  - when:
      Method:
        in: ["EPI", "BOLD"]
    value: "bold"
    override: true

  - default: "unknown"

Evaluation rules:

  • rules are evaluated top to bottom
  • the first matching rule is applied
  • if no rule matches:
    • default is used if present
    • otherwise the original value is preserved

Creating new keys

Context maps may define keys that are not produced by specs.

Run:
  type: const
  value: 1

These keys become available for:

  • selector logic
  • metadata sidecars
  • output layout rendering

Note:

  • Creating a new key with type: mapping typically requires either default: or an explicit values: entry for null/None, because a missing key has no input value to look up.

Scan selection with selectors

Keys marked with selector: true are used to filter conversions.

Modality:
  selector: true
  type: mapping
  values:
    1: "T1w"
    2: "T2w"

Only scans that produce a value for this key are converted.


Layout interaction

Context map outputs can be referenced by layout definitions.

__meta__:
  layout_template: "sub-{Subject.ID}/ses-{Session}/scan-{ScanID}"

Layout resolution uses the final values after all context map rules have been applied.


Validation

Context maps can be validated programmatically.

from brkraw.specs.remapper import validate_context_map

validate_context_map("maps.yaml")

Schema:

  • src/brkraw/schema/context_map.yaml

Validation checks:

  • rule structure
  • allowed fields and types
  • operator correctness

Design notes

  • context maps are runtime-only and project-scoped
  • they do not affect rule selection
  • they are applied after spec and transform evaluation
  • they can filter scans via selectors
  • they are the preferred way to customize layout and metadata per project