/** * Histogram-specific `RelativeData` transform. Histogram data is * `number[][]` — each series is a flat list of bin counts. This * rewrites each count to its share of the series total (0–100), so * pairing with `createPercentFormatter` renders the y-axis as * percentages. * * Pass to ``. * * The denominator is the sum of |value| across the series so mixed-sign * inputs produce sane signed shares-of-magnitude. A series whose total * magnitude is zero (all-zero or empty input) is returned unchanged so * a stalled or empty data set doesn't show misleading 0% values. Inputs * whose shape isn't `number[][]` fall through untouched (same defensive * shape-check pattern as the default transform). */ export const toRelativeHistogramData = (input: unknown): unknown => { if (!Array.isArray(input)) return input return input.map((series: unknown): unknown => { if (!isFlatNumberArray(series)) return series const total = series.reduce((acc, v) => acc + Math.abs(v), 0) if (total <= 0) return series return series.map((v) => (v / total) * 100) }) } function isFlatNumberArray(v: unknown): v is number[] { if (!Array.isArray(v)) return false return v.every((item) => typeof item === 'number' && Number.isFinite(item)) }