Skip to content

Commit 02731fb

Browse files
Filmbostock
andauthored
document basic transforms, initializers, valueof… (#1369)
* document basic transforms, initializers, valueof… Removes the FilterFunction type * fancier valueof typing * edits * edits --------- Co-authored-by: Mike Bostock <[email protected]>
1 parent 61ae5f3 commit 02731fb

File tree

2 files changed

+160
-12
lines changed

2 files changed

+160
-12
lines changed

src/options.d.ts

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,43 @@
11
import type {ChannelTransform, ChannelValue} from "./channel.js";
22
import type {Data} from "./mark.js";
33

4-
export function valueof(data: Data | null, value: ChannelValue | null, type?: any): any[] | null;
4+
/** Array, Float32Array, etc. */
5+
type ArrayishConstructor = (new (...args: any) => any) & {from: (data: Data) => Iterable<any> & ArrayLike<any>};
56

7+
/**
8+
* Given some *data* and a channel *value* definition (such as a field name or
9+
* function accessor), returns an array of the specified *type* containing the
10+
* corresponding values derived from *data*. If *type* is not specified, it
11+
* defaults to Array; otherwise it must be an Array or TypedArray subclass.
12+
*
13+
* The returned array is not guaranteed to be new; when the *value* is a channel
14+
* transform or an array that is an instance of the given *type*, the array may
15+
* be returned as-is without making a copy.
16+
*/
17+
export function valueof(data: Data | null, value: ChannelValue | null, type?: ArrayConstructor): any[] | null;
18+
export function valueof<T extends ArrayishConstructor>(data: Data | null, value: ChannelValue | null, type: T): InstanceType<T> | null; // prettier-ignore
19+
20+
/**
21+
* Returns a [*column*, *setColumn*] helper for deriving columns; *column* is a
22+
* channel transform that returns whatever value was most recently passed to
23+
* *setColumn*. If *setColumn* is not called, then the channel transform returns
24+
* undefined.
25+
*
26+
* If a *source* is specified, then *column*.label exposes the given *source*’s
27+
* label, if any: if *source* is a string as when representing a named field of
28+
* data, then *column*.label is *source*; otherwise *column*.label propagates
29+
* *source*.label. This allows derived columns to propagate a human-readable
30+
* axis or legend label.
31+
*/
632
export function column(source?: any): [ChannelTransform, <T>(value: T) => T];
733

34+
/**
35+
* A channel transform that returns the data as-is, avoiding an extra copy when
36+
* defining a channel as being equal to the data. For example, to re-use the
37+
* given *data* for the **fill** channel:
38+
*
39+
* ```js
40+
* Plot.raster(data, {width: 300, height: 200, fill: Plot.identity})
41+
* ```
42+
*/
843
export const identity: ChannelTransform;

src/transforms/basic.d.ts

Lines changed: 124 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,39 @@ import type {Context} from "../context.js";
33
import type {Dimensions} from "../dimensions.js";
44
import type {ScaleFunctions} from "../scales.js";
55

6+
/**
7+
* A mark transform function is passed the mark’s *data* and a nested index into
8+
* the data, *facets*. The transform function returns new mark data and facets;
9+
* the returned **data** defaults to the passed *data*, and the returned
10+
* **facets** defaults to the passed *facets*. The mark is the *this* context.
11+
* Transform functions can also trigger side-effects, say to populate
12+
* lazily-derived columns; see also Plot.column.
13+
*/
614
export type TransformFunction = (data: any[], facets: number[][]) => {data?: any[]; facets?: number[][]};
715

16+
/**
17+
* A mark initializer function is passed the mark’s (possibly transformed)
18+
* *data*, a nested index into the data, *facets*, and the mark’s initialized
19+
* *channels*, along with the plot’s *scales*, *dimensions*, and *context*. The
20+
* initializer function returns new mark data, facets, and channels; the
21+
* returned **data** defaults to the passed *data*, the returned **facets**
22+
* defaults to the passed *facets*, and the returned **channels** are merged
23+
* with the passed channels, replacing channels of the same name. The mark
24+
* itself is the *this* context.
25+
*
26+
* Whereas a mark transform operates in abstract data space on channel values
27+
* prior to scale application, a mark initializer runs after the (initial)
28+
* scales are constructed and hence can operate in screen space, such as pixel
29+
* coordinates and colors. For example, an initializer can adjust a mark’s
30+
* positions to avoid occlusion.
31+
*
32+
* If any of the returned derived channels are bound to scales, the associated
33+
* scales will be re-initialized. To avoid a circular dependency, mark
34+
* initializer functions cannot re-initialize position scales (*x*, *y*, *fx*,
35+
* and *fy*). If an initializer desires a channel not supported by the
36+
* downstream mark, additional channels can be declared using the mark
37+
* **channels** option.
38+
*/
839
export type InitializerFunction = (
940
data: any[],
1041
facets: number[][],
@@ -18,30 +49,112 @@ export type InitializerFunction = (
1849
channels?: Channels;
1950
};
2051

21-
export type FilterFunction = (d: any, i: number) => boolean;
22-
52+
/**
53+
* Compares the two values *a* and *b*, returning a negative number if *a* is
54+
* considered less than *b*, a positive number if *a* is considered greater than
55+
* *b*, or zero if *a* and *b* are considered equal.
56+
*/
2357
export type CompareFunction = (a: any, b: any) => number;
2458

59+
/** Mark options with a mark transform. */
2560
export type Transformed<T> = T & {transform: TransformFunction};
2661

62+
/** Mark options with a mark initializer. */
2763
export type Initialized<T> = T & {initializer: InitializerFunction};
2864

65+
/**
66+
* Given an *options* object that may specify some basic transforms (**filter**,
67+
* **sort**, or **reverse**) or a custom **transform**, composes those
68+
* transforms with the given *transform* function, returning a new *options*
69+
* object.
70+
*
71+
* If a custom **transform** is present on the given *options*, any basic
72+
* transforms are ignored. Any additional input *options* are passed through in
73+
* the returned *options* object. This method facilitates applying basic
74+
* transforms prior to applying the given *transform* and is used internally by
75+
* Plot’s built-in transforms.
76+
*
77+
* The given *transform* runs after the existing transforms in *options*. Throws
78+
* an error if the given *options* define an **initializer**, since mark
79+
* transforms must run before mark initializers.
80+
*/
2981
export function transform<T>(options: T, transform: TransformFunction): Transformed<T>;
3082

83+
/**
84+
* Given an *options* object that may specify some basic initializers
85+
* (**filter**, **sort**, or **reverse**) or a custom **initializer**, composes
86+
* those initializers with the given *initializer* function, returning a new
87+
* *options* object.
88+
*
89+
* If a custom **initializer** is present on the given *options*, any basic
90+
* initializers are ignored. Any additional input *options* are passed through
91+
* in the returned *options* object. This method facilitates applying basic
92+
* initializers prior to applying the given *initializer* and is used internally
93+
* by Plot’s built-in initializers.
94+
*
95+
* If the given *initializer* does not need to operate in screen space (after
96+
* scale application), it should instead be implemented as a mark transform for
97+
* simplicity; see Plot.transform.
98+
*/
3199
export function initializer<T>(options: T, initializer: InitializerFunction): Initialized<T>;
32100

33-
export function filter<T>(test: FilterFunction, options?: T): Transformed<T>;
101+
/**
102+
* Applies a transform to *options* to filter the mark’s index according to the
103+
* given *test*, which can be a function (receiving the datum *d* and index *i*)
104+
* or a channel value definition such as a field name; only truthy values are
105+
* retained in the index. For example, to show only data whose body mass is
106+
* greater than 3,000g:
107+
*
108+
* ```js
109+
* Plot.filter((d) => d.body_mass_g > 3000, options)
110+
* ```
111+
*
112+
* Note that filtering only affects the rendered mark index, not the associated
113+
* channel values, and thus has no effect on imputed scale domains.
114+
*/
115+
export function filter<T>(test: ChannelValue, options?: T): Transformed<T>;
34116

117+
/**
118+
* Applies a transform to *options* to reverse the order of the mark’s index,
119+
* say for reverse input order.
120+
*/
35121
export function reverse<T>(options?: T): Transformed<T>;
36122

37-
export function shuffle<T>(options?: T): Transformed<T>;
38-
39-
export interface SortOrderOptions {
40-
channel?: ChannelName;
41-
value?: ChannelValue;
42-
order?: CompareFunction | "ascending" | "descending";
43-
}
123+
/**
124+
* Applies a transform to *options* to randomly shuffles the mark’s index. If a
125+
* **seed** is specified, a linear congruential generator with the given seed is
126+
* used to generate random numbers deterministically; otherwise, Math.random is
127+
* used.
128+
*/
129+
export function shuffle<T>(options?: T & {seed?: number}): Transformed<T>;
44130

45-
export type SortOrder = CompareFunction | ChannelValue | SortOrderOptions;
131+
/**
132+
* How to order values; one of:
133+
*
134+
* - a function for comparing data, returning a signed number
135+
* - a channel value definition for sorting given values in ascending order
136+
* - a {value, order} object for sorting given values
137+
* - a {channel, order} object for sorting the named channel’s values
138+
*/
139+
export type SortOrder =
140+
| CompareFunction
141+
| ChannelValue
142+
| {value?: ChannelValue; order?: CompareFunction | "ascending" | "descending"}
143+
| {channel?: ChannelName; order?: CompareFunction | "ascending" | "descending"};
46144

145+
/**
146+
* Applies a transform to *options* to sort the mark’s index by the specified
147+
* *order*. The *order* is one of:
148+
*
149+
* - a function for comparing data, returning a signed number
150+
* - a channel value definition for sorting given values in ascending order
151+
* - a {value, order} object for sorting given values
152+
* - a {channel, order} object for sorting the named channel’s values
153+
*
154+
* For example, to render marks in order of ascending body mass:
155+
*
156+
* ```js
157+
* Plot.sort("body_mass_g", options)
158+
* ```
159+
*/
47160
export function sort<T>(order: SortOrder, options?: T): Transformed<T>;

0 commit comments

Comments
 (0)