/** * Categories that stay put while a quantity is re-divided between them at each * step — an alluvial diagram. * * The same weighted flow a sankey carries, drawn without a left-to-right * budget, so it needs nothing declared beyond which of the two it is: the * nodes, the links and their magnitudes are already in the drawing. */ declare interface AlluvialDeclaration extends DeclarationBase { /** `TraceType.ALLUVIAL` — the string `'alluvial'`. */ type: TraceType.ALLUVIAL; } /** * Canonical axis configuration. Every axis (x, y, z) must be specified as an * object of this shape. The `label` is optional and falls back to built-in * defaults ('X', 'Y', 'Level') when omitted. * * Grid navigation properties (`min`, `max`, `tickStep`) are currently consumed * by scatter-plot traces only; they are silently ignored by other trace types. * * Formatting configuration lives inline as `format` on each axis, allowing * different formatters per axis without a separate top-level block. * * @example * // Simple label * axes: { x: { label: "Date" }, y: { label: "Price" } } * * @example * // With grid navigation (scatter) * axes: { * x: { label: "Sepal Length", min: 4.3, max: 7.9, tickStep: 0.7 }, * y: { label: "Sepal Width", min: 2, max: 4.4, tickStep: 0.5 } * } * * @example * // With formatting * axes: { * x: { label: "Date" }, * y: { label: "Price", format: { type: "currency", decimals: 2 } } * } */ declare interface AxisConfig { /** Axis label displayed in text descriptions. Defaults applied when absent. */ label?: string; /** Minimum value for grid navigation (scatter only). */ min?: number; /** Maximum value for grid navigation (scatter only). */ max?: number; /** Step size for grid navigation (scatter only). */ tickStep?: number; /** Optional per-axis value formatting applied in text descriptions. */ format?: AxisFormat; } /** * Configuration for formatting values on an axis. * * Two ways to specify formatting: * 1. `function` - Function body string (for custom logic) * 2. `type` - Format type specifier (for common patterns) * * @example * // Using function string * { "function": "return `$${Number(value).toFixed(2)}`" } * * @example * // Using type specifier * { "type": "currency", "decimals": 2 } */ declare interface AxisFormat { /** * Function body string for custom formatting. * The function receives `value` as parameter and must return a string. * * @example * // Currency formatting * { "function": "return `$${Number(value).toFixed(2)}`" } * * @example * // Date formatting * { "function": "return new Date(value).toLocaleDateString('en-US')" } */ function?: string; /** * Format type specifier for common formatting patterns. * Use with `decimals`, `currency`, `locale`, `dateOptions` for customization. * * @example * { "type": "currency", "currency": "USD", "decimals": 2 } * { "type": "percent", "decimals": 1 } * { "type": "date", "dateOptions": { "month": "short", "day": "numeric" } } */ type?: FormatType; /** * Number of decimal places for numeric formatters. * Used with: currency, percent, fixed, number, scientific * @default varies by type */ decimals?: number; /** * ISO 4217 currency code for currency formatter. * @default 'USD' */ currency?: string; /** * BCP 47 locale string for locale-aware formatters. * Used with: currency, number, date * @default 'en-US' */ locale?: string; /** * Options for Intl.DateTimeFormat when using date type. * * @example * { "month": "short", "day": "numeric" } // "Jan 15" * { "year": "numeric", "month": "long" } // "January 2024" */ dateOptions?: Intl.DateTimeFormatOptions; } /** * Data point for bar charts with x and y coordinates. */ declare interface BarPoint { x: string | number; y: number | string; } /** * A letter-value plot: the box plot's five-number summary generalised to a * variable-depth ladder of quantiles. * * The ladder is precomputed outside the charting library, so the declaration * names the columns it was computed into. A box plot's summary is this shape * with exactly one rung, and that fixed depth is why a box plot cannot express * a boxen. */ declare interface BoxenDeclaration extends DeclarationBase { /** `TraceType.BOXEN` — the string `'boxen'`. */ type: TraceType.BOXEN; /** * Field holding the category this boxen summarises. Maps to `BoxenPoint.z`. * * @default 'x' */ x?: FieldRef; /** * Field holding the middle of the distribution. Maps to * `BoxenPoint.median`. * * @default 'median', falling back to `q2`, `mid` or `y` */ median?: FieldRef; /** * Field holding the rungs — the ladder of `{ p, lo, hi }` quantile pairs. * Maps to `BoxenPoint.levels`. * * The trace sorts them outward from the median rather than trusting the * order they arrive in. * * This names the *column*; the rungs inside it are not declared field by * field. A rung is read as a row of its own, so its three numbers answer to * the same spread of spellings a top-level field does: `p` also to `prob`, * `probability` or `depth`; `lo` to `lower`, `low`, `min` or `y0`; `hi` to * `upper`, `high`, `max` or `y1`. * * @default 'levels', falling back to `letterValues`, `letter_values`, * `quantiles` or `ladder` */ levels?: FieldRef; /** Field holding the values below the deepest rung. Maps to `BoxenPoint.lowerOutliers`. */ lowerOutliers?: FieldRef; /** Field holding the values above the deepest rung. Maps to `BoxenPoint.upperOutliers`. */ upperOutliers?: FieldRef; /** * Which axis the distributions run along. Maps to `MaidrLayer.orientation`. * * The `Orientation` values, which are **`'horz'` and `'vert'`** — not the * words they abbreviate, exactly as {@link ErrorBarDeclaration.orientation}. */ orientation?: Orientation; } /** * One boxen (letter-value) plot: a median, a ladder of quantile pairs around * it, and whatever fell outside the deepest rung. * * A box plot's five-number summary is this shape with exactly one rung, and * that fixed depth is the reason it cannot express a boxen: the point of a * letter-value plot is that a large sample gets *more* rungs, so the tails * stay legible instead of collapsing into a whisker and a scatter of dots. */ declare interface BoxenPoint { /** The category this boxen summarises. */ z: string; /** The middle of the distribution. */ median: number; /** * The rungs, which the trace sorts outward from the median rather than * trusting the order they arrive in -- a producer emitting them * inward-first would otherwise be navigated backwards. */ levels: LetterValueLevel[]; /** Values beyond the deepest rung, below it and above it. */ lowerOutliers?: number[]; upperOutliers?: number[]; } /** * Data point for boxplots containing quartiles, min/max, and outliers. */ declare interface BoxPoint { z: string; lowerOutliers: number[]; min: number; q1: number; q2: number; q3: number; max: number; upperOutliers: number[]; /** Mean value for violin plots when mean display is enabled. */ mean?: number; } /** * DOM selectors for boxplot visual elements. */ declare interface BoxSelector { lowerOutliers: string[]; min: string; iq: string; q2: string; max: string; upperOutliers: string[]; /** CSS selector for mean marker element in violin plots. */ mean?: string; /** Optional direct CSS selector for Q1 element (bypasses iq edge derivation). */ q1?: string; /** Optional direct CSS selector for Q3 element (bypasses iq edge derivation). */ q3?: string; } /** * Data point for candlestick charts with OHLC values, volume, and trend information. */ declare interface CandlestickPoint { value: string; /** * The period's opening price, where the chart records one. * * Optional because a real and common price chart does not have it. * Highcharts registers three price series and only two carry an open: * `candlestick` and `ohlc` do, and `hlc` draws the same high, low and * close without it. Required, the field forced that chart to be declined * outright -- announcing it as an error bar would have been exact in the * data and wrong in the name, which is the trade #1140 rules out. * * The same shape `ErrorBarPoint.y` took in #1047 for the band that draws * only bounds: absent means the chart never had one, not that it is zero. * * Its absence removes more than a row. The **body** is what an open makes * -- so a candle without one has no bullish/bearish/neutral trend, no * shape, and no pattern with its neighbours, because every one of those is * a statement about the body. {@link Candlestick} drops the section, the * trend and all of the pattern asides together rather than announcing any * of them empty. */ open?: number; high: number; low: number; close: number; /** Optional volume data. May be undefined when source (e.g., Google Charts) doesn't provide it. */ volume?: number; /** * Which way the body ran, absent on a candle with no {@link * CandlestickPoint.open} to measure it against. */ trend?: CandlestickTrend; volatility: number; } /** * DOM selectors for candlestick chart visual elements. */ declare interface CandlestickSelector { body: string | string[]; wickHigh?: string | string[]; wickLow?: string | string[]; wick?: string | string[]; open?: string | string[]; close?: string | string[]; } /** * Represents the trend direction for candlestick data points. * Used across the application for audio palette selection and data representation. */ declare type CandlestickTrend = 'Bull' | 'Bear' | 'Neutral'; /** * Identifies a specific data element in a Chart.js chart. */ declare interface ChartJsActiveElement { datasetIndex: number; index: number; } /** * Minimal representation of a Chart.js chart instance. */ export declare interface ChartJsChart { /** * Whether a dataset is drawn. `chartjs-chart-pcp` needs it because a hidden * dataset there is a hidden *axis*: Chart.js lays out no scale for it, so * it is not a column of the drawn chart at all. */ isDatasetVisible?: (index: number) => boolean; readonly canvas: HTMLCanvasElement; readonly data: ChartJsData; readonly options: ChartJsOptions; readonly config: { readonly type: string; }; /** Runtime scale instances keyed by scale id, laid out with pixel geometry. */ readonly scales?: Record; getDatasetMeta: (datasetIndex: number) => ChartJsDatasetMeta; setActiveElements: (elements: ChartJsActiveElement[]) => void; tooltip?: { setActiveElements: (elements: ChartJsActiveElement[], eventPosition: { x: number; y: number; }) => void; }; update: (mode?: string) => void; } /** * Chart.js data configuration. */ declare interface ChartJsData { labels?: (string | number)[]; datasets: ChartJsDataset[]; } /** * A single dataset in a Chart.js chart. */ declare interface ChartJsDataset { label?: string; data: ChartJsDataValue[]; type?: string; stack?: string; /** Id of the x scale this dataset is plotted against (defaults to `'x'`). */ xAxisID?: string; /** Id of the y scale this dataset is plotted against (defaults to `'y'`). */ yAxisID?: string; backgroundColor?: string | string[]; borderColor?: string | string[]; /** * Whether a line dataset joins its points. `false` draws the markers alone, * which is Chart.js's own way of writing a dot plot. */ showLine?: boolean; /** * Step interpolation for a line dataset. `'before'` (and the legacy `true`) * hold the current value until the next x and jump there, `'after'` jumps at * the current x and holds the new value across, `'middle'` jumps midway. * `false` or absent draws an ordinary interpolated line. */ stepped?: boolean | 'before' | 'after' | 'middle'; /** * Whether a line dataset is filled to a boundary, making it an area band. * * Chart.js accepts a boundary name (`'origin'`, `'start'`, `'end'`), a * dataset index to fill to (absolute `2`, or relative `'+1'` / `'-1'`), the * bare `true` for the origin, `false` for no fill, or an object — either * `{ target }` naming any of the above, or `{ value }` filling to a constant * on the value axis. Every one of those except `false` draws a band. */ fill?: boolean | number | string | { target?: boolean | number | string; value?: number; }; /** * What this dataset *means*, when the drawing cannot say. * * Chart.js has no reserved slot for third-party metadata, but it passes * dataset properties it does not know through untouched — the same mechanism * a survival curve's `censored` datum rides on ({@link ChartJsPointValue}) — * so the co-located `maidr` block is written straight onto the dataset: * * ```js * datasets: [{ * label: 'chr1', * data: [{ x: 1e6, y: 8.2, snp: 'rs1234' }], * maidr: { type: 'manhattan', label: 'snp', significance: 7.3 }, * }] * ``` * * It wins over `plugins.maidr.traceType`, which stays the chart-wide * shorthand for a figure drawn as one dataset. A block whose `type` names * nothing, or whose keys the declared type does not accept, is reported and * the chart is read as if it carried none. */ maidr?: MaidrTraceDeclaration; /** * The `chartjs-chart-treemap` source: an array of numbers, an array of rows, * or an object. After `chart.update()` the plugin has replaced `data` with * one {@link ChartJsTreemapValue} per drawn rectangle, so this is the * caller's input rather than what is read. */ tree?: unknown; /** * The fields the treemap groups by, outermost first — e.g. * `['continent', 'country']`. Absent for a flat tree, which draws one * unnamed rectangle per entry. */ groups?: string[]; /** Which field of a row carries the value the rectangles are sized by. */ key?: string; /** * The links of a `chartjs-chart-graph` dataset, when its author declared * them rather than leaving the plugin to derive them from `parent`. */ edges?: ChartJsGraphEdge[]; /** * `chartjs-chart-sankey`'s display names, keyed by node key — e.g. * `{ a: 'Apple' }`. A key with no entry is announced as itself. */ labels?: Record; } /** * Metadata for a dataset (returned by `chart.getDatasetMeta()`). */ declare interface ChartJsDatasetMeta { data: ChartJsMetaElement[]; type: string; /** * The scale a dataset's values are measured against. * * `chartjs-chart-pcp` is why this is read: its controller gives every * dataset its own axis and assigns it here, so a parallel coordinates * chart's axes live on the metas rather than in `chart.scales` -- which * holds only the one `pcp` category scale (#1184). */ vScale?: { id?: string; options?: { title?: { text?: string; display?: boolean; }; }; }; /** * What Chart.js parsed each of the dataset's values into. * * The distribution controllers are the ones that need it. A boxplot or a * violin accepts either a raw array of samples or a pre-computed summary, * and only this is the same shape for both -- the plugin does the * quartile and density work here, so reading `dataset.data` sees the raw * samples of the first form and nothing usable (#1049). */ _parsed?: ChartJsParsedValue[]; /** * The links a `chartjs-chart-graph` controller drew, both ends resolved to * the element that draws that node. * * The one uniform source: measured, this is filled for all three * controllers and whether the author declared `edges` or left the plugin to * derive them from `parent`. The ends are **elements**, so a reader pairs * them back to node positions by identity against {@link data}. */ edges?: { source: ChartJsMetaElement; target: ChartJsMetaElement; }[]; } /** * Union of data value shapes found in Chart.js datasets. * Covers native chart types and popular plugins (boxplot, financial, matrix). */ declare type ChartJsDataValue = number | null /** * A floating bar: `[start, end]` rather than a magnitude from the * baseline. Chart.js draws gantt lanes, range bars and waterfall steps * this way. */ | [ChartJsRangeBound, ChartJsRangeBound] | ChartJsPointValue | { x: number | string; o: number; h: number; l: number; c: number; } | { min: number; q1: number; median: number; q3: number; max: number; outliers?: number[]; } | { x: string | number; y: string | number; v: number; } /** * A rectangle the treemap plugin laid out. It replaces the caller's * `tree` in `dataset.data` during `chart.update()`, so this union has to * admit it for the dataset to be read at all. */ | ChartJsTreemapValue /** One weighted flow of a sankey dataset. */ | ChartJsSankeyValue /** One region of a choropleth, or one bubble of a bubble map. */ | ChartJsGeoValue /** One node of a tree, dendrogram or force-directed graph. */ | ChartJsGraphValue; /** * Result of extracting a Chart.js chart, pairing the MAIDR schema with the * bookkeeping the plugin needs to route navigation back into the chart. */ export declare interface ChartJsExtraction { /** The MAIDR data object, ready to be passed to ``. */ maidr: Maidr; /** * Figure-unique layer id → original Chart.js dataset indices backing that * layer, in MAIDR row order. For axis-stacked panels each subplot only sees * a partition of `chart.data.datasets`, so MAIDR row indices no longer equal * Chart.js dataset indices — this map restores that correspondence. */ layerDatasetIndices: Map; } /** * One row of a `chartjs-chart-geo` dataset — a choropleth region, or a bubble * on a bubble map. * * The two controllers take different rows and the fields say which: a * choropleth shades a GeoJSON `feature` and may declare a `center` for it, * while a bubble map carries its own position. Measured on * `chartjs-chart-geo@4` against a running chart, the bubble map's parse reads * `longitude ?? x` and `latitude ?? y`, so both spellings are the caller's * degrees rather than pixels. * * The value itself is deliberately absent: its field name is whatever * `scales.color.property` / `scales.size.property` names, defaulting to * `'value'`, so it is read from {@link ChartJsParsedValue.r} where the parse * has already resolved it. */ declare interface ChartJsGeoValue { /** The GeoJSON feature a choropleth row shades. */ feature?: { properties?: Record; }; /** * A choropleth row's centroid, in degrees, when its author declared one. * * The only geographic position a choropleth carries. The drawn element's * `x`/`y` are pixels on the canvas and its `getCenterPoint()` the same, so * a row without this has no centroid to emit. */ center?: { longitude: number; latitude: number; }; /** A bubble map row's longitude, degrees east. */ longitude?: number; /** A bubble map row's latitude, degrees north. */ latitude?: number; /** The author's own columns, whichever of them carries the value. */ [column: string]: unknown; } /** * One declared link of a `chartjs-chart-graph` dataset. * * Both ends by index into `dataset.data`, or by a key the plugin resolves. * Read through the metadata rather than from here, because the plugin * derives* this list from the nodes' `parent` when it is absent and both * forms arrive resolved there. */ declare interface ChartJsGraphEdge { source: number | string; target: number | string; } /** * One node of a `chartjs-chart-graph` dataset. * * All three of the plugin's controllers — `tree`, `dendrogram` and * `forceDirectedGraph` — take the same flat node list, and a node names its * parent by **position in that list** rather than by name. The field is not * configurable: measured on `chartjs-chart-graph@4`, `IGraphDataPoint` * declares `parent` and nothing else. * * A root has none. A `forceDirectedGraph` given an explicit * {@link ChartJsDataset.edges} carries none on any node, the edges being the * graph instead. */ declare interface ChartJsGraphValue { /** Which node is this one's parent, by index. */ parent?: number; /** The author's own columns — a node's name among them. */ [column: string]: unknown; } /** * One sample of a violin's kernel density estimate, as the boxplot plugin * computes it: the value on the measured axis and the density there. */ declare interface ChartJsKdeCoord { v: number; estimate: number; } /** * A visual element from dataset metadata, providing pixel coordinates. */ declare interface ChartJsMetaElement { x: number; y: number; } /** * Chart.js options object. */ declare interface ChartJsOptions { indexAxis?: 'x' | 'y'; scales?: Record; plugins?: Record; /** Chart-wide `showLine`; a dataset's own setting wins over it. */ showLine?: boolean; /** * How much of the circle an arc chart sweeps, in degrees. Less than the full * 360 is what turns a doughnut into a dial. */ circumference?: number; /** Where the sweep starts, in degrees clockwise from the top. */ rotation?: number; /** Chart-wide element defaults; a dataset's own setting wins over these. */ elements?: { line?: { stepped?: ChartJsDataset['stepped']; fill?: ChartJsDataset['fill']; }; }; } /** * What Chart.js parsed one dataset value into. * * Every field is optional because the controllers disagree about which they * produce: a plain bar parses to `{x, y}`, while the boxplot plugin adds the * five-number summary and a violin adds `coords` on top of it. * * `min`/`max` are the **data** extremes and `whiskerMin`/`whiskerMax` the ends * the chart draws its whiskers to; on a sample with an outlier the two differ, * and it is the whiskers a box plot shows (#1049). */ declare interface ChartJsParsedValue { x?: number; y?: number; /** * The value a `chartjs-chart-geo` row is drawn by — the shade of a * choropleth region, the radius of a bubble on a bubble map. * * Both controllers parse onto `r` because both hand their value to a legend * scale (`color` / `size`) whose axis is `r`. It is read from here rather * than from `dataset.data` because the field's *name* is configurable — * `scales.color.property` defaults to `'value'` but an author may point it * at `rate` or `density` — and the parse has already applied it. * * `null` is a region the chart draws with no value, which the colour scale * paints with `options.missing` rather than a shade. */ r?: number | null; min?: number; max?: number; q1?: number; median?: number; q3?: number; mean?: number; whiskerMin?: number; whiskerMax?: number; outliers?: number[]; items?: number[]; /** A violin's density curve; absent on a boxplot. */ coords?: ChartJsKdeCoord[]; /** * The interval bounds `chartjs-chart-error-bars` parses onto a datum. * * Whichever axis carries the measurement carries the bounds: a vertical * chart parses to `yMin`/`yMax`, and `indexAxis: 'y'` moves them to * `xMin`/`xMax` along with the value itself. That is why the reading comes * from here rather than from `dataset.data`, where working out which axis * is which would have to be done again. * * An array is the plugin's nested-interval form -- a 95% inside a 99%, say. * `yMinMin`/`yMaxMax` are then the outermost pair, and are scalars whether * or not the bound is an array. * * `null` is a datum written as a plain number, which draws a bar with no * whiskers; an object datum with no bounds omits the keys entirely. Both * mean "no interval", which is why the test is `!= null` (#1176). */ xMin?: number | number[] | null; xMax?: number | number[] | null; xMinMin?: number; xMaxMax?: number; yMin?: number | number[] | null; yMax?: number | number[] | null; yMinMin?: number; yMaxMax?: number; } /** * Chart.js Plugin interface (subset used by MAIDR). */ export declare interface ChartJsPlugin { id: string; afterInit?: (chart: ChartJsChart, args: unknown, options: unknown) => void; afterUpdate?: (chart: ChartJsChart, args: unknown, options: unknown) => void; resize?: (chart: ChartJsChart, args: { size: { width: number; height: number; }; }, options: unknown) => void; beforeDestroy?: (chart: ChartJsChart, args: unknown, options: unknown) => void; } /** * A point-shaped datum: a scatter or bubble point, a line vertex on a * continuum, one time of a survival curve. * * The three optional members after `r` are not Chart.js's. Chart.js passes * unknown properties on a datum through untouched, which is how a page carries * a fact its config has no field for — and a Kaplan-Meier curve has two of * those, the censoring mark and the confidence band, neither of which is a * position the chart draws. They are named here rather than read off an index * signature so this stays a statement about what the adapter looks for. */ declare interface ChartJsPointValue { x: number; y: number; /** A bubble's radius: a third encoded variable. */ r?: number; /** A subject left the study here without the event happening. */ censored?: boolean; /** Lower bound of the confidence band at this point. */ yMin?: number; /** Upper bound of the confidence band at this point. */ yMax?: number; /** * Whatever else the author's own row carries. * * The three members above are the facts this adapter looks for under a fixed * name. A volcano's gene and a Manhattan's chromosome are the same kind of * rider, but their column is the author's to name — the co-located `maidr` * block says which it is — so they cannot be listed, and a datum written in * TypeScript would otherwise be rejected for carrying the very column the * declaration points at. */ [column: string]: unknown; } /** * One end of a floating bar. * * A number on a linear scale; a `Date` when the bar is drawn against a time * scale, which is how Chart.js's own gantt and range-bar recipes write them. * ISO date *strings* are also accepted by Chart.js there and are deliberately * not read here — parsing one means guessing a calendar for a value that may * equally be a category label. */ declare type ChartJsRangeBound = number | Date; /** * A laid-out runtime scale instance (from `chart.scales`), exposing the pixel * band it occupies. Used to order axis-stacked panels by visual position. */ declare interface ChartJsRuntimeScale { axis?: 'x' | 'y' | 'r'; /** Resolved edge the scale was laid out against. */ position?: string; top: number; bottom: number; left: number; right: number; } /** * One flow of a `chartjs-chart-sankey` dataset. * * Unlike the treemap plugin, the sankey controller leaves `dataset.data` * exactly as the caller wrote it — measured, the `{from, to, flow}` rows come * back verbatim after `chart.update()`. So the reading is the rows, and the * nodes the controller derives are never read: MAIDR derives its own from the * same edges, and a second list would be a second source of truth. * * A row with no `flow` is not a case to handle — the plugin itself throws * laying it out, before MAIDR sees the chart. Zero and negative flows draw * fine and are read. */ declare interface ChartJsSankeyValue { /** The node the flow leaves. */ from: string | number; /** The node it arrives at. */ to: string | number; /** How much flows. */ flow: number; } /** * A Chart.js scale (axis) configuration. */ declare interface ChartJsScale { title?: { text?: string; display?: boolean; }; type?: string; stacked?: boolean; /** * Whether the scale runs the other way (largest value at the origin end). * A rank axis is the case that matters here: a bump chart reverses y so * rank 1 sits at the top. * * Chart.js resolves a controller's own default back into `chart.options`, * so this is populated even when the author never wrote it — which is how * a matrix chart's y scale reads `true` off an otherwise bare config. */ reverse?: boolean; /** * A category scale's domain, in the order it is drawn along the axis * (before {@link ChartJsScale.reverse} is applied). */ labels?: (string | number)[]; /** Time-scale options; `unit` names what one step of the axis measures. */ time?: { unit?: string; }; /** Which axis this scale belongs to; defaults from the scale id's first letter. */ axis?: 'x' | 'y'; /** * Which chart edge the scale is placed against. Chart.js also accepts * dynamic positions (`'center'` or an `{ [scaleId]: value }` object), hence * the loose type; only the static edge strings participate in axis stacking. */ position?: string | Record; /** * Axis-stacking group name (Chart.js >= 3.7). Scales of the same axis kind * sharing a `stack` are laid out in separate, non-overlapping bands — the * native Chart.js way to express stacked panels within one canvas. */ stack?: string; /** Relative size of this scale's band within its axis stack. */ stackWeight?: number; } /** * One drawn rectangle of a `chartjs-chart-treemap` dataset. * * The plugin replaces `dataset.data` with these during `chart.update()`, one * per rectangle it laid out — measured on `chartjs-chart-treemap@4.2.0`, they * are the identical objects each element's `$context.raw` points at, so the * dataset is read directly and no element walk is needed. * * The layout reorders: a two-row source listing France then Japan comes back * Japan first, largest rectangle first. That is the order the chart draws in * and so the order the nodes are emitted in. * * A **flat** tree carries only `v`, `s` and a numeric `_data`: no `g`, no `l`, * no `isLeaf`. Those three fields arrive together, once `groups` is declared. */ declare interface ChartJsTreemapValue { /** The rectangle, in pixels. */ x?: number; y?: number; w?: number; h?: number; /** The node's magnitude: a leaf's own value, or a group's sum. */ v: number; /** The value the layout sized by, which `sumKeys` can separate from `v`. */ s?: number; /** Its depth, 0 at the outermost declared group. */ l?: number; /** Its name at that level — the value of `groups[l]` on its rows. */ g?: string; /** Its parent group's sum. */ gs?: number; /** * Whether it sits at the **deepest declared group**, which is not the same * as having no children in the source: measured with `groups: ['continent']` * over rows that also carry a country, `Asia` comes back `isLeaf: true` with * two children. It says where the drawn hierarchy stops. */ isLeaf?: boolean; /** * The plugin's own record for the node. For a grouped tree it is an object * whose `children` are the source rows that fell under it; for a flat tree * it is the source number itself. */ _data?: unknown; } /** * Geographic regions shaded by a value. * * Read as a bar chart whose categories happen to be places, it loses * everything spatial: where the high values sit, which way the gradient runs, * and which borders the value jumps across. `lon`/`lat` are what buy that * back. */ declare interface ChoroplethDeclaration extends DeclarationBase { /** `TraceType.CHOROPLETH` — the string `'choropleth'`. */ type: TraceType.CHOROPLETH; /** * Field holding the region's name. Maps to `ChoroplethPoint.x`. * * The chain is a map's own, not the one every other declaration shares: the * names a place answers to on a GeoJSON or TopoJSON feature, ending in `x` * so the ordinary region table — `{ x: 'Texas', y: 12.4 }` — is read the * right way round. Resolved against the row **and** against its * `properties`, which is where a feature keeps everything joined onto it, so * `region: 'NAME'` finds `properties.NAME` without being spelled as a path. * * @default 'region', falling back to `name`, `NAME`, `name_long`, `admin`, * `state`, `id`, `label` or `x` */ region?: FieldRef; /** * Field holding the value the region is shaded by. Maps to * `ChoroplethPoint.y`. * * A map's own chain, deliberately **not** the one * {@link RidgelineDeclaration.value} carries: `x` is a position on the value * axis of a ridgeline and the place's own name on a map, and announcing * "Texas" as the value of Texas is a wrong reading a listener cannot tell * from a right one. Read off the row's `properties` as well, exactly as * {@link ChoroplethDeclaration.region} is. * * @default 'value', falling back to `y`, `rate`, `density` or `count` */ value?: FieldRef; /** * Field holding the region's centroid longitude, in **degrees east**. Maps * to `ChoroplethPoint.lon`. * * Degrees only. Projected or normalised coordinates must be **omitted** * rather than converted by guesswork: without the pair the map is read as a * region list in declared order, which is a poorer reading but the one the * data supports, while a wrong compass direction is a confident wrong * answer. * * @default 'lon', falling back to `longitude` or `long` */ lon?: FieldRef; /** * Field holding the region's centroid latitude, in **degrees north**. Maps * to `ChoroplethPoint.lat`. Degrees only, exactly as * {@link ChoroplethDeclaration.lon}. * * @default 'lat', falling back to `latitude` */ lat?: FieldRef; } /** * One region of a choropleth map. * * The centroid is a **longitude and a latitude in degrees**, never a projected * coordinate. Every producer has the pair -- `d3.geoCentroid` returns exactly * it -- and asking for degrees removes the one thing MAIDR could not otherwise * resolve: whether a rising `y` means north or south. Without them the map is * read as a region list in declared order, which is a poorer reading but the * one the data supports. * * @example * { x: 'Nevada', y: 42.1, lon: -116.6, lat: 39.3, neighbors: ['Utah', 'Idaho'] } */ declare interface ChoroplethPoint { /** The region's name. */ x: string | number; /** The value the region is shaded by. */ y: number; /** Centroid longitude, degrees east. */ lon?: number; /** Centroid latitude, degrees north. */ lat?: number; /** * The regions this one shares a border with, by name. * * Declared because it cannot be recovered: adjacency is not derivable from * rendered SVG paths, and not from centroids either -- two regions can have * near centroids and no shared border, and a long region can border one * whose centroid is far away. A layer that declares none keeps the spatial * walk and is told nothing about borders, rather than something guessed. */ neighbors?: (string | number)[]; } /** * One point on one iso-value curve of a contour plot. * * A contour draws a scalar field as curves of constant value, so a layer is * one curve per level -- structurally the multi-line layer {@link LineTrace} * already navigates. What makes it a type of its own is that the **level is a * first-class object rather than a colour**: the questions a reader brings are * how many levels there are, where the 0.05 contour runs, and how far apart * the curves are here. */ declare interface ContourPoint extends LinePoint { /** * The value of the field along this curve. * * Constant down a curve and carried on every point of it, the way `z` is: * the grammar's unit is the point, and a producer emitting a flat list has * nowhere else to put it. */ level?: number; } /** Fields every declaration accepts, whatever its `type`. */ declare interface DeclarationBase { /** * Overrides the layer's announced title. Maps to `MaidrLayer.title`. * * Names the *chart*; use {@link DeclarationBase.name} to say which layer of * it this is. */ title?: string; /** * Names this layer among sibling layers. Maps to `MaidrLayer.name`. * * Announced on a layer switch in place of the trace type, so a hue-split * figure says "Male" and "Female" rather than "error_bar plot" twice. */ name?: string; } /** * A dumbbell chart: its rows, and what its two ends are called. * * An object rather than a bare array -- as {@link HeatmapData} and * {@link GaugePoint} already are -- because the names of the two ends belong * to the chart and not to any one row. Repeating them on every point would * let a producer emit rows that disagree about what the chart is comparing. * * Those names are the content of the comparison. Announced as "start" and * "end", a chart of life expectancy in 1990 against 2020 tells the reader * which dot they are on and not which year it is, which is the one thing the * legend gives a sighted reader for free. */ declare interface DumbbellData { /** The rows, in the order the chart draws them. */ points: DumbbellPoint[]; /** What the starting end is called -- "1990", "before", "control". */ startLabel?: string; /** What the finishing end is called -- "2020", "after", "treatment". */ endLabel?: string; } /** * One row of a dumbbell chart: a category and the pair of values compared at * it. * * The pair is what the chart is for -- before and after, two groups, two * years -- and the segment drawn between the dots is the comparison. Which of * the two is larger is not fixed: a dumbbell showing a decline draws `end` * below `start`, and a chart usually contains both directions at once. * * The change between them is deliberately absent, and derived instead. A * drawn segment cannot disagree with the dots it joins, so an authored delta * is a second source of truth for a quantity that already has one -- and the * one a reader would be told is the one the chart did not draw. */ declare interface DumbbellPoint { /** Position along the category axis. */ x: number | string; /** The value the segment starts at -- the earlier, or the reference, one. */ start: number; /** The value the segment ends at. */ end: number; } /** * An estimate with the interval drawn around it — an error bar, a confidence * interval, a point range. * * The bounds are **absolute positions** on the value axis, never offsets from * the estimate. Producers disagree about which they hand out (matplotlib's * `yerr` is an offset, Vega-Lite's `errorbar` computes bounds), so the grammar * fixes one and {@link ErrorBarDeclaration.error} is how the other is * declared and converted. * * The two bounds are optional and independently so: a one-sided interval is a * real chart, and dropping the point for want of its other half would lose the * estimate too. */ declare interface ErrorBarDeclaration extends DeclarationBase { /** `TraceType.ERROR_BAR` — the string `'error_bar'`. */ type: TraceType.ERROR_BAR; /** * Field holding the **absolute** lower bound. Maps to `ErrorBarPoint.yMin`. * * @default 'yMin', falling back to `lower`, `lo`, `ciLower`, `ciLow`, * `ci_low`, `low` or `min` */ yMin?: FieldRef; /** * Field holding the **absolute** upper bound. Maps to `ErrorBarPoint.yMax`. * * @default 'yMax', falling back to `upper`, `hi`, `ciUpper`, `ciHigh`, * `ci_high`, `high` or `max` */ yMax?: FieldRef; /** * Field holding the interval as an **offset** from the estimate — the field * a Recharts `` or a matplotlib `yerr` points at. A number * is a symmetric offset; a `[lower, upper]` pair is an asymmetric one. * * Both forms are **positive magnitudes**, as `yerr` is: the bounds are * `estimate - lower` and `estimate + upper`, so an interval given as * `[0.2, 0.3]` around 1.4 is 1.2 to 1.7. Signed offsets are not a second * accepted spelling — read that way the same pair would give 1.6 to 1.7, and * neither reading is detectable downstream once the absolute bounds are * emitted. A negative entry is left out rather than flipped. * * Normalised to absolute bounds on the way into the payload. Loses to * `yMin`/`yMax` where both are declared, since those need no arithmetic. * * Alone among the field refs here, this one has **no fallback chain**: an * offset column is named explicitly or spelled exactly `error`. Every common * spelling is either axis-specific (`yerr`, `xerr`, and a row carrying both * says nothing about which axis this chart draws its intervals on) or a * dispersion statistic a chart commonly draws a multiple of (`sd`, `sem`, * `err` — ±1.96 SEM is as ordinary as ±1). Read as the drawn offset, one of * those resizes every interval on the figure without saying so. */ error?: FieldRef; /** * Companion series drawing the interval rather than the estimate — an * amCharts `openValueY`/`openValueX` column, a Highcharts `errorbar`. * * Merged into this layer by x and suppressed from becoming a layer of its * own. */ intervalSeries?: SeriesRef; /** * Which axis the estimate runs along. Maps to `MaidrLayer.orientation`. * * The `Orientation` values, which are **`'horz'` and `'vert'`** — not the * words they abbreviate. `'horizontal'` is not accepted, and a declaration * carrying it is warned about and read without the key. */ orientation?: Orientation; } /** * One estimate with the interval drawn around it. * * The interval is the reason this is a point shape of its own rather than a * scatter point: a chart drawn this way carries two magnitudes at every * sample — the estimate, and how far from it the data is consistent with — * and a reading that names only the first drops the part most statistical * graphics are drawn to show. * * `lower` and `upper` are absolute positions on the value axis, not offsets * from `y`. Producers disagree about which they hand out (matplotlib's * `yerr` is an offset, Vega-Lite's `errorbar` computes bounds), so the * schema fixes one and each adapter converts to it. * * The bounds are optional and independently so: a one-sided interval — an * upper bound with no lower, say — is a real chart, and dropping the point * for want of its other half would lose the estimate too. * * The *estimate* is optional for the mirror-image reason. A band with two * bounds and nothing between them is a real chart too — Highcharts draws it * as `arearange`, and the same shape arrives from `Plot.areaY` with * `y1`/`y2`, from `geom_ribbon`, and from `fill_between` without a centre * line. There is no honest number to put here for one: the midpoint is a * value the chart never draws, and either bound announced as the estimate * loses the other and implies a point reading the chart does not make * (#1047). */ declare interface ErrorBarPoint { /** Position along the main axis. */ x: number | string; /** * The estimate itself: a mean, a median, a fitted value. * * Absent on a band that draws only bounds. {@link ForestPoint} re-declares * it required, because a forest plot's whole reading is whether the * interval crosses the null *relative to the estimate* — so the shape that * needs it says so, rather than every reader of this one assuming it. */ y?: number; /** Absolute lower bound of the interval, when the chart draws one. */ yMin?: number; /** Absolute upper bound of the interval, when the chart draws one. */ yMax?: number; /** * Name of the group this estimate belongs to, for a chart drawing an * interval per group at each category. * * Named to match {@link LinePoint.z} and carried for the same reason. A * dodged error bar over two treatments puts two estimates at every * category, and without this they arrive as two readings of one name with * nothing telling them apart. The grouping cannot be recovered from * emission order, because nothing states that order — so the comparison the * chart exists to support, whether one group's interval overlaps another's, * is the thing that goes missing (#942). * * Meaningful on the grouped shape, `ErrorBarPoint[][]`, where every point * in a series carries the same value. A single-series chart has one group * and needs no name for it. * * @example * { x: 'a', y: 2, yMin: 1.5, yMax: 2.9, z: 'control' } */ z?: string; } /** * Extracts MAIDR data plus the layer→dataset routing map from a Chart.js * chart instance. * * Charts using Chart.js axis stacking (2+ scales of the same axis kind laid * out in separate bands via the scale `stack` option) become multi-subplot * figures: one MAIDR subplot per stacked panel, arranged as N rows × 1 column * for y-stacks (rows bottom-first, matching the grammar's matplotlib row * convention so Up/Down arrows track the on-canvas direction) and 1 row × N * columns for x-stacks (left-to-right). All other charts — including classic * dual-axis overlays — remain a single subplot. */ export declare function extractChartData(chart: ChartJsChart, pluginOptions?: MaidrPluginOptions, onNavigate?: NavigateCallback): ChartJsExtraction; /** * Extracts a complete {@link Maidr} data object from a Chart.js chart instance. * * @param chart - The Chart.js chart instance to extract data from * @param pluginOptions - Optional per-chart plugin options * @param onNavigate - Optional callback invoked on data-point navigation * @returns A MAIDR data object ready to be passed to `` */ export declare function extractMaidrData(chart: ChartJsChart, pluginOptions?: MaidrPluginOptions, onNavigate?: NavigateCallback): Maidr; /** * The name of a property on the author's own datum/row object. * * Never a function: a declaration must survive JSON, because four of the slots * it rides in are serialised chart config and a function cannot be written in * one. d3 keeps its `DataAccessor` (`string | function`) and accepts a bare * `FieldRef` wherever this file names one. * * The name is resolved against the row the charting library bound to the mark * — a Chart.js datum, a Highcharts `point.options`, an amCharts * `dataItem.dataContext` — so it is the column name in your data, not a label * on the chart. * * @example * // rows are { time: 4, surv: 0.8, isCensored: true } * { type: TraceType.SURVIVAL, censored: 'isCensored' } */ export declare type FieldRef = string; /** * One weighted flow of a sankey, alluvial or chord diagram. * * A flow names both of its ends, so the **nodes are derived from the edges** * and a separate node list would be a second source of truth for something the * data already says -- the treemap's reasoning about paths, applied to a graph. * Their order is first appearance, which is the order the producer drew them. * * @example * { source: 'Coal', target: 'Electricity', value: 34 } */ declare interface FlowPoint { /** The node the flow leaves. */ source: string | number; /** The node it arrives at. */ target: string | number; /** How much flows. */ value: number; } /** * One effect estimate with its interval per study, against a shared null line, * with a pooled summary at the foot — the standard figure of a meta-analysis. * * It *is* an {@link ErrorBarDeclaration} laid out on a categorical row axis, * so it accepts every field one does. What it adds is the part a sighted * reader takes from the drawing and is otherwise never told: how much each * study weighs, which row is the pooled result rather than evidence, and where * the null line sits. */ declare interface ForestDeclaration extends Omit { /** `TraceType.FOREST` — the string `'forest'`. */ type: TraceType.FOREST; /** * Field holding the study's weight in the pooled estimate, as a fraction of * one. Maps to `ForestPoint.weight`. * * A forest plot encodes this as marker *area*: two studies whose intervals * look alike can contribute wholly differently to the result. Omitted from * the payload when nothing resolves — a forest plot without weights is a * real chart. * * A **fraction of one**, not a percentage. Meta-analysis software reports * this column as a percentage — `12.5` for one study in eight — and that is * the number the default chain will find. A resolved weight above 1 is left * out rather than rescaled: dividing by 100 guesses that the column sums to * 100, and announcing it untouched says "weight 1250%". * * @default 'weight', falling back to `w` or `share` */ weight?: FieldRef; /** * Field marking a row as the pooled summary rather than a study. Maps to * `ForestPoint.pooled`. * * It is a different kind of row — it is not evidence, it is what the * evidence came to — and announcing it as one more study invites a reader to * count it among them. * * Read on the same strict table as * {@link SurvivalDeclaration.censored}: `true`, `1`, `'1'` and `'true'` mark * the pooled row and nothing else does. Read by truthiness instead, a CSV's * `'0'` marks every study as the summary and empties the evidence the trace * counts and compares. * * @default 'pooled', falling back to `isPooled` or `summary` */ pooled?: FieldRef; /** * Row index of the pooled summary, for data that carries no flag column. A * meta-analysis draws the pooled row last, so this is usually the last * index. * * Counts **the declaring series' own rows, as authored**, from zero — * including any row an adapter goes on to drop for want of a finite value, * since that is the only sequence an author can see. It is resolved before * any {@link ForestDeclaration.pooledSeries} is absorbed, so it never * addresses a row that arrived from the companion. */ pooledIndex?: number; /** * Companion series drawing the pooled summary's own mark — the diamond a * meta-analysis ends with, when it is drawn differently from the studies. * * Its rows are appended after the studies and the companion is suppressed * from becoming a layer of its own. */ pooledSeries?: SeriesRef; /** * The value that means "no effect" — 1 for a ratio measure, 0 for a * difference. Maps to `MaidrLayer.forestOptions.nullValue`. * * Whether a study's interval crosses it *is the result for that study*, so * the trace announces the crossing. There is deliberately **no default**: a * ratio chart guessed at 0 would report every study as not crossing, since * odds ratios are all positive, and that is a confident wrong answer given * to every row. Undeclared, the layer gets the estimate, the interval and * the weight, and makes no claim about significance. */ nullValue?: number; } /** * Display configuration for a forest plot layer. */ declare interface ForestOptions { /** * The value that means "no effect" -- 1 for a ratio measure, 0 for a * difference. * * Whether an interval crosses it *is the result for that study*, so the * trace announces the crossing. There is deliberately **no default**: a * ratio chart guessed at 0 would report every study as not crossing, since * odds ratios are all positive, and that is a confident wrong answer given * to every row. A layer that does not declare it gets the estimate, the * interval and the weight, and no claim about significance. */ nullValue?: number; } /** * One row of a forest plot: a study's effect estimate with its interval. * * A meta-analysis draws one of these per study against a shared null line, * with a pooled summary at the foot. It is an {@link ErrorBarPoint} laid out * on a categorical row axis, plus the two things that make the figure a * forest plot rather than a row of intervals. */ declare interface ForestPoint extends ErrorBarPoint { /** * The study's effect estimate. * * Required here where {@link ErrorBarPoint.y} is optional. A forest plot * is read by whether each interval crosses the null, and that question is * only answerable *relative to the estimate* — a row without one is not a * study with a missing number, it is not a forest plot row at all (#1047). */ y: number; /** * The study's weight in the pooled estimate, as a fraction of one. * * A forest plot encodes this as marker *area*, which is a magnitude a * reader is otherwise never told: two studies whose intervals look alike * can contribute wholly differently to the result. */ weight?: number; /** * Marks the pooled summary rather than a study. * * It is a different kind of row -- it is not evidence, it is what the * evidence came to -- and announcing it as one more study invites a reader * to count it among them. */ pooled?: boolean; } /** * Supported format type specifiers for JSON/HTML API. */ declare type FormatType = 'currency' | 'percent' | 'fixed' | 'number' | 'date' | 'scientific'; /** * A gantt chart: its lanes, and how its axis reads. * * An object rather than a bare array, for the reason {@link DumbbellData} is * one: a unit belongs to the chart and not to any row, and repeating it per * point would let a producer emit rows that disagree about what their numbers * measure. */ declare interface GanttData { /** * The lanes, in the order the chart draws them, each holding the intervals * of one lane. * * Nested rather than flat so a lane with no intervals still exists: an empty * row is a real statement about a schedule -- nothing is booked -- and a * flat list grouped by `x` cannot say it. */ points: GanttPoint[][]; /** * What each lane is called, in the order {@link GanttData.points} holds * them. * * A populated lane names itself: every interval carries its lane in `x`. An * **empty** lane holds no interval and so has nowhere to carry one, which * makes it the only row a reader can navigate onto and be told nothing * about -- and an empty lane is exactly the row this shape is nested to be * able to express. This is where its name goes. * * Optional, and optional per entry: a chart with no empty lanes need not * supply it, and the trace prefers a lane's own intervals over this when * both are present, so a producer cannot make the two disagree about a * populated lane. */ lanes?: (string | number)[]; /** * What a unit of the axis is called: "days", "hours", "weeks". * * The length of an interval is the fact a gantt exists to carry, and a bare * number does not carry it. Omitted, the trace announces the length without * a unit rather than guessing one. */ unit?: string; } /** * A schedule drawn as intervals along a shared axis — a gantt chart, a * timeline, a swimlane diagram. * * What separates this from a bar chart is that both coordinates are positions * on the same axis rather than a position and a magnitude. A bar has one * number and a baseline; an interval has two numbers and no baseline, and the * fact a reader is listening for — how *long* the interval is — is a * difference between them that has to be announced rather than heard as a * height. * * That difference is also why {@link GanttDeclaration.unit} matters more here * than a unit does elsewhere: no charting library carries what a step of the * axis is called, so without it a task is announced as "7 long" rather than * "7 days". * * The variant is the schema an adapter reads a schedule through; no adapter * reads a gantt block yet, so a chart declaring one today is read as the * undeclared chart and told so. Adoption is a per-adapter change. * * @example * // The block a Highcharts adapter reading schedules would take, on a series * // whose rows name their ends the ordinary way * { custom: { maidr: { type: 'gantt', x: 'resource', unit: 'days' } } } */ declare interface GanttDeclaration extends DeclarationBase { /** `TraceType.GANTT` — the string `'gantt'`. */ type: TraceType.GANTT; /** * Field holding the lane the interval belongs to — a task, a resource, a * phase. Maps to `GanttPoint.x`. * * A lane commonly holds several intervals, and grouping is by this field's * value, so a row that resolves nothing here is its own lane rather than * joining another. * * @default 'x', falling back to `lane`, `category`, `label`, `name`, `key`, * `group` or `task` */ x?: FieldRef; /** * Field holding where the interval begins. Maps to `GanttPoint.start`. * * @default 'start', falling back to `from`, `begin`, `x0` or `startDate` */ start?: FieldRef; /** * Field holding where the interval ends. Maps to `GanttPoint.end`. * * @default 'end', falling back to `to`, `finish`, `x1` or `endDate` */ end?: FieldRef; /** * Field holding what this interval is called, when the lane is not already * its name. Maps to `GanttPoint.label`. * * The chain is a schedule's own rather than the `label` chain every other * declaration shares, which is the Manhattan identifier's (`snp`, `gene`, * `probe`) and names nothing on a schedule. * * The `x` chain includes `label`, so a row that names its interval but not * its lane resolves both fields to the same word. An adapter adopting this * declaration should drop a label equal to the lane it sits in rather than * emit it — an interval labelled with its own lane says the same thing * twice. {@link resolveFieldRef} resolves the two names independently and * does not compare them, so the drop belongs to the adopting adapter. * * @default 'label', falling back to `name`, `task`, `title` or `activity` */ label?: FieldRef; /** * What a unit of the axis is called: `'days'`, `'hours'`, `'weeks'`. Maps to * `GanttData.unit`. * * A literal word, not a field: the unit belongs to the chart and not to any * row, and a per-row unit would let a producer emit intervals that disagree * about what their numbers measure. Omitted, the trace announces a length * without a unit rather than guessing one. */ unit?: string; } /** * One interval of a gantt chart, timeline or swimlane diagram. * * The two coordinates are both positions on the same axis rather than a * position and a magnitude, which is what makes this a shape of its own. A bar * has one number and a baseline; an interval has two numbers and no baseline, * and its length is a difference the reader has to be told rather than a * height they can hear. */ declare interface GanttPoint { /** Which lane the interval belongs to -- a task, a resource, a phase. */ x: number | string; /** Where the interval begins. */ start: number; /** Where the interval ends. */ end: number; /** * What this interval is called, when the lane is not already its name. * * A lane commonly holds several intervals -- a resource booked twice, a * phase that pauses and resumes -- and without this they are announced by * position alone. Omit it when the lane names the work. */ label?: string; } /** * One qualitative band of a bullet chart, named and bounded above. * * Bands partition the range, so only the upper edge is carried: a band starts * where the previous one ended, and the first starts at the gauge's `min`. * Carrying both edges would let a chart declare overlapping or gapped bands * that the drawing cannot express. */ declare interface GaugeBand { /** Upper edge of the band, inclusive. */ to: number; /** What the band is called -- "poor", "ok", "good". */ label: string; } /** * A gauge or bullet chart: one measure against a range. * * Unlike every other trace's data this is a single object rather than an * array, because the chart draws exactly one measure -- the same reason * {@link HeatmapData} is an object. An array of one would describe a shape the * chart does not have. * * The value alone is not the reading. "73" means nothing without the range it * sits in, the target it was aiming at, and the band it lands in, and none of * those are written anywhere a screen reader can reach on a drawn gauge. */ declare interface GaugePoint { /** The measure. */ value: number; /** Lower end of the dial. */ min: number; /** Upper end of the dial. */ max: number; /** What the measure is called, when the chart names it. */ label?: string; /** The target marker a bullet chart draws, when it has one. */ target?: number; /** Qualitative bands, in ascending order. */ bands?: GaugeBand[]; } /** * Data structure for heatmap charts with x/y labels and 2D point values. * * **Rows run top-first**: `y[0]` names the row drawn at the *top* of the * chart and `points[0]` holds it, so the two arrays read the way a sighted * reader reads the grid. {@link Heatmap} turns both over on construction, so * that its own row 0 is the bottom of the drawn grid and , which * increments the row index, moves visually upward. * * Stated here because it cannot be recovered from the payload: a matrix of * numbers looks the same either way up, so a layer written bottom-first is * not wrong in any way the core could notice. It loads, it navigates, and * every value is still announced against its own label -- both arrays having * been reversed together -- while walks *down* the chart and the * cursor enters at the top instead of the bottom. A reader who then reports * what the top row contains has it exactly backwards (#971). * * Producers therefore have to know which way their own library counts. * matplotlib's array is top-first and needs nothing; plotly numbers a * heatmap's rows from the bottom and its adapter turns them over. */ declare interface HeatmapData { /** Column labels, left to right. */ x: string[]; /** Row labels, **top row first**. */ y: string[]; /** * `points[row][col]`, rows **top-first**, aligned with `y` and `x`. * * A cell the chart drew no value at is `null`, or any non-finite number -- * the same spelling {@link BarPoint} uses for a gap, and read through the * same `toBarValue`. It is not `0`: a grid is a rectangle, and an * adapter whose data does not fill it had no way to say so, so three of * them filled the holes with zeros and announced a value the chart never * drew (#1191). Measured on Highcharts 13.0.1, a 3x2 heatmap omitting one * cell and the same heatmap stating that cell as `0` produced byte-identical * payloads, while the first drew five cells and the second six. * * A calendar heat map is the case that makes it unavoidable rather than * merely wrong: Google draws every day of every year its data spans, so a * two-year chart of ten records is 731 cells with 721 holes. */ points: (number | null)[][]; } /** * Hexagonal binning: the standard answer to an overplotted scatter. * * A lattice of cells each carrying a count, with the one difference that * decides its navigation: a hex lattice staggers alternate rows, so a column * index does not identify a position and each bin carries its own centre. */ declare interface HexbinDeclaration extends DeclarationBase { /** `TraceType.HEXBIN` — the string `'hexbin'`. */ type: TraceType.HEXBIN; /** * Field holding the bin's centre along the x axis, in **data units**. Maps * to `HexbinPoint.x`. * * Screen coordinates would announce every bin's position in pixels. * * The chain is a hexbin's own: `x` names a bin centre here and a category, a * lane or a quantile on other charts, so no chain could be shared. It is the * shipped d3 hexbin binder's, which is where these bins are already read * from. * * @default 'x', falling back to `x0` or `cx` */ x?: FieldRef; /** * Field holding the bin's centre along the y axis, in **data units**. Maps * to `HexbinPoint.y`. * * @default 'y', falling back to `y0` or `cy` */ y?: FieldRef; /** * Field holding how many points fell in the bin. Maps to * `HexbinPoint.count`. * * The `length` fallback is what makes a d3-hexbin bin work untouched: its * bins are arrays of the points that fell in them. * * @default 'count', falling back to `length`, `value`, `n` or `total` */ count?: FieldRef; /** * Field holding the lattice row a bin sits on, for data that names it. * * Omitted, rows are grouped by identical `y`, which is what a lattice * computed by the usual libraries produces. */ row?: FieldRef; } /** * One hexagonal bin: where its centre is, and how many points fell in it. * * The centre is carried per bin rather than derived from a lattice origin and * a cell size, because a hex lattice staggers alternate rows by half a cell -- * so a bin's index does not give its position, and a consumer reconstructing * one would have to know which rows a particular library chose to offset. */ declare interface HexbinPoint { /** The bin's centre along the x axis. */ x: number | string; /** The bin's centre along the y axis. */ y: number | string; /** How many points fell in it. */ count: number; } /** * Data point for histograms extending bar points with bin ranges. */ declare interface HistogramPoint extends BarPoint { xMin: number; xMax: number; yMin: number; yMax: number; } /** * One rung of a letter-value ladder: a pair of quantiles symmetric about the * median. * * `p` is the *tail* probability, which is how letter-value plots are defined * and how the libraries that draw them report it: `p = 0.25` is the rung * spanning the middle half, `p = 0.125` the middle three quarters, and so on * inwards from the median. The trace converts it to percentiles for the * announcement, because "the 12.5th percentile" is a number a reader can * place and "p is 0.125" is one they have to convert. */ declare interface LetterValueLevel { /** * Tail probability, strictly between 0 and 0.5. * * The median is carried separately on `BoxenPoint` and is not a rung, so * `0.5` is out of range rather than a way of naming it: a rung at `0.5` * would put two positions labelled `50th percentile` either side of the one * already called `median`. Values outside the range are dropped. */ p: number; /** The lower quantile of the pair: the `p` quantile. */ lo: number; /** The upper quantile of the pair: the `1 - p` quantile. */ hi: number; } /** * Data point for line charts with optional fill color for multi-series plots. */ declare interface LinePoint { x: number | string; /** * The magnitude at this x, or `null` where the series has a position but no * reading. * * A gap is not a zero. `seaborn.pointplot` pads a hue level missing from one * category so its estimate lines stay the same length, and a producer that * meets a break in a series has nowhere else to put it. `Number(null)` is * `0`, which would make the gap sound like a real low point, let it be * reached as the row's minimum, and pull the range every other point's pitch * is scaled against — the same trap `toBarValue` was written for (#925). * * `null` rather than a non-finite number because the payload has to survive * `JSON.parse`: `json.dumps` writes `NaN` and `Infinity` as bare tokens that * are legal JavaScript and invalid JSON, and a producer emitting one stops * the chart initialising at all (xability/py-maidr#427). */ y: number | null; z?: string; /** * Ordinal level name announced in place of the raw numeric `y`, for a chart * whose y axis is a category rather than a magnitude — a hypnogram's sleep * stages, a Likert response, a severity grade. `y` stays numeric because it * drives sonification, braille and the min/max range, so the human-readable * name has to travel alongside it. * * An empty string counts as absent, so a producer that emits `''` for an * unnamed level gets the numeric announcement rather than a blank one. * Omitting it entirely is the right shape for a continuous y. * * @example * { x: 1.5, y: 3, label: 'REM' } */ label?: string; /** * Lower bound of the uncertainty around `y`, when the chart draws one. * * A fitted curve almost always comes with a band, and it is the reason the * curve is drawn rather than a plain line: `geom_smooth(se = TRUE)` and * `sns.regplot` both default to one. Carried on the sample rather than in a * layer of its own so a reader hears the value and its interval at the same * x — the comparison a band exists for is whether the trend is * distinguishable from flat, and that cannot be made by navigating two * layers in turn. * * Named to match {@link ErrorBarPoint}, so a producer that already computes * an interval emits the same keys wherever it puts them. * * Both bounds are optional and independent: a one-sided interval is a real * chart, and a sample missing its bounds still carries its value. */ yMin?: number; /** Upper bound of the uncertainty around `y`. See {@link LinePoint.yMin}. */ yMax?: number; } /** * Root MAIDR data structure containing figure metadata and subplot grid. * This is the type for the `data` prop passed to the `` React component. * * @example * ```typescript * const data: Maidr = { * id: 'my-chart', * title: 'Sales by Quarter', * subplots: [[{ * layers: [{ * id: '0', * type: 'bar', * axes: { x: 'Quarter', y: 'Revenue' }, * data: [{ x: 'Q1', y: 120 }, { x: 'Q2', y: 200 }], * }], * }]], * }; * ``` */ declare interface Maidr { /** Unique identifier for the chart. Used for DOM element IDs. */ id: string; /** Chart title displayed in text descriptions. */ title?: string; /** Chart subtitle. */ subtitle?: string; /** Chart caption. */ caption?: string; /** * Optional figure-wide axis labels shared across every subplot — e.g. a facet * grid whose panels all sit on one common X and Y axis drawn at the figure * margins. Only `label` is honored at the figure level, so the type is * narrowed to `Pick` (a layer's `min` / `max` / * `tickStep` / `format` have no figure-wide meaning and would be silently * ignored — the narrower type surfaces that as a compile error instead). * * When present and authored, the figure lobby's `l x` / `l y` announce these * as the figure-wide label; when omitted they fall back to the focused * subplot's own axis, so existing charts are unaffected. * * @example * axes: { x: { label: "Year" }, y: { label: "Revenue" } } */ axes?: { x?: Pick; y?: Pick; }; /** * 2D grid of subplots. Each row is an array of subplots. * For a single chart, use `[[{ layers: [...] }]]`. */ subplots: MaidrSubplot[][]; /** * Enables live/realtime mode for this chart. When true: * - React consumers can update the `data` prop to replace the chart data in place. * - Script-tag consumers can push updates via `window.maidrLive.setData()` / * `window.maidrLive.appendData()`. * - The 'M' key toggles monitor mode, which auto-sonifies and announces * newly appended data points. * * Static charts (the default) are unaffected. */ live?: boolean; /** * Sliding window size for streaming data. When set, appending a data point * beyond this width drops the oldest point(s), keeping at most `maxWidth` * points per series. Only applies to `appendData` updates. */ maxWidth?: number; /** * Optional callback invoked when the active data point changes. * Used by canvas-based charting libraries (e.g., Chart.js) for visual highlighting, * since canvas elements cannot be targeted with CSS selectors. * * This field is not serializable as JSON; it is only available when constructing * MAIDR data programmatically (e.g., via the Chart.js plugin or React API). */ onNavigate?: NavigateCallback; } /** * Layer/trace definition containing plot type, data, and rendering configuration. */ declare interface MaidrLayer { id: string; type: TraceType; title?: string; /** * What this layer is, when a subplot's layers are the same kind of thing. * * Announced on a layer switch in place of the trace type. Without it, two * layers of one type are indistinguishable — a hue-split error bar chart * announces "Layer 1 of 2: error_bar plot" and then "Layer 2 of 2: * error_bar plot", so a reader hears two different sets of numbers and is * never told that the first is Male and the second Female, which is the * whole content of the split and what a legend gives a sighted reader for * free. * * Distinct from `title`, which names the *chart* rather than the layer: * producers put the figure's title there for every layer of a figure, so it * cannot say which layer this is. * * @example * name: 'Male' */ name?: string; /** * Which element of the chart each point of the layer is drawn as. * * A plain string leaves the pairing to document order; an array names one * element per point; a grid names one per cell of a segmented layer. * * A grid cell may be `null`, which says the chart drew **no element** for * that cell — a category a series has no bar at, or a position a heat grid * is not a rectangle at. That is different from a selector that fails to * resolve, which is a mistake and declines the whole grid: without a way to * tell the two apart, a producer whose layer has a gap has to choose between * losing the highlight everywhere and inferring the gaps from the values, * and a value of zero is not evidence that a bar was never drawn (#1002). * * It is also not the same as a `null` in {@link HeatmapData.points}, which * says the chart drew no *value*. A calendar has both, at different cells: * a day inside the year with no row is drawn as a white square, so it has * an element and no value, while the slots outside the year have neither * (#1174). */ selectors?: string | string[] | (string | null)[][] | BoxSelector[] | CandlestickSelector; /** * Which way the layer is drawn. Defaults to {@link Orientation.VERTICAL}. * * For one family of traces this key decides **which field of a point holds * the magnitude**, so getting it wrong is not a cosmetic error — the trace * reads a category name where it expects a number and sounds with no * magnitude at all. For every other trace it changes only which axis label * a reading is announced against, and the payload is written the same way * whichever value is set. * * **What the two words name.** Orientation is the direction the *magnitude* * runs, not which axis happens to be called `x`. That is the convention the * whole field uses: a horizontal bar chart is one whose bars run left to * right, with the categories down the y axis — and it is how the drawing * libraries name the same switch. Chart.js: `indexAxis: 'y'` gives * "horizontal bars", the y axis holding the categories and the x axis the * values. Highcharts: `chart.inverted` makes "the x axis vertical and y axis * horizontal". Matplotlib 3.10 replaced `boxplot(vert=False)` with * `orientation='horizontal'`, which "plots the boxes horizontally". Plotly * states it outright: with `'h'`, "the value of each bar spans along the * horizontal". * * A producer therefore reads its chart, not its API's vocabulary. Where a * library names the *other* direction — ECharts' and amCharts' funnel * `orient`/`orientation` name the way the stages progress, so their default * funnels encode the value as a band's width and are `horz` here — the * adapter translates, and says so where it does. * * The rule is: **the bar family swaps `x` and `y`; nothing else does.** * * | trace | `vert` | `horz` | * | --- | --- | --- | * | the bar family, listed below | `x` is the category, `y` the magnitude | `x` is the **magnitude**, `y` the category | * | `error_bar`, `forest` | `x` is the category, `y`/`yMin`/`yMax` the magnitudes | unchanged — only the axis labels swap | * | `box`, `boxen`, `violin_box` | quantile fields, no axis assignment | unchanged | * | `gantt`, `dumbbell` | — | unchanged; navigation and panning only | * * The bar family is defined by what a type is built on rather than by what * it is called, because the exchange is inherited from `AbstractBarPlot`'s * constructor: `bar`, `histogram`, `stacked`, `dodged`, `normalized` and * the traces built on those (`diverging`, `mosaic`) — and also `dot` and * `lollipop`, which the factory constructs as a `BarTrace` outright, and * `funnel`, whose trace extends `BarTrace` and never undoes the exchange. * Reading one model file at a time misses those last three, so * `test/type/orientationContract.test.ts` runs the list rather than * restating it. * * Note that this is a different question from the one * `resolveOrientation()` in `src/util/orientation.ts` answers. Its * `IS_ORIENTED` record says whether a type has an orientation worth * announcing ("vertical bar plot"); a type can be oriented in that sense * and still not want its payload swapped, which is the trap this table * exists to close. Both r-maidr #184 and #186 were emitted against the * wrong half of it. * * @example * // a horizontal bar chart of apple = 30 * { orientation: 'horz', data: [{ x: 30, y: 'apple' }] } */ orientation?: Orientation; /** * Optional DOM mapping hints. When provided, individual traces can opt-in * to use these hints to map DOM elements to the internal row-major data grid * without changing default behavior when omitted. */ domMapping?: { /** * Specify DOM flattening order for grid-like traces. * 'row' => row-major, 'column' => column-major. */ order?: 'row' | 'column'; /** * For segmented/dodged bars, control the per-column group/level iteration. * 'forward' => iterate groups top-to-bottom (as previously domOrder='forward'). * 'reverse' => iterate bottom-to-top (default). */ groupDirection?: 'forward' | 'reverse'; /** * For boxplots, control the Q1/Q3 edge mapping for IQR box. * 'forward' => Q1=bottom, Q3=top (default for vertical) * 'reverse' => Q1=top, Q3=bottom (for Base R vertical boxplots) */ iqrDirection?: 'forward' | 'reverse'; /** * For a line-family layer, whether the chart draws the series' points in * the opposite order from the one `data` lists them in. * `'data'` (the default) => the r-th mark drawn is `data[r]`. * `'reverse'` => the marks run the other way, so the last one drawn is * `data[0]`. * * A reversed category axis draws a series from its far end while the * library goes on reporting its points in the order they were written, so * a chart read in the written order is announced as its own mirror image: * every value right, the shape backwards, and with it the stereo pan, the * braille line and the direction autoplay sweeps (#1007). * * A bar layer fixes that adapter-side, by reversing the rows and naming * each bar outright so the highlight follows (#995). A line cannot: it has * no per-point selector to permute -- `LineTrace` reads its points out of * one ``'s geometry, in path order, which is the *library's* data * order whichever way the axis runs. Reversing the payload alone would * pair `data[0]` with the vertex at the other end of the chart, trading a * correct highlight for a wrong one (#988, #990). This is how an adapter * says it has reversed the payload, so the trace can pair the two halves * back up. * * Read by `LineTrace` (and the traces built on it) and ignored by every * other type. Omit it unless the drawn direction is known: a layer that * declares `'reverse'` and is not drawn that way outlines the wrong end * of the series, which is worse than the direction being wrong on its own. */ pointOrder?: 'data' | 'reverse'; }; /** * Axis configuration. Every axis (x, y, z) is specified as an {@link AxisConfig} * object with an optional `label`, optional grid navigation properties * (`min`, `max`, `tickStep`), and optional per-axis `format`. * * @example * // Basic labels * axes: { x: { label: "Date" }, y: { label: "Price" } } * * @example * // With per-axis formatting * axes: { * x: { label: "Date" }, * y: { label: "Price", format: { type: "currency", decimals: 2 } } * } * * @example * // With grid navigation (scatter) * axes: { * x: { label: "Sepal Length", min: 4.3, max: 7.9, tickStep: 0.7 }, * y: { label: "Sepal Width", min: 2, max: 4.4, tickStep: 0.5 } * } */ axes?: { x?: AxisConfig; y?: AxisConfig; z?: AxisConfig; }; /** Display configuration for a forest plot layer. */ forestOptions?: ForestOptions; /** Threshold configuration for a volcano or Manhattan plot layer. */ thresholdOptions?: ThresholdOptions; /** * Optional display configuration for violin plot layers (VIOLIN_KDE and VIOLIN_BOX). * Controls which summary statistics are shown in the violin box overlay. */ violinOptions?: ViolinOptions; /** * Where a {@link TraceType.STEP} layer jumps between samples, and how a * stepped {@link TraceType.AREA} band moves between them. Read by * `StepTrace` and by `AreaTrace` -- `line.shape` and a fill are independent, * so a band can be a staircase -- and ignored by every other trace type. * Omit it when the producing library does not report one, rather than * guessing: the announcement names the convention, and naming the wrong one * is worse than staying silent. */ stepDirection?: StepDirection; data: BarPoint[] | FlowPoint[] | NetworkPoint[] | BoxPoint[] | BoxenPoint[] | CandlestickPoint[] | DumbbellData | ErrorBarPoint[] | ErrorBarPoint[][] | ForestPoint[] | GanttData | GaugePoint | HeatmapData | HexbinPoint[][] | HistogramPoint[] | LinePoint[][] | PiePoint[] | ScatterPoint[] | MosaicPoint[][] | VolcanoPoint[] | SegmentedPoint[][] | SmoothPoint[][] | ContourPoint[][] | StepPoint[][] | ChoroplethPoint[] | SurvivalPoint[][] | TreemapPoint[] | ViolinKdePoint[][] | WaterfallPoint[] | WordCloudPoint[]; } /** * Chart.js plugin that automatically adds MAIDR accessibility. * * Register globally with `Chart.register(maidrPlugin)` or per-chart via * the `plugins` array in the chart configuration. * * Disable for a specific chart: * ```js * new Chart(ctx, { * // ... * options: { plugins: { maidr: { enabled: false } } }, * }); * ``` */ export declare const maidrPlugin: ChartJsPlugin; /** * Per-chart options for the MAIDR plugin, configurable via * `options.plugins.maidr` in the Chart.js config. */ export declare interface MaidrPluginOptions { /** Set to `false` to disable the MAIDR plugin for a specific chart. */ enabled?: boolean; /** Override the auto-detected chart title. */ title?: string; /** Override axis labels. */ axes?: { x?: string; y?: string; z?: string; }; /** * What the chart actually is, when Chart.js cannot say. * * Several figures are drawn in Chart.js as a recipe rather than as a type of * their own, and a few of those are shape-identical to another recipe: a * Kaplan-Meier curve is a stepped line, a dumbbell is a horizontal floating * bar exactly as a one-interval gantt is, and a gauge is a part-circle * doughnut exactly as a half-pie is. Where the values cannot settle it — see * the value heuristics in the extractor for the cases where they can — this * is the author saying so, and it wins over every heuristic. */ traceType?: TraceType; /** * What one unit of a gantt chart's interval axis measures — "days", * "sprints", "hours". * * The length of an interval is the fact a schedule is drawn to carry, and * Chart.js states the unit nowhere: a linear axis is bare numbers, and a * time axis is parsed to epoch milliseconds whatever `time.unit` displays. * Absent, MAIDR announces a length without naming a unit rather than * inventing one. */ unit?: string; /** * What a dumbbell's two ends are called — "1990" and "2020", "before" and * "after". * * A dumbbell drawn as a floating bar carries one datum per row and no name * for either end, so without these a reader is told which dot they are on * ("start", "end") but not which year it is — the one thing the legend gives * a sighted reader for free. */ startLabel?: string; endLabel?: string; /** * The target a bullet chart's marker sits at, and the qualitative bands its * arc is coloured in. * * A doughnut gauge draws neither: the target is a second arc or a needle and * the bands are background colours, and Chart.js records both as styling * rather than as data. They are part of the reading — "7 below target, in * the 'ok' band" — so the author supplies them here or they go unannounced. */ target?: number; bands?: GaugeBand[]; /** * Outline color used for the DOM highlight overlay drawn on top of the * canvas during MAIDR navigation. Accepts any CSS color string. * Defaults to a translucent orange. */ highlightColor?: string; } /** * Subplot data structure containing optional legend and trace layers. * A subplot groups one or more layers (traces) that share the same coordinate space. * * @example * ```typescript * const subplot: MaidrSubplot = { * layers: [ * { id: '0', type: 'bar', axes: { x: 'X', y: 'Y' }, data: [...] }, * { id: '1', type: 'line', axes: { x: 'X', y: 'Y' }, data: [...] }, * ], * }; * ``` */ declare interface MaidrSubplot { /** Legend labels for multi-series plots. */ legend?: string[]; /** CSS selector for the subplot container element. */ selector?: string; /** Array of trace layers in this subplot. */ layers: MaidrLayer[]; } /** * A declaration of what one series means, discriminated on its `type`. * * `type` is the **`TraceType` string value**, not a private alias: the word * the author writes is the word emitted in `MaidrLayer.type` and printed in * every warning. Two of them surprise people and are called out on the fields * that carry them — `TraceType.SCATTER` is `'point'` and `TraceType.PARALLEL` * is `'parallel_coordinates'`. * * The key set of each variant is **closed**, and adapters check it at read * time — the key names, the shape of each value, and the presence of the few * fields a variant cannot be read without. A plain-JS author who writes * `significanse: 7.3`, or `significanceDirection: 'Below'`, is told so, which * is the only defence available outside TypeScript. A value that is not what * its key takes is dropped rather than passed on, so the grammar's own default * applies instead of a wrong reading. */ export declare type MaidrTraceDeclaration = SurvivalDeclaration | ErrorBarDeclaration | ForestDeclaration | VolcanoDeclaration | ManhattanDeclaration | AlluvialDeclaration | MosaicDeclaration | ScatterDeclaration | ChoroplethDeclaration | ParallelDeclaration | RidgelineDeclaration | HexbinDeclaration | BoxenDeclaration | GanttDeclaration; /** * Genomic position against significance — the standard figure of a GWAS. * * Read as a scatter it offers point-by-point navigation over tens of thousands * of points, which is not a viable path to the few dozen that matter. What a * reader wants is which points cross the line and what they are called. * * @example * // Chart.js, 22 chromosome datasets that read as one cloud * { maidr: { type: 'manhattan', label: 'snp', group: 'chr', significance: 7.3 } } */ export declare interface ManhattanDeclaration extends DeclarationBase { /** `TraceType.MANHATTAN` — the string `'manhattan'`. */ type: TraceType.MANHATTAN; /** * Field holding what each point *is* — a SNP id, a probe, a marker. Maps to * `VolcanoPoint.label`. * * Identity is the payload on these charts, not the coordinates: a reader * told "x is 2.3, y is 14.1" has been given the two numbers whose shape they * can already hear and withheld the one thing they came for. Left out of the * payload when nothing resolves. * * @default 'label', falling back to `snp`, `id`, `name`, `gene` or `probe` */ label?: FieldRef; /** * Field holding the region a point belongs to — its chromosome. Maps to * `VolcanoPoint.group`. * * @default 'group', falling back to `chromosome`, `chrom`, `chr` or `region` */ group?: FieldRef; /** * The significance cutoff on the y axis, on the axis the chart is drawn * against — 7.3 for genome-wide significance on a `-log10(p)` axis. Maps to * `MaidrLayer.thresholdOptions.significance`. * * There is deliberately **no default**: the conventions differ by field and * by software, and a guessed line would sort every point on the figure onto * the wrong side, silently. Undeclared, the trace simply reports no * findings. */ significance?: number; /** * Which side of `significance` is the significant one. Maps to * `MaidrLayer.thresholdOptions.significanceDirection`. * * `'above'` suits the transformed axes these charts usually carry; a **raw p * axis runs the other way** and needs `'below'`, where a reading fixed to * `'above'` would select precisely the points that failed to reach * significance and announce them as the result. * * The grammar's `'above'` default is the grammar's to apply: pass your value * through or pass nothing. */ significanceDirection?: 'above' | 'below'; /** * The effect-size cutoff on the x axis, applied to its **magnitude**. Maps * to `MaidrLayer.thresholdOptions.effect`. * * Meaningful on a volcano, whose x is an effect size. A Manhattan's x is a * genomic position and its x-axis plot lines are chromosome dividers rather * than cutoffs, so this is never inferred for one — declare it or leave it * out. */ effect?: number; /** * Absorb *following* sibling series of the same drawn kind that carry no * declaration of their own into this layer. * * This is how a 22-dataset Manhattan becomes one navigable trace rather than * 22 layers a reader must switch between. * * @default true */ merge?: boolean; } /** * A stacked bar chart whose bar **widths** also encode data — a mosaic or * marimekko, a two-way contingency table drawn as tiles. * * Read as a plain stacked bar it loses the width entirely, which is half the * table: the conditional proportions arrive without the group sizes they were * computed from, so a category of six people and one of six hundred read * identically. * * Always declared, never detected. A non-uniform width array on a stacked bar * is a claim about how authors behave, not about what the data means, and a * false positive would announce every column's width as a share of all * observations — a number the chart does not contain. */ declare interface MosaicDeclaration extends DeclarationBase { /** `TraceType.MOSAIC` — the string `'mosaic'`. */ type: TraceType.MOSAIC; /** * Field holding the category's share of all observations, as a fraction of * one — the width its column is drawn at. Maps to `MosaicPoint.width`. * * @default 'width' */ width?: FieldRef; /** * Field holding the cell's own count, when the producer has the contingency * table. Maps to `MosaicPoint.count`. * * Optional because a producer working from proportions alone genuinely does * not have it, and multiplying out a rounded share would put a number in the * announcement that the data does not contain. * * @default 'count', falling back to `length`, `value`, `n` or `total` */ count?: FieldRef; } /** * One cell of a mosaic (marimekko) plot. * * A mosaic is a stacked bar chart in which the **bar widths also encode * data** -- typically each category's share of all observations. A reader * given only the segment heights has half the table: the conditional * proportions without the group sizes they were computed from, so a category * of six people and one of six hundred read identically. */ declare interface MosaicPoint extends SegmentedPoint { /** * The category's share of all observations, as a fraction of one -- the * width its column is drawn at. * * Carried on every cell of the column rather than once per column, the way * `z` is carried on every cell of a series: the grammar's unit is the * point, and a producer emitting a flat list has nowhere else to put it. */ width?: number; /** * The cell's own count, when the producer has the contingency table. * * A mosaic is drawn *from* a two-way table, and the count is the number the * table was built on. It is optional because a producer working from * proportions alone genuinely does not have it, and inventing one by * multiplying out a rounded share would put a number in the announcement * that the data does not contain. */ count?: number; } /** * Callback invoked when the active data point changes during navigation. * Used by canvas-based charting libraries (e.g., Chart.js) for visual highlighting. * * `null` means no data point is active — the cursor has left a subplot for the * figure lobby of a multi-panel chart. A consumer drawing an overlay must clear * it, since there is no other signal that the selection ended: without one, the * last point's highlight stays on screen and follows the user to another panel, * pointing at a chart it does not belong to. * * @param info - The current navigation position, or `null` when nothing is * selected * @param info.layerId - The ID of the active layer/trace * @param info.row - The current row index (e.g., dataset index) * @param info.col - The current column index (e.g., data point index) * @param info.pointIndices - Present only for a point cloud (scatter, volcano, * manhattan), whose selection is a *set of points* rather than a cell of a * grid: the indices into that layer's `data` array — as the producer supplied * it — of every point the highlight covers. When it is present `row` and * `col` are both `-1`, because no row/column pair can name the selection, and * a consumer that bounds-checks them (as it must) then clears the overlay * rather than outlining an arbitrary mark. */ declare type NavigateCallback = (info: { layerId: string; row: number; col: number; pointIndices?: readonly number[]; } | null) => void; /** * One link of a network or node-link diagram. * * Undirected: a link between two nodes is a fact about the pair, not a * direction, and the nodes are derived from the links exactly as a * {@link FlowPoint}'s are. * * **There is deliberately no position here.** Where a force-directed node * lands is a fact about the solver's seed rather than about the data, so * announcing it would be inventing a finding -- and a field that existed * would eventually be announced. * * @example * { source: 'Ada', target: 'Grace' } */ declare interface NetworkPoint { /** One end of the link. */ source: string | number; /** The other end. */ target: string | number; } /** * Which way a layer is drawn, for the many trace types that can go either way * — the bar family, the box and violin family, error bars, funnels, Gantt * charts and dumbbells among them. * * See {@link MaidrLayer.orientation} for what setting it actually changes, * which is not the same for every type: for the bar family it selects which * field of a point carries the magnitude, and elsewhere it only swaps which * axis label a reading is announced against. */ declare enum Orientation { VERTICAL = "vert", HORIZONTAL = "horz" } /** * One polyline per observation across several axes, one axis per variable. * * Every column is a different quantity, so a value is pitched against its * **own** axis rather than against one range for the layer — which is why the * axes must be named and why they must be named in draw order. */ declare interface ParallelDeclaration extends DeclarationBase { /** * `TraceType.PARALLEL` — the string **`'parallel_coordinates'`**, not * `'parallel'`. */ type: TraceType.PARALLEL; /** * The axes, in the order they are drawn — which is the order a reader arrows * through them. * * Required, and required to be a list: nothing on the observation says it, * an object's key order is not an axis order and must never be used as one, * and a guessed order would announce the chart's columns in the wrong * places. * * A bare string names both the axis and the **raw, un-normalised** field on * the observation. The object form separates them, for a chart whose column * key is not what a reader should hear. Either way the field named is the * value *before* the chart scaled it to the axis: a trace derives each * column's own extent, so it must never see 0–1 values. * * @example * dimensions: ['mpg', 'hp', { label: 'Weight (lb)', key: 'wt' }] */ dimensions: (string | { label?: string; key: FieldRef; })[]; /** * Field holding the observation's name, announced as its series name. * * The default chain is the genomics one, so a row carrying an `id` or a * `name` column resolves to it. Where that column is chart plumbing rather * than the observation's name, name the field explicitly. * * @default 'label', falling back to `snp`, `id`, `name`, `gene` or `probe` */ label?: FieldRef; } /** * Data point for one slice of a pie chart. * * A pie layer's `data` is a flat `PiePoint[]` — one entry per slice, in the * order the slices are drawn — never the nested group array the bar-family * types use. * * `y` is strictly numeric, unlike {@link BarPoint.y}: it is both the sonified * magnitude and the numerator of the slice's percentage, and a percentage * derived from a string is not a percentage. * * There is deliberately no `percentage` field. The share of the whole is * derived once in the model as `y / sum(y) * 100`, so an authored percentage * can never disagree with the values it is supposedly derived from. */ declare interface PiePoint { /** Slice label, e.g. the category the slice stands for. */ x: string | number; /** Slice magnitude. Negative values are not meaningful in a pie. */ y: number; } /** * One density curve per group along a shared value axis, the curves offset * down the page so their shapes can be compared. * * The offset is presentation — it exists so the curves do not overlap * illegibly — so a layer carries each group's curve on its own terms and never * the baseline it was drawn from. */ declare interface RidgelineDeclaration extends DeclarationBase { /** `TraceType.RIDGELINE` — the string `'ridgeline'`. */ type: TraceType.RIDGELINE; /** * Field holding the group a curve belongs to — the row it is drawn on. Maps * to the categorical axis of `ViolinKdePoint`. * * Required, and therefore always used verbatim: without it there is nothing * to separate the curves by, and one ridgeline read as a single density is a * different chart. */ group: FieldRef; /** * Field holding the position along the value axis. Maps to * `ViolinKdePoint.y`. * * @default 'value', falling back to `x`, `t` or `position` */ value?: FieldRef; /** * Field holding the kernel-density value **before** the group's ridge offset * was added. Maps to `ViolinKdePoint.density`. * * Fed the drawn y instead, every group's loudness becomes a function of * where it was stacked and the lowest ridge is the loudest. Where this * resolves to nothing the reading is refused outright — an adapter warns and * falls back to the undeclared chart type rather than subtracting a guessed * baseline. * * @default 'density', falling back to `kde`, `width`, `p` or `estimate` */ density?: FieldRef; } /** * An ordinary scatter, declared rather than detected. * * Worth declaring for the two things a scatter cannot say for itself: that its * points carry an identity beyond their coordinates, and that several series * are one cloud. */ export declare interface ScatterDeclaration extends DeclarationBase { /** * `TraceType.SCATTER` — the string **`'point'`**, not `'scatter'`. The * grammar names the mark, and the value is what an adapter emits and what * every warning prints. */ type: TraceType.SCATTER; /** * Field holding what each point *is*, announced alongside its coordinates * wherever the emitted point carries a name. * * `ScatterPoint` has no label field today, so a plain `point` layer has * nowhere to put one: declare `volcano` or `manhattan` where identity is the * payload, which is where the grammar carries it. The key is accepted here * rather than reported as unknown because it is the field's obvious home, * and warning about a spelling the declaration documents would send an * author looking for a typo they did not make. * * The default chain is the genomics one, so a row carrying an `id` or a * `name` column resolves to it. Where those are chart plumbing rather than * the point's identity, name the field explicitly. * * @default 'label', falling back to `snp`, `id`, `name`, `gene` or `probe` */ label?: FieldRef; /** * Absorb following undeclared siblings of the same drawn kind into this * layer, as {@link ManhattanDeclaration.merge} does. * * @default false */ merge?: boolean; } /** * Data point for scatter plots with x and y coordinates, plus optional z for 3D. */ declare interface ScatterPoint { x: number; y: number; z?: number; /** * What the point *is* -- a country, a gene, a node of a tree. * * Distinct from {@link ScatterPoint.xLabel} and * {@link ScatterPoint.yLabel}, which name *the category a coordinate is a * position for*. \"This slot on the x axis is called Norway\" and \"this * point is Norway\" are different statements, and a chart can make either * one: a strip plot makes the first, a labelled scatter the second. * * On some charts identity is the whole payload rather than a decoration. * A reader told \"x is 2.3, y is 14.1\" has been given the two numbers they * can see the shape of already and withheld the one thing they came for -- * which is why a volcano plot, a Manhattan plot and Observable's canonical * country-names-against-GDP scatter are all drawn this way, and why * `Plot.text` exists as a mark at all. * * Declared here rather than on {@link VolcanoPoint}, where it began: the * field is a property of *a point that has a name*, not of one chart type, * and `VolcanoPoint` inherits it unchanged. * * An empty string counts as absent, per {@link ScatterPoint.xLabel}. * * @example * { x: 3.1, y: 14.2, label: 'Norway' } */ label?: string; /** * The name of the category `x` is a position for, when the x axis carries * names rather than measurements. * * `x` stays numeric because {@link ScatterTrace} does arithmetic on it — * `sort((a, b) => a.x - b.x)`, `Math.hypot(center.x - _x, …)`, and the * column index that stereo panning resolves through. `'a' - 'b'` is `NaN`, * so a string in `x` alone would give an unstable sort, a broken column * index and a highlight that resolves to nothing. The name therefore * travels *alongside* the position rather than in place of it, which is * also what the chart is: a category **at** a slot. * * {@link LinePoint} needs no equivalent for x because it never subtracts * one — `LinePoint.x` simply widens to `string`. {@link LinePoint.label} is * the same idea as this one applied to a line's *y*, which cannot widen * because it drives sonification. * * A categorical scatter is not a rare shape: it is what * `seaborn.stripplot`, `seaborn.swarmplot` and `ggplot2::geom_jitter` draw, * and what any `geom_point` on a discrete scale draws. Without this a * reader hears "g is 0" where the chart says "a" (#927). * * An empty string counts as absent, so a producer emitting `''` for an * unnamed slot gets the numeric announcement rather than a blank one. * * @example * { x: 0, xLabel: 'a', y: 12.5 } */ xLabel?: string; /** * The name of the category `y` is a position for, for the same reasons * {@link ScatterPoint.xLabel} gives. * * Both axes carry one because either can be the categorical one: a strip * plot drawn `sns.stripplot(df, x='g', y='v')` puts the names on x, and * `sns.stripplot(df, y='g', x='v')` puts them on y. A single un-suffixed * `label` would leave a consumer guessing which coordinate it names. * * @example * { x: 12.5, y: 0, yLabel: 'a' } */ yLabel?: string; } /** * Data point for segmented/grouped bar charts with fill color identifier. */ declare interface SegmentedPoint extends BarPoint { z: string; } /** * A library-native identifier for another series in the same chart — * Highcharts `series.options.id`, amCharts `IEntitySettings.id`, Chart.js * `dataset.label`, Recharts `dataKey`. * * **Never an index.** Positional addressing into a series list goes stale the * moment a series is filtered, reordered or toggled — a routine chart edit * nobody associates with accessibility — and that is the failure this design * exists to remove. * * A ref that names no series is reported and the parent layer is emitted * without that half, rather than silently matching whatever sits at that * position today. */ declare type SeriesRef = string; /** * Data point for smooth/regression plots with data and SVG coordinate pairs. */ declare interface SmoothPoint { x: number; y: number; svg_x: number; svg_y: number; } /** * Where a step chart jumps between two consecutive samples. * * - `hv` — hold `y[i]` until `x[i+1]`, then jump (matplotlib `steps-post`). * - `vh` — jump at `x[i]`, then hold until `x[i+1]` (matplotlib `steps-pre`). * - `mid` — jump at the midpoint of the two x values (matplotlib `steps-mid`). * * `hv` is what `ggplot2::geom_step()` draws by default, but MAIDR substitutes * no default of its own: see {@link MaidrLayer.stepDirection}. */ declare type StepDirection = 'hv' | 'vh' | 'mid'; /** * Data point for step charts — structurally a {@link LinePoint}. * * The ordinal `label` that lets a hypnogram announce "REM" instead of "3" * started here, but it is not a step-only pairing: a line or path over the * same ordinal y needs it just as much, so it now lives on `LinePoint` and * every trace in the line family reads it. * * The name is kept because a step layer's `data` is authored as * `StepPoint[][]`, and it says which chart the points belong to. * * @example * { x: 1.5, y: 3, label: 'REM' } */ declare type StepPoint = LinePoint; /** * A Kaplan-Meier survival curve drawn as a step line. * * What a survival figure carries beyond a step chart is the two things it is * read for: which times were **censored**, and how wide the **confidence * band** is. Censoring marks are drawn as ticks rather than as steps, and a * reader who cannot tell a censored time from an ordinary one cannot tell a * flat tail backed by two hundred subjects from one backed by three. * * @example * // Highcharts, one arm whose own samples carry the flag * { custom: { maidr: { type: 'survival', censored: 'cens' } } } */ export declare interface SurvivalDeclaration extends DeclarationBase { /** `TraceType.SURVIVAL` — the string `'survival'`. */ type: TraceType.SURVIVAL; /** * Field marking a sample as a censored time. Maps to `SurvivalPoint.censored`. * * `true`, `1`, `'1'` and `'true'` count as censored; anything else does * not — the flag arrives as a boolean, as a 0/1 indicator or as the string * one of those was parsed from, and `'0'` is truthy in every one of those * readings but censors nobody. The same table decides * {@link ForestDeclaration.pooled}. * * Deliberately **not** aliased to `event`, which most survival datasets * carry with the opposite meaning: a 1 there is the event happening, which * is exactly the times that are not censored. * * @default 'censored', falling back to `censor` or `isCensored` */ censored?: FieldRef; /** * Field holding the confidence band's lower bound at this time. Maps to * `SurvivalPoint.yMin`. * * @default 'yMin', falling back to `lower`, `lo`, `ciLower`, `ciLow`, * `ci_low`, `low` or `min` */ yMin?: FieldRef; /** * Field holding the confidence band's upper bound at this time. Maps to * `SurvivalPoint.yMax`. * * @default 'yMax', falling back to `upper`, `hi`, `ciUpper`, `ciHigh`, * `ci_high`, `high` or `max` */ yMax?: FieldRef; /** * Where the curve jumps between times. Maps to `MaidrLayer.stepDirection`. * * `'hv'` is what a Kaplan-Meier curve means — survival holds until an event * drops it — but MAIDR substitutes no default of its own, so declare it * rather than letting the description stay silent about the convention. */ stepDirection?: StepDirection; /** * Companion series drawing the censoring ticks, when they come from their * own data join rather than from a `censored` column on the curve. * * Each tick is merged into this layer at the time its x gives, and the * companion is suppressed from becoming a layer of its own. Highcharts * charts that already pair with `linkedTo` need not repeat themselves here. */ censoredSeries?: SeriesRef; /** Companion series drawing the confidence band, merged in by x as above. */ bandSeries?: SeriesRef; /** * Absorb *following* sibling series of the same drawn kind into this layer * as further **arms** of the same curve, as * {@link ManhattanDeclaration.merge} absorbs further points into one cloud. * * On by default, because a survival figure is one figure whose arms belong * together: treated and control are read against each other, and two arms * split into two layers is a reader switching layers to compare the two * numbers the chart exists to compare. `SurvivalTrace` carries an arm per * row, so the arms stay individually navigable either way. * * Set `false` for the rare figure whose curves are genuinely separate * charts. A second arm needs no declaration block of its own. * * @default true */ merge?: boolean; } /** * One point of a Kaplan-Meier survival curve. * * The curve itself is a step function -- survival holds until an event drops * it -- so this is a {@link StepPoint} with the two things a survival figure * carries that a step chart does not. */ declare interface SurvivalPoint extends StepPoint { /** * A subject left the study at this time without the event happening. * * Censoring marks are drawn as ticks on the curve rather than as steps, * because censoring does not change the estimate -- it changes how much of * the curve is still supported by data. A reader who cannot tell a censored * time from an ordinary one cannot tell a flat tail backed by two hundred * subjects from one backed by three. */ censored?: boolean; /** Lower bound of the confidence band at this time, when the chart draws one. */ yMin?: number; /** Upper bound of the confidence band at this time, when the chart draws one. */ yMax?: number; } /** * Display configuration for a volcano or Manhattan plot layer. */ declare interface ThresholdOptions { /** * The significance cutoff on the y axis. * * There is deliberately no default. These charts are drawn on transformed * axes whose conventions differ by field and by software: -log10(p) at 1.3 * for p < 0.05, and at 7.3 for genome-wide significance. A guessed line * would sort every point on the figure onto the wrong side, silently. */ significance?: number; /** * Which side of the significance cutoff is the significant one. * * `above` is the default because the transformed axes these charts usually * carry -- -log10(p) and its relatives -- put the interesting points at the * top. A **raw p axis runs the other way**: there, p <= 0.05 is the * finding, and a reading fixed to `above` would select precisely the points * that failed to reach significance and announce them as the result. * * That is not a degraded reading, it is the exact inverse of one, which is * why this is declarable rather than assumed. */ significanceDirection?: 'above' | 'below'; /** * The effect-size cutoff on the x axis, applied to its **magnitude** -- a * volcano is symmetric, and a fold change of -2 is as large an effect as * one of +2. */ effect?: number; } /** * Enumeration of supported plot trace types. * Use these values for the `type` field in {@link MaidrLayer}. * * @example * ```typescript * import { TraceType } from 'maidr/react'; * const layer = { id: '0', type: TraceType.BAR, ... }; * // Or use the string value directly: * const layer2 = { id: '0', type: 'bar', ... }; * ``` */ declare enum TraceType { /** * A filled band between a series and a baseline. Navigates exactly as * {@link TraceType.LINE} does — the fill is what the mark looks like, not * an extra magnitude — so several `AREA` series are read independently of * one another. Use {@link TraceType.STACKED_AREA} when the bands sit on * top of each other instead. */ AREA = "area", /** * Categories that stay put while a quantity is re-divided between them at * each step -- an alluvial diagram. The same weighted flow a * {@link TraceType.SANKEY} carries, drawn without a left-to-right budget. */ ALLUVIAL = "alluvial", BAR = "bar", /** * Rank over time, one line per competitor -- a bump chart. Navigated as a * multi-line layer, with the one difference that decides whether it reads * correctly: the y axis is a *rank*, so rank 1 is the best position and the * smallest number, and the pitch is inverted to match. Each point announces * the places gained or lost alongside the rank, since the overtake is what * the chart is drawn for. * * A slope graph of *values* is a {@link TraceType.LINE} layer with two * samples, not this. */ BUMP = "bump", BOX = "box", /** * A letter-value plot: the box plot's five-number summary generalised to a * variable-depth ladder of quantiles, so a large sample's tails stay * legible. Navigated as a box plot is -- one distribution per row, its * summary values walked along the other axis -- with the ladder read * outward from the median in value order, and each rung announced as the * percentile it actually is. */ BOXEN = "boxen", CANDLESTICK = "candlestick", /** * Virtual layer comparing candlestick OHLC fields against a reference * line (e.g. a moving average). Never declared in MAIDR JSON — created at * runtime by the candlestick delta feature (Alt+L to toggle, Ctrl+Shift+L * to pick the reference line). */ CANDLESTICK_DELTA = "candlestick_delta", /** * Flow between members of one set, drawn around a circle. Cyclic by * construction, so it has no stages -- and every ribbon still follows. */ CHORD = "chord", /** * Geographic regions shaded by a value. Read as a bar chart whose * categories happen to be places, it loses everything spatial: where the * high values sit, which way the gradient runs, and which borders the * value jumps across. */ CHOROPLETH = "choropleth", /** * A scalar field drawn as curves of constant value. Read as a * {@link TraceType.LINE} layer the level is just a series name, so the two * questions the chart is drawn for -- what value this curve is, and how * steeply the field changes here -- both go unanswered. */ CONTOUR = "contour", /** * Two series drawn back to back across a shared category axis, one growing * left and one growing right -- a population pyramid, or a Likert scale * split around a neutral midpoint. Navigated as a * {@link TraceType.STACKED} layer is, with the one difference that decides * whether it reads correctly: the values arrive **signed**, and the sign is * a direction rather than a magnitude, so the pitch takes the size and the * announcement names the side. */ DIVERGING = "diverging_bar", DODGED = "dodged_bar", /** * A category and a value drawn as a point rather than a bar -- a Cleveland * dot plot. Read exactly as a {@link TraceType.BAR} is; the two differ in * the mark, not in what a reader navigates, which is why this carries no * model of its own. It exists so the chart announces itself as the chart * the author drew. */ DOT = "dot", /** * Two values per category joined by a segment -- before and after, two * groups, two years. The gap is the message, so the trace announces the * change alongside each end rather than leaving the reader to subtract two * numbers they heard one at a time. */ DUMBBELL = "dumbbell", /** * An estimate with the interval drawn around it — an error bar, a * confidence interval, a point range. Navigated as a grid of * `[lower, value, upper]` against the samples, so the reader can move * between the three magnitudes at one x as readily as between samples. */ ERROR_BAR = "error_bar", /** * One effect estimate with its interval per study, against a shared null * line, with a pooled summary at the foot -- the standard figure of a * meta-analysis. Read as an {@link TraceType.ERROR_BAR} layer it loses the * three things it is drawn for: whether an interval crosses the null, how * much each study weighs, and which row is the pooled result rather than * evidence. */ FOREST = "forest", /** * Intervals along a shared axis, one lane per row -- a gantt chart, a * timeline, a swimlane diagram. Each point carries a start and an end * rather than a magnitude, so what the reader is told is a span and its * length, and where it sits is carried in the panning: a lane's intervals * sweep left to right with the axis, so later is audibly later. */ GANTT = "gantt", /** * A population shrinking across ordered stages. Navigated as a * {@link TraceType.BAR} layer is, with the one difference that decides * whether the chart is readable: the number a reader wants is the * **retention** between adjacent stages, not the count, so that is what the * pitch carries. The counts are announced alongside it. */ FUNNEL = "funnel", /** * A single measure read against a range -- a gauge, or a bullet chart with * its target and qualitative bands. One navigable point whose meaning is * entirely relational: 73 says nothing without the 100 it is out of, the 80 * it was aiming at, and the band it lands in. */ GAUGE = "gauge", HEATMAP = "heat", /** * Hexagonal binning: the standard answer to an overplotted scatter. Read as * a lattice of cells each carrying a count, which is a {@link * TraceType.HEATMAP} -- with the one difference that decides its * navigation: a hex lattice staggers alternate rows, so a column index does * not identify a position. A vertical move keeps the bin whose centre is * nearest in x, and the announcement gives the centre rather than the * indices. */ HEXBIN = "hexbin", HISTOGRAM = "hist", /** * The same hierarchy as a {@link TraceType.TREEMAP}, drawn as depth-ordered * bands rather than nested rectangles. The layout differs; the tree does * not, so it is read by the same trace. */ ICICLE = "icicle", LINE = "line", /** * A dot plot with a stem to the baseline. Read exactly as * {@link TraceType.DOT} and {@link TraceType.BAR} are -- the stem is what * the mark looks like, not a second magnitude. */ LOLLIPOP = "lollipop", /** * Genomic position against significance -- the standard figure of a GWAS. * Read as a {@link TraceType.SCATTER} it offers point-by-point navigation * over tens of thousands of points, which is not a viable path to the few * dozen that matter. */ MANHATTAN = "manhattan", /** * A stacked bar chart whose bar **widths** also encode data -- a two-way * contingency table drawn as tiles. Read as a {@link TraceType.STACKED} * layer it loses the width entirely, which is half the table: the * conditional proportions arrive without the group sizes they were * computed from. */ MOSAIC = "mosaic", /** * A node-link diagram: nodes joined by undirected links, laid out by a * force solver or similar. The same graph a {@link TraceType.SANKEY} * carries with the constraints relaxed -- no stages, no direction -- and * with degree in place of magnitude as the thing a reader is after. */ NETWORK = "network", NORMALIZED = "stacked_normalized_bar", /** {@link TraceType.STACKED_AREA} whose bands are shares of a common total. */ NORMALIZED_AREA = "stacked_normalized_area", /** * One polyline per observation across several axes, one axis per variable. * Navigated as a multi-line layer -- an observation per row, an axis per * column -- with the one difference that decides the chart: every column is * a different quantity, so a value is pitched against its OWN axis rather * than against one range for the layer. */ PARALLEL = "parallel_coordinates", PIE = "pie", /** * Categories arranged around a circle rather than along an axis, drawn as * wedges whose radius is the value -- a polar area, coxcomb or rose chart. * Read exactly as {@link TraceType.RADAR} is; the two differ in the mark, * not in what a reader navigates. */ POLAR_AREA = "polar_area", /** * Categories arranged around a circle rather than along an axis, joined * into a closed outline -- a radar or spider chart. Navigated as a * multi-line layer, with each spoke a column and each series a row; what * the circle adds is that a spoke's stereo position follows its angle * rather than its index, so a sweep goes out and comes back. */ RADAR = "radar", /** * One density curve per group along a shared value axis, the curves offset * down the page so their shapes can be compared. The offset is presentation * -- it exists so the curves do not overlap illegibly -- so a layer carries * each group's curve on its own terms and never the baseline it was drawn * from. Reading it as a {@link TraceType.VIOLIN_KDE} pitches every group * against a reference curve, which answers a different question than the * one a ridgeline is drawn to ask. */ RIDGELINE = "ridgeline", /** * Weighted flow between nodes, drawn as ribbons whose width is the * magnitude. The chart exists to show routing and proportion at once, which * is a question about topology -- and there is no partial reading of it * available on a grid, because the chart is a graph. */ SANKEY = "sankey", SCATTER = "point", SMOOTH = "smooth", /** * A scatter for data with ties, where several observations landing on one * coordinate are drawn as a single mark with that many petals. * * Read by {@link ScatterTrace}, over plain {@link ScatterPoint}s whose `z` * is how many observations are on the mark -- `z` being announced with its * axis label and driving the intensity, so the multiplicity is both spoken * and audible rather than a field the reader has to go looking for. * * Named apart from {@link TraceType.SCATTER} for a reason stronger than the * one {@link TraceType.TREE} gives. It is not only that "scatter plot" * names a chart nobody drew: a sunflower plot's **marks are not its * observations**. Sixty observations come back as twenty-one marks, because * coincident ones were collapsed -- which is the single fact the chart was * chosen to convey. A reader told "scatter" has been told the marks are the * data, and here they are not. */ SUNFLOWER = "sunflower", STACKED = "stacked_bar", /** * Area bands stacked on one another, so a band's *height* is its own * series' value while the band's *top edge* is the running total. Reading * such a layer as a {@link TraceType.LINE} announces one number where the * chart draws two, with nothing to say which one was heard — which is why * this is a type of its own rather than a line with a fill. */ STACKED_AREA = "stacked_area", STEP = "step", /** * A hierarchy drawn as nested rectangles whose area is a magnitude. It is * the first trace type that is not a flat grid: a node's address is its * depth and its position within that depth, and the arrow keys move between * parent, child and sibling rather than along rows and columns. */ TREEMAP = "treemap", /** * The same hierarchy as a {@link TraceType.TREEMAP}, drawn as boxes joined * by links rather than as nested areas. The tree does not differ and the * painting does, so it is read by the same trace and named apart only so * that the reader is told what is on the page: an organization chart * announced as a treemap is a chart type nobody drew. * * The magnitude is commonly absent here -- a reporting line has no size -- * which is the case {@link TreemapPoint.y} being optional exists for. */ TREE = "tree", /** * The same hierarchy as a {@link TraceType.TREEMAP}, drawn as circles * nested inside circles rather than as nested rectangles. Sized by value * like a treemap and navigated identically, and named apart for the reason * {@link TraceType.TREE} is: the reader is told which chart is on the page, * and a circle-packing diagram announced as a treemap is a chart type * nobody drew. */ PACK = "pack", /** * The same hierarchy as a {@link TraceType.TREEMAP}, drawn as rings around * a centre rather than as nested rectangles. The layout differs and the * tree does not, so it is read by the same trace -- with one thing of its * own: the rings are angular, so the sound is panned around the dial the * way a pie's is, and sweeping a ring goes out and comes back. */ SUNBURST = "sunburst", /** * A Kaplan-Meier survival curve: the probability of surviving past each * time, dropping in steps as events occur. Read as a {@link TraceType.STEP} * layer it loses the two facts the figure is drawn for -- the median * survival, which is the number most readers came for, and which times are * censored rather than events. */ SURVIVAL = "survival", VIOLIN_BOX = "violin_box", VIOLIN_KDE = "violin_kde", /** * Effect size against significance -- the standard figure of a differential * expression analysis. Read as a {@link TraceType.SCATTER} it announces the * two coordinates and withholds the point's identity, which is the payload. */ VOLCANO = "volcano", /** * A sequence of signed contributions carrying a starting value to an ending * one — the staple of financial and product reporting. Each step draws a * floating bar from its running total before to its running total after, so * the point carries both the contribution and the total it produced. */ WATERFALL = "waterfall", /** * Terms sized by weight. The layout carries no information -- it is chosen * to pack glyphs, not to encode anything -- so the trace reads it as what * it measures: a term and a magnitude, walked in weight order. */ WORD_CLOUD = "word_cloud" } /** * One node of a treemap, or of any other hierarchy drawn as area. * * The hierarchy is declared as a **path** rather than as a parent pointer. A * path is acyclic by construction and cannot dangle: there is no id to point * at a node that was never emitted, and no way to author a cycle. Every * producer has one -- a `d3.hierarchy` walk yields it directly, and Plotly's * `labels`/`parents` pair resolves to it -- and it doubles as the breadcrumb * the reader is told when they are several levels down. * * Interior nodes need not be declared. A layer emitting only its leaves -- * which is what a treemap draws -- gets its interior nodes and their totals * derived from the paths. * * @example * // A leaf three levels down, with its two ancestors named. * { x: 'France', y: 67.4, path: ['World', 'Europe'] } */ declare interface TreemapPoint { /** What the node is called. Unique among its siblings, not chart-wide. */ x: string | number; /** * The node's magnitude. * * Omitted for an interior node whose value is the sum of its children, * which is the ordinary case. A declared value is kept even where it * disagrees with that sum: a parent may carry mass no child accounts for, * and overwriting it would be inventing data. */ y?: number; /** * The node's ancestors, root first, **excluding the node itself**. * * A top-level node omits it or declares `[]`. */ path?: (string | number)[]; } /** * Data point for violin KDE (kernel density estimation) curves. * Library-agnostic — no SVG coordinates embedded in data. * The density field falls back to width if absent. */ declare interface ViolinKdePoint { /** Categorical label for the violin (e.g., "setosa") */ x: string | number; /** Position along the density axis */ y: number; /** KDE density value at this point. Falls back to `width` if absent. */ density?: number; /** Half-width of the violin at this Y level (used as density fallback) */ width?: number; /** SVG viewport x-coordinate for highlight positioning (provided by backend) */ svg_x?: number; /** SVG viewport y-coordinate for highlight positioning (provided by backend) */ svg_y?: number; } /** * Configuration options for violin plot display. * Controls which summary statistics are shown in the violin box overlay. * Sent from the Python backend alongside violin_kde and violin_box layers. */ declare interface ViolinOptions { /** Show median line marker. Default: true */ showMedian?: boolean; /** Show mean value marker. Default: false */ showMean?: boolean; /** Show extrema (min/max) markers. Default: true */ showExtrema?: boolean; } /** * Effect size against significance — the standard figure of a differential * expression analysis. * * The same chart as a {@link ManhattanDeclaration}, read the same way and * accepting the same fields: `label` names the gene the way it names the SNP, * and `significance` is the same cutoff on the same axis. What a volcano adds * is the **second** cutoff — its x is an effect size rather than a position, * so a point is a finding only when it clears both. */ export declare interface VolcanoDeclaration extends Omit { /** `TraceType.VOLCANO` — the string `'volcano'`. */ type: TraceType.VOLCANO; /** * Absorb following undeclared siblings of the same drawn kind, as * {@link ManhattanDeclaration.merge} does. * * Off by default, the other way round from a Manhattan: a volcano's sibling * series are usually up-regulated, down-regulated and unchanged — three * things a reader wants told apart, not one cloud. * * @default false */ merge?: boolean; } /** * One point of a volcano or Manhattan plot. * * Both are scatters read almost entirely through a threshold: a volcano puts * effect size against significance, a Manhattan puts genomic position against * it. They routinely carry tens of thousands of points of which a few dozen * matter, so the question is never "what is at this coordinate" -- it is * "which points cross the line, and what are they called". */ declare interface VolcanoPoint extends ScatterPoint { /** * The region the point belongs to -- a chromosome on a Manhattan plot. * * Announced alongside the point, because "which chromosome is it on" is * the second question every one of these charts is read for. */ group?: string; } /** * What a waterfall step does to the running total. * * `total` marks a step that restates the running total rather than changing * it — the opening and closing bars, and any subtotal drawn along the way. * Those sit on the baseline instead of floating, and a reader told a subtotal * "rose by 950" would be hearing a contribution the chart never made. */ declare type WaterfallKind = 'increase' | 'decrease' | 'total'; /** * One step of a waterfall chart. * * A waterfall answers "how did we get from here to there", so a step carries * two numbers that a bar chart would conflate: the contribution it made * (`delta`) and the running total it produced (`end`). The bar is drawn * floating between `start` and `end`, which is why neither alone describes it * — the height is the contribution and the position is the total. * * `start` and `end` are absolute positions on the value axis, so a producer * that only knows offsets has to accumulate them before emitting, the same * way {@link ErrorBarPoint} fixes absolute bounds. */ declare interface WaterfallPoint { /** The step's label along the category axis. */ x: number | string; /** Running total before this step. */ start: number; /** Running total after this step. */ end: number; /** * The signed contribution, `end - start`. * * Carried rather than derived because a producer may round the two totals * for display, and a delta recomputed from rounded ends is not the number * the chart's own label shows. */ delta: number; /** Whether the step adds, subtracts, or restates the total. */ kind: WaterfallKind; } /** * One term of a word cloud. * * A word cloud is the canonical chart that carries real data while being * readable only by eye: the weight is encoded as glyph size and written down * nowhere on the page. Structurally it is a categorical label and a * magnitude, which is why it needs no shape of its own beyond naming them. */ declare interface WordCloudPoint { /** The term. */ x: string; /** * Its weight -- a frequency, a score, a count. * * Widened to accept a string for the same reason {@link BarPoint.y} is: * hand-authored JSON and some producers send numbers as strings, and the * trace coerces on the way in. Declaring it `number` alone would not stop * one arriving, it would only stop the compiler from admitting it -- and a * string reaching the description's running total would concatenate rather * than add. */ y: number | string; } export { }