Recipes
Recipes: anatomy, keyboard behavior, state, and theming in Askr.
Example
import { createPlot } from '@askrjs/charts';
const Plot = createPlot<ProjectRow>();
<Plot.Root data={rows} rowKey="id" label="Revenue and target">
<Plot.Bar x="createdAt" y="revenue" fill="team" />
<Plot.Line x="createdAt" y="target" />
<Plot.Point x="createdAt" y="target" />
<Plot.Legend interactive />
</Plot.Root>Time series
A typical time series pairs Line (or Area) with a time/utc scale inferred from a Date field, often layering a movingAverage(field, { window }) trend line over raw Point markers. Set followLatest on Root when the series is live, and use actual Date instances in row data rather than transport strings so temporal inference and utc selection behave predictably.
Histogram
Bin a numeric or Date field with bin(field, { thresholds }) on Bar.x, pair it with count() on y, and the compiler handles bucket boundaries and default axes automatically. Adding fill and stack on a categorical field turns the same histogram into a stacked breakdown by category without changing the binning logic.
Stacked bars
Bar's stack prop takes the categorical series field directly — stack="outcome" — and normalize converts the result to percent stacks. For cases where the numeric channel itself needs composing first, the stack(input, options?) and normalize(input) expression helpers do the same accumulation with explicit offset (zero, diverging, expand) and order control.
Dashboard polling
For a plot driven by periodic fetches, pass data as a reactive () => readonly Row[] getter and update the underlying array with appendPlotRows or upsertPlotRows on each poll, trimming with trimPlotRows so the series doesn't grow forever. Combine that with followLatest and PlotApi.resumeLive() so a viewer who's paused to inspect a spike doesn't get pulled back to the live edge by the next poll.