Skip to main content

Data adapters

functions@pond-ts/charts

fromTimeSeriessource

fromTimeSeries(series: TimeSeries<S>, column: string): ChartSeries

Build a ChartSeries from a pond TimeSeries by reading its columnar buffers directly — no per-event materialization. column names a numeric value column; the key column supplies the time axis (begin, in ms).

bandFromTimeSeriessource

bandFromTimeSeries(series: TimeSeries<S>, lower: string, upper: string): BandSeries

Build a BandSeries from a pond TimeSeries — two numeric columns for the lower/upper edges sharing the series' time axis. The edge columns are typically rollingByColumn percentiles (e.g. p25/p75); a sample with either edge missing reads as a gap in the fill.

barsFromTimeSeriessource

barsFromTimeSeries(series: TimeSeries<S>, column: string): BarSeries

Build a BarSeries from a pond TimeSeries — one bar per event, the key's [begin, end] as the x-span and column as the height.

Key-shape fallback (point-keyed series). The primary form is interval / timeRange-keyed, where each key already carries a [begin, end] span. A point-keyed (time) series has begin === end (zero width), so this derives a span from neighbour spacing: each bar is centred on its timestamp and reaches halfway to each neighbour (a Voronoi cell on the time axis). The first/last bars mirror their single adjacent gap so the row's end bars match their interior width. A lone point (length 1) has no neighbour, so it keeps zero width and falls back to the renderer's minWidth.

This makes a uniformly-sampled point series render as contiguous bars (the histogram look) without the caller pre-keying to intervals, while an interval-keyed series (e.g. an aggregate/window rollup) draws its true bucket spans. Detected by keyColumn().kind === 'time'.

boxFromTimeSeriessource

boxFromTimeSeries(series: TimeSeries<S>, columns: BoxColumns): BoxSeries

Build a BoxSeries from a pond TimeSeries. lower/upper (the whisker reach) are required; q1/q3 (the box body) and median (the centre line) are optional — omit them for a range-only box (a bid→ask segment). The quantile columns are typically rolling/aggregate percentiles; a key with any present quantile missing reads as a gap (the box draws nothing).

Key-shape aware, like ohlcFromTimeSeries. An interval / timeRange-keyed series uses the key's own [begin, end) as the box span; a point-keyed (time) series synthesizes the span from neighbour spacing (each box centred on its timestamp, halfway to each neighbour), so a raw percentile-per-timestamp feed renders as contiguous boxes instead of collapsing to the 1px floor.

ohlcFromTimeSeriessource

ohlcFromTimeSeries(series: TimeSeries<S>, columns: OhlcColumns): OhlcSeries

Build an OhlcSeries from a pond TimeSeries — four numeric price columns (open/high/low/close) plus the candle's horizontal slot.

Key-shape aware, like barsFromTimeSeries. An interval / timeRange-keyed series (an aggregate rollup — weekly / monthly bars) uses the key's own [begin, end) as the slot. A point-keyed (time) series — raw daily OHLCV — has begin === end (zero width), so the slot is derived from neighbour spacing (each candle centred on its timestamp, reaching halfway to each neighbour; see neighbourSpans). This is the ergonomic win over the interval-only boxFromTimeSeries: raw OHLC feeds straight in with no aggregate pass.

A key with any of the four prices missing reads as a gap (the candle draws nothing). Detected by keyColumn().kind === 'time'.

stacksFromGroupssource

stacksFromGroups(groups: ReadonlyMap<string, TimeSeries<S>>, column: string): StackedBarSeries

Build a StackedBarSeries from a Map of grouped series — one series per stack group. This is the natural reader for pond's grouped-aggregate output: series.partitionBy('host', { groups }).aggregate(Sequence.every('5m'), { n: 'count' }).toMap() yields a Map<host, TimeSeries>, one interval-keyed series per host. The stack order (groups, bottom → top) is the map's insertion order (stable when you pass partitionBy's { groups } option).

Aligned by bucket key, not by index. Each partition's aggregate spans only its own events' range, so the groups generally have different grids (host A might have buckets 0–8, host B buckets 3–9). This reader takes the union of every group's [begin, end) slots (ascending) and places each group's column value at the matching begin; a bucket a group is missing reads as a gap (NaN, contributing nothing to that stack). So the segments always line up on the real bucket, never on a positional accident. (Pass aggregate's { range } option if you want every group padded to one dense grid — the union is then that grid.) When two groups carry the same begin, the first group's end sets that slot's width — correct for the uniform-width buckets aggregate / pivotByGroup produce (all groups share the grid width), which is the intended input.

stacksFromColumnssource

stacksFromColumns(series: TimeSeries<S> | ValueSeries<VS>, columns: readonly string[]): StackedBarSeries

Build a StackedBarSeries from a wide series — one numeric column per stack group. This is the reader for pond's pivotByGroup output (long → wide reshape: each group value becomes its own column), or any series that is already wide (e.g. in / out traffic). columns names the segment columns bottom → top; a ValueSeries bins on its value axis (neighbour-spaced slots), a TimeSeries on its key (interval spans or neighbour-spaced points).

stacksFromBinssource

stacksFromBins(bins: readonly BinRecord[], columns: readonly string[], options?: StacksFromBinsOptions): StackedBarSeries

Build a StackedBarSeries from byColumn bin records — the array of { start, end, …aggregates } a value-band aggregation returns (series.byColumn('power', { width: 20 }, { seconds: { from: 'dt', using: 'sum' } })). columns names the aggregate field(s) to draw as segments (['seconds'] for a plain distribution; several for a stacked value-band histogram).

By default each bin keeps its real numeric [start, end] edges — a true value axis (power W, risk %). Pass { ordinal: true } for uniform unit slots ([i, i+1]) when the bins are categories whose numeric width shouldn't distort the layout (heart-rate zones); label them with <YAxis ticks>.

A missing / non-finite aggregate reads as a gap (NaN).

categoryStacksource

categoryStack(records: readonly CategoryDatum[]): StackedBarSeries

Build a StackedBarSeries (single group, G === 1) from an ordered list of { label, value } categories — one unit slot [i, i+1] per category, in order. This is the categorical row-read's geometry: the slots are ordinal indices (the bar's pixel span comes from the container's ScaleBand), and the labels become the axis's ordered category names (xCategories). A non-finite value reads as a gap (NaN). Reuses the shipped stacked geometry — no new draw path.

transposeRowsource

transposeRow(series: TimeSeries<S>, options?: TransposeRowOptions): CategoryDatum[]

The transpose reader (categorical-axis RFC, Phase 1 PR2): read one row of a wide TimeSeries across — its columns become the categories, that row's cells the values — for <BarChart categories={…}>. This is "columns on x": the schema's numeric columns (a pivotByGroup output's per-group columns, a vol term structure's per-expiry columns, …) laid out at one instant.

The row is picked the ordinary way (options.at, default the head row): series.last() / .first() / .at(index) / .nearest(time). So "which row" is just row selection — the live snapshot is the head row; a static report pins a row by index or time. (Binding the row to a scrubbing time cursor is a later phase.) Pass options.columns to bound / order the category set; omit it to take every numeric value column. An empty series (or a row past the ends) yields []; a missing / non-numeric cell reads as a gap (NaN).