Published-release documentation · release compatibility
Rectangular 2D Bins
createBin2DData groups two quantitative fields into a rectangular grid.
editBin2DData partially revises an existing logical grid owner. Both store
concrete cell bounds and counts as immutable datasets, so ordinary ranged
rectangles or other marks can consume the result without asking the renderer to
perform data transforms.
createBin2DData({ id, source?, x, y, bins?, extent?, assignment?, includeEmpty?, members?, as? })
Contextual fragment. Use an ES module with the imports, data, and prepared resource state described in this section. Resolve these names from setup in this fragment or section; alternatives branch from the same base.
const program = chart()
.createData({
id: "observations",
values: [
{ x: 0, y: 0 },
{ x: 1, y: 0 },
{ x: 2, y: 2 }
]
})
.createBin2DData({
id: "cells",
x: "x",
y: "y",
bins: { x: 2, y: 2 },
extent: { x: [0, 2], y: [0, 2] },
includeEmpty: true,
as: { count: "count" }
});
| Option | Type | Default |
|---|---|---|
id |
logical derived-dataset ID | required |
source |
existing dataset ID | current dataset; previous source on revision |
x, y |
quantitative field names | required |
bins |
positive integer or { x, y } |
{ x: 10, y: 10 } |
extent |
{ x?: [min, max], y?: [min, max] } |
eligible min/max per axis |
assignment |
"edges" or "step" |
"edges" |
includeEmpty |
boolean | false |
members |
boolean | false |
as |
partial output-field object | namespaced from id |
Each axis accepts at most 10,000 bins, and a grid accepts at most 1,000,000
cells in total. These limits are validated before any cell storage is
allocated, including when the transform is reached through createHeatmap or
editBin2DData.
Only rows with finite values for both fields are eligible. Default assignment: "edges"
compares each value with the actual stored edges: cells are half-open [lower, upper),
and the last cell includes its upper endpoint. This default is omitted from stored
provenance, preserving existing snapshots.
Explicit assignment: "step" instead computes the logical uniform index
floor(1e-14 + (value - min) / step) on each axis, then clamps it to the valid
index range. The fixed index increment is part of this policy, not a configurable
tolerance. step = (max - min) / bins; overflowing subtraction uses
max / bins - min / bins, and an overflowing value difference uses
value / step - min / step. A one-bin axis assigns index zero; the final upper
endpoint always belongs to the last bin. Explicit extents are still validated
before assignment, so clamping cannot accept out-of-range rows.
Both policies generate identical stored edges. Floating-point rounding can place
a value just below a stored edge while step assigns it to the logical upper
cell. For extent [-5, 5] with 50 bins, input 0.6 falls below the stored edge
0.6000000000000005 under edges, but enters the upper cell under step.
A value 0.6 - 1e-12 remains below it. Both policies assign every eligible row
once and order output from low to high y, then low to high x.
The stored transform includes the resolved axis extents and edge arrays. An explicit extent must contain every eligible value; the action throws rather than silently dropping rows. An automatic axis with no positive span also throws instead of guessing a display range.
Every resolved edge is a finite number and edges are strictly increasing. Edge
generation supports extents whose direct subtraction overflows, such as a grid
from -1e308 to 1e308. If the requested number of distinct bins cannot be
represented within an extent, the action throws RangeError; it never silently
returns fewer bins.
The default output fields are __<id>_x0, __<id>_x1, __<id>_y0,
__<id>_y1, and __<id>_count. Pass as to give downstream encodings shorter
names. With members: true, each cell also stores source row indexes. It never
copies complete source row objects into every cell.
Revisions
Calling createBin2DData again with the same logical id remains supported as
a complete reauthoring operation. Supply the complete transform decisions for
that intent. It creates a new immutable revision, rebinds direct visual
consumers, rematerializes their scales, marks, and guides, and releases the
unreferenced previous revision.
editBin2DData
editBin2DData({ target?, source?, x?, y?, bins?, extent?, assignment?, includeEmpty?, members?, as?, dependents? })
Use editBin2DData when only part of the current transform should change:
Contextual fragment. Use an ES module with the imports, data, and prepared resource state described in this section. Caller-provided receivers:
program. Resource selectors used here:target: "cells". Resolve these names from setup in this fragment or section; alternatives branch from the same base.
const revised = program.editBin2DData({
target: "cells",
bins: { x: 20, y: 10 },
includeEmpty: false
});
target names the logical owner, not a generated revision dataset. It can be
omitted when the current dataset identifies an owner or exactly one 2D-bin owner
exists. Multiple owners without a current match are ambiguous and require
target.
Every omitted top-level option is preserved from the current requested
provenance. assignment: "edges" restores the default and removes stored step
provenance; an unchanged policy is a no-op and is rejected. Supplying extent replaces the complete extent decision and an
omitted axis inside that object returns to automatic extent. Supplying as
requires the complete x0, x1, y0, y1, and count output map, plus
members when member indexes are enabled. When as is omitted, enabling
members adds __<logical-owner>_members; disabling members removes only that
output.
An edit must contain at least one transform or source option and must produce an actual change. The complete source, transform, and every direct visual consumer are validated before the returned action records its first child transition. Successful calls create a deterministic immutable revision, explicitly rebind each direct layer, rematerialize affected scales, marks, and guides, then release the unreferenced prior revision. Earlier programs and caller-owned options remain unchanged.
dependents defaults to "reject". With that default, an edit stops before
changing the program when another derived dataset reads the current grid.
Pass dependents: "recompute" to revise the complete downstream dependency
closure in topological order. Every affected logical owner receives one new
deterministic revision, direct visual consumers move to those revisions, and
obsolete revisions are released only after the whole speculative result passes
validation. Cycles, unsupported internal transforms, and unsafe output-field
renames reject atomically.
Related
Data overview · Source and derived data · Heatmaps · Action reference
Documentation provenance
293 actions · sha256:e755591a2e5f5e2b494867583876e28020a478c5220b77bdc6ad469a6224891d