import type { ColumnDataMap, ColumnData } from "../../data/view-reader"; import type { CategoricalDomain, CategoricalLevel } from "../../axis/categorical-axis"; export interface CategoryAxisResult { /** * Fully materialized hierarchical levels — labels and group runs are * pre-resolved from the view's `__ROW_PATH_N__` dictionaries (or * synthesized for non-string levels) so the chart can retain them * past the `with_typed_arrays` callback scope. Empty when `groupBy` * is empty. */ rowPaths: CategoricalLevel[]; /** * Rows that actually contribute a category (post-offset). */ numCategories: number; /** * Leading rows skipped; callers use this to rebase per-row indices. */ rowOffset: number; } export type AxisMode = { mode: "category"; } | { mode: "numeric"; numericType: "date" | "datetime" | "integer" | "float"; }; /** * Numeric category-axis state. Shared across bar / candlestick / heatmap * pipelines: when an axis is driven by exactly one non-string group_by / * split_by level, glyphs anchor at real data values via `categoryPositions` * and the chrome renders a numeric (date-aware) tick row. */ export interface NumericCategoryDomain { min: number; max: number; isDate: boolean; label: string; /** * Data-unit width of one category band, from min adjacent delta. */ bandWidth: number; } /** * Compute `categoryPositions` (per-row real data values) plus a * `NumericCategoryDomain` summarizing min/max/bandWidth for a numeric * row-path column. `bandWidth` falls back to the full domain when there * are <2 distinct positions. Pivot rows for a single group_by come ASC * by default, so a forward sweep for `minDelta` is sufficient. * * Returns `null` when the row-path column is missing or carries no * `values` array (e.g. dictionary-encoded string column). */ export declare function resolveNumericCategoryDomain(rpValues: ArrayLike | null | undefined, numCategories: number, rowOffset: number, label: string, isDate: boolean): { categoryPositions: Float64Array; numericCategoryDomain: NumericCategoryDomain; } | null; /** * Decide whether the categorical axis should render as a stringified * category axis or a true numeric axis. Numeric mode is only used when * there is exactly one `group_by` level AND that level is a non-string, * non-boolean numeric type. Boolean and any multi-level case → category. */ export declare function resolveAxisMode(groupBy: string[], groupByTypes: Record): AxisMode; /** * Synthesize a `(indices, dictionary)` pair from a non-string row-path * column so the rest of the categorical axis machinery (label * pre-resolution, run-length encoding) can run unchanged. The dictionary * uses `""` at index 0 as the rollup-row sentinel — this preserves the * existing skip-rollup loop's `s !== ""` check. */ export declare function synthesizeStringLevel(rp: ColumnData, numRows: number, levelType: string): { indices: Int32Array; dictionary: string[]; }; /** * Resolve the category axis for a categorical-X chart (bar, candlestick, * ohlc, …). Walks the `__ROW_PATH_N__` hierarchy columns, skips the * rollup rows at the top ("Total" parent aggregates), and returns fully * JS-owned level structures (precomputed labels + runs) plus the * trimmed category count. * * Non-string row-path columns (date / datetime / integer / float / * boolean group_by levels) are stringified into a synthetic dictionary * so the downstream label / run-length machinery is type-agnostic. * * When `groupByLen === 0`, there are no row-path columns and the * category axis falls back to the raw row index — callers infer that * from `rowPaths.length === 0`. */ export declare function resolveCategoryAxis(columns: ColumnDataMap, numRows: number, groupByLen: number, levelTypes?: string[]): CategoryAxisResult; export interface ValueCategoryColumn { /** * Source aggregate column name; used only for the axis label fallback. */ name: string; /** * Post-aggregation perspective type string from `chart._columnTypes` * (`"string"` is what triggers categorical mode). */ type: string; /** * The actual `ColumnData` from the view. May be undefined when the * caller couldn't resolve the column (treated as all-null). */ data: ColumnData | undefined; } export interface ValueCategoryDomain { /** * Single-level `CategoricalDomain` shared across all input columns. * `levels[0].labels` is the dictionary in slot order. */ domain: CategoricalDomain; /** * Per-column slot-index buffers. Length === `numCategories`. * Indexed in the same order as the input `columns` array. */ perColumnSlots: Int32Array[]; } /** * Build a single shared categorical domain across one or more aggregate * columns that land on the same axis side (primary or alt). Implements * the "all-or-nothing per axis side" rule: returns `null` (= caller stays * numeric) when any column is non-string; otherwise returns a single- * level domain with the dictionary built in first-seen row order plus * per-column slot indices the build pipeline writes into its pixel/slot * buffer. * * Null / invalid rows surface as a `"(null)"` slot that's lazily added * to the dictionary on first encounter — no reserved slot 0 when the * data has no missing values. */ export declare function resolveValueCategoryDomain(columns: ValueCategoryColumn[], numRows: number, rowOffset: number, axisLabel: string): ValueCategoryDomain | null;