diff --git a/README.md b/README.md index ada8ff287f..ccbdf16f59 100644 --- a/README.md +++ b/README.md @@ -2557,9 +2557,11 @@ The following **order** methods are supported: - null (default) - input order - *value* - ascending value order (or descending with **reverse**) +- *x* - alias of *value*; for stackX only +- *y* - alias of *value*; for stackY only - *sum* - order series by their total value - *appearance* - order series by the position of their maximum value -- *inside-out* - order the earliest-appearing series on the inside +- *inside-out* (default with *wiggle*) - order the earliest-appearing series on the inside - a named field or function of data - order data by priority - an array of *z* values @@ -2570,8 +2572,8 @@ The stack transform supports diverging stacks: negative values are stacked below After all values have been stacked from zero, an optional **offset** can be applied to translate or scale the stacks. The following **offset** methods are supported: - null (default) - a zero baseline -- *expand* (or *normalize*) - rescale each stack to fill [0, 1] -- *center* (or *silhouette*) - align the centers of all stacks +- *normalize* - rescale each stack to fill [0, 1] +- *center* - align the centers of all stacks - *wiggle* - translate stacks to minimize apparent movement - a function to be passed a nested index, and start, end, and *z* values diff --git a/src/transforms/stack.d.ts b/src/transforms/stack.d.ts index 73c48733d3..45b7413e8d 100644 --- a/src/transforms/stack.d.ts +++ b/src/transforms/stack.d.ts @@ -8,45 +8,120 @@ export type StackOffsetName = | ("expand" & Record) // deprecated; use normalize | ("silhouette" & Record); // deprecated; use center -export type StackOffsetFunction = (stacks: number[][][], y1: number[], y2: number[], z: any[]) => void; +export type StackOffsetFunction = (index: number[][][], y1: number[], y2: number[], z: any[]) => void; +/** How the baseline of stacked layers may be offset. */ export type StackOffset = StackOffsetName | StackOffsetFunction; export type StackOrderName = "value" | "x" | "y" | "z" | "sum" | "appearance" | "inside-out"; +/** How to order layers prior to stacking. */ export type StackOrder = | StackOrderName | (string & Record) // field name; see also https://github.com/microsoft/TypeScript/issues/29729 | ((d: any, i: number) => any) // function of data | any[]; // explicit ordinal values +/** Options for the stack transform. */ export interface StackOptions { + /** + * After all values have been stacked from zero, an optional **offset** can be + * applied to translate or scale the stacks: + * + * - null (default) - a zero baseline + * - *normalize* - rescale each stack to fill [0, 1] + * - *center* - align the centers of all stacks + * - *wiggle* - translate stacks to minimize apparent movement + * - a function to be passed a nested index, and start, end, and *z* values + * + * If a given stack has zero total value, the *expand* offset will not adjust + * the stack’s position. Both the *center* and *wiggle* offsets ensure that + * the lowest element across stacks starts at zero for better default axes. + * The *wiggle* offset is recommended for streamgraphs, and if used, changes + * the default **order** to *inside-out*. + * + * For details on the *wiggle* offset, see [Byron & Wattenberg](http://leebyron.com/streamgraph/). + */ offset?: StackOffset | null; + + /** + * The order in which stacks are layered: + * + * - null (default) - input order + * - *value* - ascending value (or descending with **reverse**) + * - *x* - alias of *value*; for stackX only + * - *y* - alias of *value*; for stackY only + * - *sum* - total value per series + * - *appearance* - position of maximum value per series + * - *inside-out* (default with *wiggle*) - order the earliest-appearing series on the inside + * - a named field or function of data - natural order + * - an array enumerating all the *z* values in the desired order + * + * For details on the *inside-out* order, see [Byron & Wattenberg](http://leebyron.com/streamgraph/). + */ order?: StackOrder | null; + + /** If true, reverse the effective order of the stacks. */ reverse?: boolean; + + /** + * The *z* channel defines the series of each value in the stack. Used when + * the **order** is *sum*, *appearance*, *inside-out*, or an explicit array of + * *z* values. + */ z?: ChannelValue; } +/** + * Transforms a length channel *x* into starting and ending position channels + * *x1* and *x2* by “stacking” elements that share a given *y* position. The + * starting position of each element equals the ending position of the preceding + * element in the stack. Non-positive values are stacked to the left of zero, + * with *x2* to the left of *x1*. A new *x* channel is derived that represents + * the midpoint between *x1* and *x2*, for example to place a label. If not + * specified, the input channel *x* defaults to the constant one. + */ export function stackX(options?: T & StackOptions): Transformed; - export function stackX(stackOptions?: StackOptions, options?: T): Transformed; +/** + * Like **stackX**, but returns the starting position *x1* as the *x* channel, + * for example to position a dot on the left-hand side of each element of a + * stack. + */ export function stackX1(options?: T & StackOptions): Transformed; - export function stackX1(stackOptions?: StackOptions, options?: T): Transformed; +/** + * Like **stackX**, but returns the starting position *x2* as the *x* channel, + * for example to position a dot on the right-hand side of each element of a + * stack. + */ export function stackX2(options?: T & StackOptions): Transformed; - export function stackX2(stackOptions?: StackOptions, options?: T): Transformed; +/** + * Transforms a length channel *y* into starting and ending position channels + * *y1* and *y2* by “stacking” elements that share a given *x* position. The + * starting position of each element equals the ending position of the preceding + * element in the stack. Non-positive values are stacked below zero, with *y2* + * below *y1*. A new *y* channel is derived that represents the midpoint between + * *y1* and *y2*, for example to place a label. If not specified, the input + * channel *y* defaults to the constant one. + */ export function stackY(options?: T & StackOptions): Transformed; - export function stackY(stackOptions?: StackOptions, options?: T): Transformed; +/** + * Like **stackY**, but returns the starting position *y1* as the *y* channel, + * for example to position a dot at the bottom of each element of a stack. + */ export function stackY1(options?: T & StackOptions): Transformed; - export function stackY1(stackOptions?: StackOptions, options?: T): Transformed; +/** + * Like **stackY**, but returns the ending position *y2* as the *y* channel, + * for example to position a dot at the top of each element of a stack. + */ export function stackY2(options?: T & StackOptions): Transformed; - export function stackY2(stackOptions?: StackOptions, options?: T): Transformed; diff --git a/test/plots/industry-unemployment-share.ts b/test/plots/industry-unemployment-share.ts index fd454cbd31..edfea6f2b5 100644 --- a/test/plots/industry-unemployment-share.ts +++ b/test/plots/industry-unemployment-share.ts @@ -15,7 +15,7 @@ export async function industryUnemploymentShare() { x: "date", y: "unemployed", fill: "industry", - offset: "expand", + offset: "normalize", title: "industry" }) ), diff --git a/test/plots/stacked-bar.ts b/test/plots/stacked-bar.ts index 9cb6f7af80..b4b6df65d2 100644 --- a/test/plots/stacked-bar.ts +++ b/test/plots/stacked-bar.ts @@ -12,7 +12,7 @@ export async function stackedBar() { x: (d, i) => i, fill: (d, i) => i, insetLeft: 1, - offset: "expand" + offset: "normalize" }) ) ] diff --git a/test/plots/stacked-rect.ts b/test/plots/stacked-rect.ts index fd491f9bc9..00d07e8de8 100644 --- a/test/plots/stacked-rect.ts +++ b/test/plots/stacked-rect.ts @@ -12,7 +12,7 @@ export async function stackedRect() { x: (d, i) => i, fill: (d, i) => i, insetLeft: 1, - offset: "expand" + offset: "normalize" } ) ]