Skip to main content
A highlight emphasises the observations that match a predicate by de-emphasising the ones that don’t. You describe what to match — not which pixels to paint — so the highlight tracks the data through re-sorts, filters, and updates.

Predicates

The first argument to highlight() is a predicate — a test against your post-transform columns. Field predicates name a variable and a comparison:
Ordered operators (gt, gte, lt, lte, range) need a numeric or date column. Using one against a categorical field is an INVALID_PREDICATE_OPERATOR warning that drops the whole highlight — the chart still renders, minus that emphasis. Naming a column the data doesn’t have (UNKNOWN_VARIABLE) behaves the same way, and one bad leaf inside an and or or drops the highlight it belongs to. Both arrive as diagnostics.
There is no neq here — write { not: { variable: 'region', eq: 'EU' } } instead. (The neq operator on transform.filter belongs to a separate comparison vocabulary.) Combine predicates with the logical forms and, or, and not:

Scope

By default a highlight matches individual observations. The scope option expands each match to a larger visual unit:

Scoping to one layer

In a multi-layer chart (say bars plus a trend line), bind the highlight to a single layer: name the layer with id and point at it with layerId. Observations in other layers are never tested, so a Q4 highlight on the bars leaves the trend line untouched:
Omit layerId to evaluate the predicate against every layer. A layer you never name gets an id assigned at resolve time, so scoping is the one case where naming it yourself matters.

Combining highlights

Multiple highlight() calls accumulate, and the engine unions their matches — an observation matched by any highlight is emphasised. So two separate highlights behave like an or:
Because the union is exactly an or, this is equivalent to a single highlight with an or predicate — same matched observations, same result:
Reach for the single or predicate when the two conditions are one idea; reach for two separate highlights when they’re independent emphases you might toggle separately.

Styling the de-emphasis

Every non-matched observation carries the dimmed style state, and what that state looks like is one stylesheet entry. The built-in stylesheet dims to alpha: 0.4; put your own entry in overrides, where it wins the cascade:
alpha lowers the opacity of non-matched observations; saturation: 0 drains their color toward grey. SetHighlightDimStyleCommand is the same choice as one command, for a picker in an editing UI — it writes exactly that entry:
'dim' writes the built-in wash (alpha: 0.4) out in full, 'desaturate' writes { saturation: 0, alpha: 0.6 }. readHighlightDimStyle(spec) reads the current choice back to select the right item in the picker.

Highlight commands

highlight() has a one-for-one imperative mirror: The id is settled when the command is constructed, so RemoveHighlightCommand can address a highlight that was added without one.
  • Styling — the stylesheet the dimmed entries live in, and the where condition that takes this same predicate language
  • Mappings & aesthetics — the variables a predicate can name
  • Transforms — predicates run against post-transform columns