Data adapters
functions@pond-ts/chartsfromTimeSeriessource
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).