contour generates level sets from a regular scalar grid. Import it from the optional spatial subpath; it is not included in the root or universal barrel.
import { contour } from '@tanstack/charts/spatial/contour'
const mark = contour(wind, {
width: 64,
height: 60,
value: (row) => Math.hypot(row.u, row.v),
thresholds: [2, 4, 6, 8, 10],
stroke: '#fff',
strokeWidth: 0.75,
})function contour<TDatum>(
source: Iterable<TDatum>,
options: ContourOptions<TDatum>,
): ChartMark<never, never, never>The mark contributes derived color values but no positional domains or ChartPoint interaction candidates.
| Option | Type | Default | Meaning |
|---|---|---|---|
| width | number | Required | Number of columns in the row-major grid |
| height | number | Required | Number of rows in the row-major grid |
| value | Channel<TDatum, number?> | Numeric identity | Scalar grid value |
| thresholds | number | Iterable<number> | Sturges | Approximate level count or exact scalar levels |
| smooth | boolean | true | Interpolate marching-squares crossings |
| color | Channel<ContourDatum<TDatum>, ChartKey?> | Level value | Derived value sent to the color scale |
| fill | VisualChannel<ContourDatum<TDatum>, string> | Resolved color | Contour fill |
| stroke | VisualChannel<ContourDatum<TDatum>, string> | None | Contour stroke |
| fillOpacity, strokeOpacity, and strokeWidth | number | Renderer default | Contour presentation |
| strokeDasharray | string | None | Contour stroke dash pattern |
| opacity | number | Renderer default | Whole-contour opacity |
| id | string | Layer-derived | Stable mark ID |
| motion | ChartMarkMotionOptions<never>['motion'] | None | Contour enter, update, and exit motion |
width and height must be positive integers, and the source length must be exactly width * height. A numeric threshold count must be a positive integer. Exact thresholds are copied and sorted without mutating the input iterable.
Source values use row-major order. The first width values form Cartesian row zero at the bottom of the plot; subsequent rows move upward. Null and nonfinite values remain missing cells in their original grid positions instead of shifting later samples.
Marching-squares topology depends only on the source grid, thresholds, and smooth, so the mark generates it eagerly when the definition is built. Ordinary rendering maps the resulting grid coordinates linearly into the final plot rectangle and clips them there. Resizing changes that projection without re-estimating topology or requiring positional scales.
Every rendered ContourDatum<TDatum> contains:
Presentation accessors receive this derived datum and the complete rendered contour array.
Each level is one structured scene area containing all disconnected polygons and holes. SVG, Canvas, React Native SVG, hit geometry, gradients, and clipping consume the same rings; the mark does not author SVG path strings or depend on d3-geo.
A level can contain several disconnected regions, and an aggregate centroid can fall outside all of them. The mark therefore does not manufacture a focus target or tooltip datum. Layer an interactive source mark only when the grid samples themselves should own focus and tooltips.