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?, includeEmpty?, members?, as? })

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
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. Cells are half-open: [lower, upper). The last cell on each axis includes its upper endpoint, so every eligible row belongs to exactly one cell. Output rows are ordered from low to high y and 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?, includeEmpty?, members?, as? })

Use editBin2DData when only part of the current transform should change:

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. 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.

A dependent derived dataset currently blocks both complete reauthoring and partial editing with an explicit error; create a new logical ID when that dependency must remain.

Data overview · Source and derived data · Heatmaps · Action reference