Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Migrating from Vega-Lite

Prism borrows Vega-Lite’s vocabulary (mark, encoding, transform, layer, facet) and channel model. The divergences are intentional — read this guide to port specs in minutes.

At a glance

Vega-LitePrismWhy divergence
data.urlinline data.values / datasets.*.values (or a runtime ref)Prism reads already-materialized rows; it never fetches a URL or reads a .pulse file.
transform[].aggregatesame shapeidentical
op: "mean"samefriendly aliases match Vega-Lite verbatim
mark, encodingsame vocabularysame
type: "quantitative"samenominal/ordinal/quantitative/temporal
scale.schemesamesame color schemes
selectionsame shapepoint + interval supported v1
params / signalsdroppedno reactive runtime
layer, concat, facet, repeatsamefull composition v1
condition encodingssame shapeselection + test predicate conditions supported
strokeWidth (camelCase)stroke_widthsnake_case throughout
Vega expression languagestructured filter / calculate built-insno expression language, no JS eval

snake_case (D019)

All field names in spec + scene IR are snake_case. Single-word Vega-Lite vocabulary (mark, encoding, transform, layer, facet) stays as-is.

Vega-LitePrism
strokeWidthstroke_width
cornerRadiuscorner_radius
fontSizefont_size
tickCounttick_count
labelOverlaplabel_overlap

Structured transforms (D005)

Prism has no expression language. Vega-Lite’s inline expression strings for filter predicates and calculate computed columns are replaced by structured built-ins — JSON object trees. A raw string where a predicate or expression is expected is rejected at decode time.

Vega-LitePrism
"filter": "datum.score > 50""filter": {"op": "gt", "field": "score", "value": 50}
"filter": "datum.region === 'NA'""filter": {"op": "eq", "field": "region", "value": "NA"}
"filter": "datum.a > 0 && datum.b != null""filter": {"and": [{"op": "gt", "field": "a", "value": 0}, {"op": "not_null", "field": "b"}]}
"calculate": "datum.x * 2", "as": "y""calculate": {"op": "mul", "operands": [{"field": "x"}, {"literal": 2}]}, "as": "y"
"calculate": "datum.x == null ? 0 : datum.x", "as": "y""calculate": {"fn": "coalesce", "args": [{"field": "x"}, {"literal": 0}]}, "as": "y"

No datum. prefix, no operators, no JS function calls. See Spec › Filter transform and Spec › Calculate transform for the full grammar (operators, functions, case, and null / division semantics).

Aggregate aliases (D003)

Vega-Lite parity:

count sum mean median min max stdev variance q1 q3 ci0 ci1

Prism adds: distinct mode.

Cohort-analytics extensions (Prism-only): wmean ratio lift share.

Dropped features (v1)

  • params / signals — no reactive runtime.
  • Inline Vega expressions everywhere — use the structured filter / calculate built-ins, or pre-compute richer logic before the data reaches Prism.
  • Vega-Lite tooltip template strings — Prism tooltips are pre-formatted TooltipLine lists.

Added features

  • datasets block + per-layer data overrides — first-class multi-source.
  • Hash join transform ({join: {left, right, on, kind}, as}) — in-Prism, no Pulse change.
  • Cohort-analytics aggregates (wmean, lift, share, ratio).
  • sankey, funnel, sparkline marks — first-class, not third-party plugins.
  • Server-side + browser-side dataset registries.
  • MCP tool surface for agent integration.

Worked porting example

Vega-Lite:

{
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "data": {"url": "data/cars.json"},
  "transform": [{"filter": "datum.Horsepower > 100"}],
  "mark": {"type": "bar", "cornerRadius": 4},
  "encoding": {
    "x": {"field": "Origin", "type": "nominal"},
    "y": {"aggregate": "mean", "field": "Horsepower", "type": "quantitative"},
    "color": {"field": "Origin"}
  }
}

Prism:

{
  "$schema": "urn:prism:schema:v1:spec",
  "data": {"values": [
    {"Origin": "USA",    "Horsepower": 130},
    {"Origin": "Europe", "Horsepower": 105},
    {"Origin": "Japan",  "Horsepower": 95}
  ]},
  "transform": [{"filter": {"op": "gt", "field": "Horsepower", "value": 100}}],
  "mark": {"type": "bar", "corner_radius": 4},
  "encoding": {
    "x": {"field": "Origin", "type": "nominal"},
    "y": {"aggregate": "mean", "field": "Horsepower", "type": "quantitative"},
    "color": {"field": "Origin", "type": "nominal"}
  }
}

Diffs:

  • $schema: URN form.
  • data.url → inline data.values (the caller materializes the rows; Prism reads no URL or .pulse file).
  • filter: expression string → structured {op, field, value} predicate.
  • cornerRadiuscorner_radius.
  • color channel: explicit type (Vega-Lite infers; Prism is strict).

Editor setup

prism init writes .prism/editor/ with configs for VSCode, JetBrains, Neovim, Vim — autocomplete + inline validation on *.prism.json files from the embedded JSON Schema bundle.