UNPKG

@tanstack/charts

Version:

A chart grammar for TypeScript and JavaScript. Marks consume your data directly, channels describe visual encodings, and the engine compiles them into a renderer-neutral keyed scene. TanStack's compact scales cover common numeric and categorical mappings.

154 lines (122 loc) 4.35 kB
--- title: Transforms and Reactivity description: Derive typed rows once and memoize them where the data is owned. --- TanStack transforms are eager, deterministic data utilities. Their results can feed a chart, table, export, test, or another transform. ```text source rows data transforms mark channels mark layout ``` Use a channel accessor for a one-row calculation, a data transform for reusable cross-row work, and `layout: stack()` or `layout: group()` when geometry belongs only to one mark. ## Hoist the calculation ```ts const daily = groupBy(orders, { by: { region: 'region', day: (datum) => utcDay.floor(datum.createdAt), }, outputs: { revenue: { value: 'amount', reduce: 'sum' }, orders: { reduce: 'count' }, averageOrder: { value: 'amount', reduce: 'mean' }, }, }) const trends = rollingWindow(daily, { by: 'region', orderBy: 'day', size: 28, partial: false, outputs: { revenue28d: { value: 'revenue', reduce: 'sum' }, averageOrder28d: { value: 'averageOrder', reduce: 'mean' }, }, }) lineY(trends, { x: 'day', y: 'revenue28d', color: 'region' }) ``` Unlike a mark-options transform, both intermediate datasets are normal typed rows. Group fields are named and row transforms remain flat. ## Compose structural and analytic transforms Keep each ownership decision visible where derived data is created: ```ts import { normalize, select } from '@tanstack/charts' import { fold } from '@tanstack/charts/transform/fold' const fields = ['latency', 'throughput'] as const const folded = fold(services, { fields, as: { key: 'metric', value: 'measurement' }, }) const normalized = normalize(folded, { by: 'metric', value: 'measurement', basis: 'extent', as: 'relativeMeasurement', }) const firstService = select(normalized, { by: 'metric', select: 'first', }) ``` `fold` owns wide-to-long structure. `normalize` owns the cross-row numeric comparison. `select` returns chosen rows unchanged. Metric direction, chosen profiles, and display labels remain explicit application semantics. ## Use callbacks and escape hatches Field names and object-bag callbacks are interchangeable: ```ts const summaries = groupBy(rows, { by: { region: 'region', profitable: ({ datum }) => datum.margin > 0 }, outputs: { p90: { value: 'latency', reduce: quantile(0.9) }, custom: { reduce: ({ data, group }) => domainCalculation(data, group), }, }, }) ``` For transforms outside the built-ins, use an ordinary function: ```ts const active = rows.filter((row) => row.active) const enriched = active.map(enrichRow) const summaries = groupBy(enriched, options) ``` This is the escape hatch and the composition model. There is no pipeline protocol to learn. ## Memoize at the owner ```tsx const histogram = useMemo( () => binX(observations, { value: 'latency', thresholds: 24 }), [observations], ) ``` Use `computed`, `createMemo`, `$derived`, or the equivalent application primitive. TanStack Charts does not add a cache or reactive graph. Memoize the complete pipeline when its source and options share a lifecycle. Re-run it when the source rows, folded field tuple, metric direction, or selection policy changes. Do not mutate a transform result and expect a chart runtime to discover the change. Transform option errors are synchronous. Validate dynamic field lists before calling `fold`; duplicate fields and invalid output names fail with a `fold:` error instead of producing ambiguous rows. Every transform records direct lineage to its immediate input. For example, `normalized[0].source[0]` is a folded row, while that row's `source[0]` is the original service record. Preserve this chain when a tooltip or drill-down needs the raw observation. ## Keep geometry separate Color can infer stack series for stack-capable marks. Grouping remains an explicit geometric choice: ```ts barY(rows, { x: 'quarter', y: 'revenue', color: 'product' }) barY(rows, { x: 'quarter', y: 'revenue', color: 'product', layout: group(), }) ``` Use `stackRowsX` or `stackRowsY` when stack endpoints must be reused outside that mark. Granular imports such as `@tanstack/charts/transform/fold`, `@tanstack/charts/transform/group`, and `@tanstack/charts/transform/rolling-window` keep unrelated transform families out of bundle-sensitive code.