Skip to content

Selection

selection_point, selection_interval, conditional encodings (when / value).

Ferrum — a statistical visualization library with a Rust core.

selection_multi module-attribute

selection_multi = partial(selection_point, toggle='event.shiftKey')

selection_single module-attribute

selection_single = partial(selection_point, toggle='false')

ConditionalSpec dataclass

Resolved conditional encoding — produced by sel.when(...).otherwise(...).

Do not construct directly. Build one through the selection fluent API::

sel.when(<if_encoding>).otherwise(<else_encoding>)

Attributes:

Name Type Description
selection_name str

Name of the Selection that drives the condition.

if_selected encoding channel or value(...)

Encoding applied when a datum falls inside the selection.

if_not encoding channel or value(...)

Encoding applied when a datum falls outside the selection.

channel str or None, default None

Explicit wire channel (e.g. "opacity", "size", "color"). Set by Chart.encode(<channel>=cond) from the encode key, so the wire channel and the value-kind resolution match even when the branches are bare numbers (which carry no channel of their own). When None the channel is inferred from if_selected via _resolve_channel.

selection Selection or None, default None

The originating Selection, carried so callers (Chart.encode / Chart.conditional) can auto-register it without a separate .add_selection() call.

Examples:

>>> import ferrum as fm
>>> sel = fm.selection_point()
>>> cond = sel.when(fm.Color("category")).otherwise(fm.value("#cccccc"))
>>> type(cond).__name__
'ConditionalSpec'

to_spec_dict

to_spec_dict() -> dict

Serialize to a dict matching the Rust ConditionalEncoding shape.

When self.channel is set (the encode(<channel>=cond) path) it is used as both the wire channel and the value-kind hint for if_selected/if_not. Otherwise the channel is inferred from if_selected (the .conditional(...) path with an encoding object).

Selection dataclass

Bases: Parameter

Immutable selection descriptor.

Created by selection_point(), selection_interval(), selection_single(), or selection_multi() — do not construct directly.

Selection is a subtype of Parameter, so isinstance(sel, Parameter) is True and sel.ref() returns {"param": self.name}.

Attributes:

Name Type Description
name str

Stable identifier used to link this selection to conditional encodings and to the WASM renderer.

kind {'point', 'interval'}

Selection type.

params dict

Resolved parameters forwarded to the Rust SelectionSpec.

bind str or None, default None

Optional bind target. "legend" wires legend-entry clicks to toggle the point selection. When None the "bind" key is omitted from to_param_spec_dict() output.

Examples:

Build a conditional encoding from a selection:

>>> import ferrum as fm
>>> sel = fm.selection_point()
>>> color_enc = sel.when(fm.Color("category")).otherwise(fm.value("#cccccc"))
>>> fm.Chart(df).mark_point().encode(
...     x=fm.X("x"), y=fm.Y("y"), color=color_enc
... ).add_selection(sel)

ref

ref() -> dict

Return the reference marker dict used at parameter reference sites.

Returns:

Type Description
dict

{"param": self.name} — consumed by scale.domain, filter predicates, and conditional value sites.

Examples:

>>> import ferrum as fm
>>> fm.param("brush").ref()
{'param': 'brush'}

when

when(if_encoding: Any) -> _SelectionCondition

Start a conditional encoding: sel.when(Color("x")).otherwise(value("#ccc")).

to_spec_dict

to_spec_dict() -> dict

Serialize to a dict matching the Rust SelectionSpec shape.

This is the existing Phase 11c wire format consumed by the WASM renderer. The bind field is intentionally excluded here — it belongs only in to_param_spec_dict().

Returns:

Type Description
dict

{"type": kind, "name": name, ...params}

to_param_spec_dict

to_param_spec_dict() -> dict

Serialize to the params-array wire dict (D6 reactive-parameter format).

This is the unified declaration consumed by the static resolver and the new WASM parameter wiring. Selections also continue to serialize into the existing selections key via to_spec_dict() for backward-compatible WASM reads.

"bind" is emitted only when set to avoid null clutter.

Returns:

Type Description
dict

Wire shape::

{"name": str, "kind": "point"|"interval",
 "select": {<params dict>}}

# with bind:
{"name": str, "kind": "point"|"interval",
 "select": {<params dict>}, "bind": str}

Examples:

>>> import ferrum as fm
>>> brush = fm.selection_interval(name="brush", encodings=["x"])
>>> brush.to_param_spec_dict()
{'name': 'brush', 'kind': 'interval', 'select': {'translate': True, ...}}

SelectionMark dataclass

Visual style for the interval selection brush rectangle.

Pass an instance to selection_interval(mark=...) to override the default brush appearance.

Parameters:

Name Type Description Default
fill str

Hex colour string for the brush fill (e.g. "#4287f5"). Defaults to the renderer's built-in blue.

None
stroke str

Hex colour string for the brush border. Defaults to the renderer's built-in grey.

None
fill_opacity float

Opacity of the fill (0.0 = transparent, 1.0 = opaque).

0.3
stroke_opacity float

Opacity of the border.

1.0
stroke_width float

Border line width in pixels.

1.0
stroke_dash list of float

Dash pattern for the border (e.g. [4, 2]). Solid when omitted.

None

Examples:

>>> import ferrum as fm
>>> brush_style = fm.SelectionMark(fill="#ff9900", fill_opacity=0.2, stroke_dash=[4, 2])
>>> brush = fm.selection_interval(mark=brush_style)

to_spec_dict

to_spec_dict() -> dict

Serialize to a dict matching the Rust SelectionMarkStyle shape.

selection_interval

selection_interval(*, fields: list[str] | None = None, encodings: list[str] | None = None, translate: bool = True, zoom: bool = True, mark: SelectionMark | None = None, resolve: Literal['global', 'union', 'intersect'] = 'global', name: str | None = None) -> Selection

Create an interval (brush) selection activated by dragging.

An interval selection lets the user drag a rectangular brush over the chart. All marks inside the brush are considered selected. The brush supports panning (translate=True) and scroll-to-zoom (zoom=True) after it is drawn.

Parameters:

Name Type Description Default
fields list of str

Data fields to project the brush onto. When omitted the brush applies to all fields represented by the brushed encodings.

None
encodings list of str

Encoding channels to constrain the brush to (e.g. ["x"] for a 1-D horizontal brush).

None
translate bool

Allow the user to reposition the brush by dragging inside it.

True
zoom bool

Allow the user to scroll inside the brush to zoom the view.

True
mark SelectionMark

Visual style of the brush rectangle. Defaults to a semi-transparent blue fill with a solid grey border.

None
resolve ('global', 'union', 'intersect')

How to resolve this selection when the chart is faceted.

"global"
name str

Stable identifier for the selection. Auto-generated when omitted.

None

Returns:

Type Description
Selection

Immutable selection descriptor. Pass to Chart.add_selection() and use sel.when(...).otherwise(...) to build conditional encodings.

Examples:

Brush that greys out unselected points:

>>> import ferrum as fm
>>> brush = fm.selection_interval()
>>> fm.Chart(df).mark_point().encode(
...     x=fm.X("x"), y=fm.Y("y"),
...     color=brush.when(fm.Color("category")).otherwise(fm.value("#cccccc")),
... ).add_selection(brush)

Horizontal-only brush:

>>> brush = fm.selection_interval(encodings=["x"])

Custom brush style:

>>> brush = fm.selection_interval(
...     mark=fm.SelectionMark(fill="#4287f5", fill_opacity=0.2, stroke_dash=[4, 2])
... )

selection_point

selection_point(*, fields: list[str] | None = None, encodings: list[str] | None = None, nearest: bool = False, toggle: str = 'event.shiftKey', on: str = 'click', clear: str = 'mouseout', resolve: Literal['global', 'union', 'intersect'] = 'global', name: str | None = None, bind: str | None = None) -> Selection

Create a point selection activated by clicking on marks.

A point selection highlights individual marks. Shift-click adds to the selection by default (toggle="event.shiftKey"). Use selection_single to disable toggle, or selection_multi to keep the shift-click default explicitly.

Parameters:

Name Type Description Default
fields list of str

Data fields to project the selection onto. When omitted the selection binds to all fields.

None
encodings list of str

Encoding channels to project onto (e.g. ["x", "color"]).

None
nearest bool

When True, clicking between marks selects the nearest one.

False
toggle str

JavaScript event expression controlling when clicking adds to the selection instead of replacing it. Pass "false" to disable toggling (see also selection_single).

"event.shiftKey"
on str

Event that triggers the selection (e.g. "mouseover").

"click"
clear str

Event that clears the selection.

"mouseout"
resolve ('global', 'union', 'intersect')

How to resolve this selection when the chart is faceted.

"global"
name str

Stable identifier for the selection. Auto-generated when omitted.

None
bind str or None

Optional bind target. "legend" wires legend-entry clicks to toggle the point selection (and thus any series linked to it via a conditional encoding). When None no bind is configured.

None

Returns:

Type Description
Selection

Immutable selection descriptor. Pass to Chart.add_selection() and use sel.when(...).otherwise(...) to build conditional encodings.

Examples:

Highlight selected marks by colour:

>>> import ferrum as fm
>>> sel = fm.selection_point()
>>> fm.Chart(df).mark_point().encode(
...     x=fm.X("x"), y=fm.Y("y"),
...     color=sel.when(fm.Color("category")).otherwise(fm.value("#cccccc")),
... ).add_selection(sel)

Nearest-mark selection on mouse-over:

>>> sel = fm.selection_point(nearest=True, on="mouseover", clear="mouseout")

Legend-toggle selection:

>>> sel = fm.selection_point(bind="legend")

value

value(v: Any) -> '_LiteralValue'

Wrap a literal value for use in conditional encodings.

Returns an opaque literal wrapper that can be passed as the if_selected or if_not argument of sel.when(...).otherwise(...) when a constant (rather than a field mapping) is needed.

Parameters:

Name Type Description Default
v str, int, or float

The constant to embed. Hex colour strings (e.g. "#cccccc") are interpreted as colours. Numbers are interpreted as opacity values.

required

Returns:

Type Description
_LiteralValue

Opaque wrapper consumed by ConditionalSpec.

Examples:

Grey-out unselected marks:

>>> import ferrum as fm
>>> sel = fm.selection_point()
>>> fm.Chart(df).mark_point().encode(
...     x=fm.X("x"), y=fm.Y("y"),
...     color=sel.when(fm.Color("category")).otherwise(fm.value("#cccccc")),
... ).add_selection(sel)

Fade unselected marks with low opacity (numeric branches resolve to opacity values, not colours, so assign to the opacity channel):

>>> opacity = fm.when(sel).then(1.0).otherwise(0.1)
>>> # or, equivalently, with explicit value(...) wrappers:
>>> opacity = sel.when(fm.value(1.0)).otherwise(fm.value(0.1))

when

when(parameter: Parameter) -> _When

Start a module-level conditional encoding builder.

A more explicit alternative to sel.when(enc).otherwise(enc) for cases where the conditional test is on a selection parameter and the branches are literal values (opacity, colour) rather than encoding channels.

Usage::

fm.when(sel).then(v_if).otherwise(v_else)

The parameter argument must be a Selection instance — the conditional test is "datum ∈ selection". Variable parameters (fm.param) drive value/domain/bind references, not the conditional predicate; passing one raises TypeError.

v_if and v_else may be plain numbers or fm.value(...) wrappers; they are wrapped via value() when not already a _LiteralValue. Hex colour strings are interpreted as colours at serialization time (in _resolve_encoding_value), not at this layer.

Parameters:

Name Type Description Default
parameter Selection

The selection whose active/inactive state drives the condition. Produced by selection_point() or selection_interval().

required

Returns:

Type Description
_When

Intermediate builder. Call .then(v_if).otherwise(v_else) to finalize.

Raises:

Type Description
TypeError

If parameter is not a Selection instance. Variable parameters from fm.param drive value/domain/bind references, not the conditional predicate.

Examples:

Fade unselected marks — assign the conditional to the opacity channel so the numeric branches resolve to opacity values (encode stamps the channel from its key and auto-registers sel):

>>> import ferrum as fm
>>> sel = fm.selection_point()
>>> chart = fm.Chart(df).mark_point().encode(
...     x=fm.X("x"), y=fm.Y("y"),
...     opacity=fm.when(sel).then(1.0).otherwise(0.2),
... )

Colour toggle on legend selection:

>>> sel = fm.selection_point(bind="legend")
>>> cond = fm.when(sel).then(fm.value("#1f77b4")).otherwise(fm.value("#cccccc"))