Skip to content

Commit 29390e6

Browse files
Filmbostock
andauthored
document axis (#1403)
* axis, save point * a bit more * 😅 save point * suggest textOverflow * document axes * documents axes * remove unsupported options; add exports * avoid duplicating scale options * edits * edits * edits --------- Co-authored-by: Mike Bostock <[email protected]>
1 parent f469f7f commit 29390e6

File tree

3 files changed

+210
-53
lines changed

3 files changed

+210
-53
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1091,7 +1091,7 @@ The axis mark’s default margins depend on its orientation (**anchor**) as foll
10911091
* *bottom* - 0, 20, 30, 20
10921092
* *left* - 20, 0, 20, 40
10931093
1094-
For simplicity’s sake and for consistent layout across plots, axis margins are not automatically sized to make room for tick labels; instead, shorten your tick labels (for example using the *k* SI-prefix tick format, or setting a *scale*.transform to show thousands or millions, or setting the **lineWidth** option to wrap long labels) or increase the margins as needed.
1094+
For simplicity’s sake and for consistent layout across plots, axis margins are not automatically sized to make room for tick labels; instead, shorten your tick labels (for example using the *k* SI-prefix tick format, or setting a *scale*.transform to show thousands or millions, or setting the **textOverflow** option to *ellipsis* and the **lineWidth** option to clip long labels) or increase the margins as needed.
10951095
10961096
#### Plot.axisX(*data*, *options*)
10971097

src/marks/axis.d.ts

+181-42
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,209 @@
1-
import type {CompoundMark, Data, MarkOptions, RenderableMark} from "../mark.js";
1+
import type {CompoundMark, Data, MarkOptions} from "../mark.js";
22
import type {ScaleOptions} from "../scales.js";
3-
import type {RuleXOptions, RuleYOptions} from "./rule.js";
3+
import type {RuleX, RuleXOptions, RuleY, RuleYOptions} from "./rule.js";
44
import type {TextOptions} from "./text.js";
55
import type {TickXOptions, TickYOptions} from "./tick.js";
66

7-
export type AxisAnchor = "top" | "right" | "bottom" | "left";
8-
9-
interface GridOptions {
10-
anchor?: AxisAnchor;
11-
interval?: ScaleOptions["interval"];
12-
ticks?: ScaleOptions["ticks"];
13-
tickSpacing?: ScaleOptions["tickSpacing"];
7+
/** The subset of scale options for grids. */
8+
type GridScaleOptions = Pick<ScaleOptions, "interval" | "ticks" | "tickSpacing">;
9+
10+
/** The subset of scale options for axes. */
11+
type AxisScaleOptions = Pick<ScaleOptions, "tickSize" | "tickPadding" | "tickFormat" | "tickRotate" | "label" | "labelOffset" | "labelAnchor">; // prettier-ignore
12+
13+
/** Options for the grid marks. */
14+
export interface GridOptions extends GridScaleOptions {
15+
/**
16+
* The side of the frame on which to place the axis: *top* or *bottom* for
17+
* horizontal axes (axisX and axisFx) and their associated vertical grids
18+
* (gridX and gridFx), or *left* or *right* for vertical axes (axisY and
19+
* axisFY) and their associated horizontal grids (gridY and gridFy).
20+
*
21+
* The default **anchor** depends on the associated scale:
22+
*
23+
* - *x* - *bottom*
24+
* - *y* - *left*
25+
* - *fx* - *top* if there is a *bottom* *x* axis, and otherwise *bottom*
26+
* - *fy* - *right* if there is a *left* *y* axis, and otherwise *right*
27+
*
28+
* For grids, the **anchor** also affects the extent of grid lines when the
29+
* opposite dimension is specified (**x** for gridY and **y** for gridX). For
30+
* example, to draw a horizontal gridY between the *right* edge of the frame
31+
* and the specified **x** value:
32+
*
33+
* ```js
34+
* Plot.gridY({x: (y) => aapl.find((d) => d.Close >= y)?.Date, anchor: "right"})
35+
* ```
36+
*/
37+
anchor?: "top" | "right" | "bottom" | "left";
38+
39+
/**
40+
* A shorthand for setting both **fill** and **stroke**; affects the stroke of
41+
* tick vectors and grid rules, and the fill of tick texts and axis label
42+
* texts; defaults to *currentColor*.
43+
*/
1444
color?: MarkOptions["stroke"];
45+
46+
/**
47+
* A shorthand for setting both **fillOpacity** and **strokeOpacity**; affects
48+
* the stroke opacity of tick vectors and grid rules, and the fill opacity of
49+
* tick texts and axis label texts; defaults to 1 for axes and 0.1 for grids.
50+
*/
51+
opacity?: MarkOptions["opacity"];
1552
}
1653

17-
interface AxisOptions extends GridOptions, MarkOptions, TextOptions {
18-
tickSize?: ScaleOptions["tickSize"];
19-
tickPadding?: ScaleOptions["tickPadding"];
20-
tickFormat?: ScaleOptions["tickFormat"];
21-
tickRotate?: ScaleOptions["tickRotate"];
22-
grid?: ScaleOptions["grid"];
23-
line?: ScaleOptions["line"];
24-
label?: ScaleOptions["label"];
25-
labelOffset?: ScaleOptions["labelOffset"];
26-
labelAnchor?: ScaleOptions["labelAnchor"];
54+
/** Options for the axis marks. */
55+
export interface AxisOptions extends GridOptions, MarkOptions, TextOptions, AxisScaleOptions {
56+
/** The tick text **stroke**, say for a *white* outline to improve legibility; defaults to null. */
2757
textStroke?: MarkOptions["stroke"];
58+
/** The tick text **strokeOpacity**; defaults to 1; has no effect unless **textStroke** is set. */
2859
textStrokeOpacity?: MarkOptions["strokeOpacity"];
60+
/** The tick text **strokeWidth**; defaults to 4; has no effect unless **textStroke** is set. */
2961
textStrokeWidth?: MarkOptions["strokeWidth"];
3062
}
3163

64+
/** Options for the axisX and axisFx marks. */
3265
export interface AxisXOptions extends AxisOptions, TickXOptions {}
3366

67+
/** Options for the axisY and axisFy marks. */
3468
export interface AxisYOptions extends AxisOptions, TickYOptions {}
3569

70+
/** Options for the gridX and gridFx marks. */
3671
export interface GridXOptions extends GridOptions, Omit<RuleXOptions, "interval"> {}
3772

73+
/** Options for the gridY and gridFy marks. */
3874
export interface GridYOptions extends GridOptions, Omit<RuleYOptions, "interval"> {}
3975

40-
export function axisY(options?: AxisYOptions): CompoundMark;
41-
76+
/**
77+
* Returns a new compound axis mark to document the visual encoding of the
78+
* vertical position *y* scale, comprised of (up to) three marks: a vector for
79+
* ticks, a text for tick labels, and another text for an axis label. The *data*
80+
* defaults to tick values sampled from the *y* scale’s domain; if desired,
81+
* specify the axis mark’s *data* explicitly, or use one of the **ticks**,
82+
* **tickSpacing**, or **interval** options.
83+
*
84+
* The **facetAnchor** option defaults to *right-empty* if **anchor** is
85+
* *right*, and *left-empty* if **anchor** is *left*. The default margins
86+
* likewise depend on **anchor** as follows; in order of **marginTop**,
87+
* **marginRight**, **marginBottom**, and **marginLeft**, in pixels:
88+
*
89+
* - *right* - 20, 40, 20, 0
90+
* - *left* - 20, 0, 20, 40
91+
*
92+
* For simplicity, and for consistent layout across plots, default axis margins
93+
* are not affected by tick labels. If tick labels are too long, either increase
94+
* the margin or shorten the labels: use the *k* SI-prefix tick format; use the
95+
* **transform** *y*-scale option to show thousands or millions; or use the
96+
* **textOverflow** and **lineWidth** options to clip.
97+
*/
4298
export function axisY(data?: Data, options?: AxisYOptions): CompoundMark;
99+
export function axisY(options?: AxisYOptions): CompoundMark;
43100

44-
export function axisFy(options?: AxisYOptions): CompoundMark;
45-
101+
/**
102+
* Returns a new compound axis mark to document the visual encoding of the
103+
* vertical facet position *fy* scale, comprised of (up to) three marks: a
104+
* vector for ticks, a text for tick labels, and another text for an axis label.
105+
* The *data* defaults to the *fy* scale’s domain; if desired, specify the axis
106+
* mark’s *data* explicitly, or use one of the **ticks**, **tickSpacing**, or
107+
* **interval** options.
108+
*
109+
* The **facetAnchor** option defaults to *right-empty* if **anchor** is
110+
* *right*, and *left-empty* if **anchor** is *left*. The default margins
111+
* likewise depend on **anchor** as follows; in order of **marginTop**,
112+
* **marginRight**, **marginBottom**, and **marginLeft**, in pixels:
113+
*
114+
* - *right* - 20, 40, 20, 0
115+
* - *left* - 20, 0, 20, 40
116+
*
117+
* For simplicity, and for consistent layout across plots, default axis margins
118+
* are not affected by tick labels. If tick labels are too long, either increase
119+
* the margin or shorten the labels, say by using the **textOverflow** and
120+
* **lineWidth** options to clip.
121+
*/
46122
export function axisFy(data?: Data, options?: AxisYOptions): CompoundMark;
123+
export function axisFy(options?: AxisYOptions): CompoundMark;
47124

48-
export function axisX(options?: AxisXOptions): CompoundMark;
49-
125+
/**
126+
* Returns a new compound axis mark to document the visual encoding of the
127+
* horizontal position *x* scale, comprised of (up to) three marks: a vector for
128+
* ticks, a text for tick labels, and another text for an axis label. The *data*
129+
* defaults to tick values sampled from the *x* scale’s domain; if desired,
130+
* specify the axis mark’s *data* explicitly, or use one of the **ticks**,
131+
* **tickSpacing**, or **interval** options.
132+
*
133+
* The **facetAnchor** option defaults to *bottom-empty* if **anchor** is
134+
* *bottom*, and *top-empty* if **anchor** is *top*. The default margins
135+
* likewise depend on **anchor** as follows; in order of **marginTop**,
136+
* **marginRight**, **marginBottom**, and **marginLeft**, in pixels:
137+
*
138+
* - *top* - 30, 20, 0, 20
139+
* - *bottom* - 0, 20, 30, 20
140+
*
141+
* For simplicity, and for consistent layout across plots, default axis margins
142+
* are not affected by tick labels. If tick labels are too long, either increase
143+
* the margin or shorten the labels: use the *k* SI-prefix tick format; use the
144+
* **transform** *x*-scale option to show thousands or millions; or use the
145+
* **textOverflow** and **lineWidth** options to clip; or use the **tickRotate**
146+
* option to rotate.
147+
*/
50148
export function axisX(data?: Data, options?: AxisXOptions): CompoundMark;
149+
export function axisX(options?: AxisXOptions): CompoundMark;
51150

52-
export function axisFx(options?: AxisXOptions): CompoundMark;
53-
151+
/**
152+
* Returns a new compound axis mark to document the visual encoding of the
153+
* horizontal facet position *fx* scale, comprised of (up to) three marks: a
154+
* vector for ticks, a text for tick labels, and another text for an axis label.
155+
* The *data* defaults to the *fx* scale’s domain; if desired, specify the axis
156+
* mark’s *data* explicitly, or use one of the **ticks**, **tickSpacing**, or
157+
* **interval** options.
158+
*
159+
* The **facetAnchor** and **frameAnchor** options defaults to **anchor**. The
160+
* default margins likewise depend on **anchor** as follows; in order of
161+
* **marginTop**, **marginRight**, **marginBottom**, and **marginLeft**, in
162+
* pixels:
163+
*
164+
* - *top* - 30, 20, 0, 20
165+
* - *bottom* - 0, 20, 30, 20
166+
*
167+
* For simplicity, and for consistent layout across plots, default axis margins
168+
* are not affected by tick labels. If tick labels are too long, either increase
169+
* the margin or shorten the labels, say by using the **textOverflow** and
170+
* **lineWidth** options to clip, or using the **tickRotate** option to rotate.
171+
*/
54172
export function axisFx(data?: Data, options?: AxisXOptions): CompoundMark;
173+
export function axisFx(options?: AxisXOptions): CompoundMark;
55174

56-
export function gridY(options?: GridYOptions): RenderableMark;
57-
58-
export function gridY(data?: Data, options?: GridYOptions): RenderableMark;
59-
60-
export function gridFy(options?: GridYOptions): RenderableMark;
61-
62-
export function gridFy(data?: Data, options?: GridYOptions): RenderableMark;
63-
64-
export function gridX(options?: GridXOptions): RenderableMark;
65-
66-
export function gridX(data?: Data, options?: GridXOptions): RenderableMark;
67-
68-
export function gridFx(options?: GridXOptions): RenderableMark;
69-
70-
export function gridFx(data?: Data, options?: GridXOptions): RenderableMark;
175+
/**
176+
* Returns a new horizontally-positioned ruleX mark (a vertical line, |) that
177+
* renders a grid for the *x* scale. The *data* defaults to tick values sampled
178+
* from the *x* scale’s domain; if desired, specify the *data* explicitly, or
179+
* use one of the **ticks**, **tickSpacing**, or **interval** options.
180+
*/
181+
export function gridX(data?: Data, options?: GridXOptions): RuleX;
182+
export function gridX(options?: GridXOptions): RuleX;
183+
184+
/**
185+
* Returns a new horizontally-positioned ruleX mark (a vertical line, |) that
186+
* renders a grid for the *fx* scale. The *data* defaults to the *fx* scale’s
187+
* domain; if desired, specify the *data* explicitly, or use the **ticks**
188+
* option.
189+
*/
190+
export function gridFx(data?: Data, options?: GridXOptions): RuleX;
191+
export function gridFx(options?: GridXOptions): RuleX;
192+
193+
/**
194+
* Returns a new vertically-positioned ruleY mark (a horizontal line, —) that
195+
* renders a grid for the *y* scale. The *data* defaults to tick values sampled
196+
* from the *y* scale’s domain; if desired, specify the *data* explicitly, or
197+
* use one of the **ticks**, **tickSpacing**, or **interval** options.
198+
*/
199+
export function gridY(data?: Data, options?: GridYOptions): RuleY;
200+
export function gridY(options?: GridYOptions): RuleY;
201+
202+
/**
203+
* Returns a new vertically-positioned ruleY mark (a horizontal line, —) that
204+
* renders a grid for the *fy* scale. The *data* defaults to the *fy* scale’s
205+
* domain; if desired, specify the *data* explicitly, or use the **ticks**
206+
* option.
207+
*/
208+
export function gridFy(data?: Data, options?: GridYOptions): RuleY;
209+
export function gridFy(options?: GridYOptions): RuleY;

src/scales.d.ts

+28-10
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type {InsetOptions} from "./inset.js";
22
import type {NiceInterval, RangeInterval} from "./interval.js";
33
import type {LegendOptions} from "./legends.js";
4-
import type {AxisAnchor} from "./marks/axis.js";
4+
import type {AxisOptions} from "./marks/axis.js";
55

66
/**
77
* How to interpolate range (output) values for continuous scales; one of:
@@ -294,12 +294,22 @@ export interface ScaleDefaults extends InsetOptions {
294294
padding?: number;
295295

296296
/**
297-
* Where to place the implicit axis; equivalent to the **anchor** option of
298-
* the axis mark.
297+
* The side of the frame on which to place the implicit axis: *top* or
298+
* *bottom* for *x* or *fx*, or *left* or *right* for *y* or *fy*. The default
299+
* depends on the scale:
299300
*
300-
* For position scales only.
301+
* - *x* - *bottom*
302+
* - *y* - *left*
303+
* - *fx* - *top* if there is a *bottom* *x* axis, and otherwise *bottom*
304+
* - *fy* - *right* if there is a *left* *y* axis, and otherwise *right*
305+
*
306+
* If *both*, an implicit axis will be rendered on both sides of the plot
307+
* (*top* and *bottom* for *x* or *fx*, or *left* and *right* for *y* or
308+
* *fy*). If null, the implicit axis is suppressed.
309+
*
310+
* For position axes only.
301311
*/
302-
axis?: AxisAnchor | "both" | boolean | null;
312+
axis?: AxisOptions["anchor"] | "both" | boolean | null;
303313

304314
/**
305315
* Whether to show a grid aligned with the scale’s ticks. If true, show a grid
@@ -313,7 +323,8 @@ export interface ScaleDefaults extends InsetOptions {
313323

314324
/**
315325
* A textual label to show on the axis or legend; if null, show no label. By
316-
* default the scale label is inferred from channel definitions.
326+
* default the scale label is inferred from channel definitions, possibly with
327+
* an arrow (↑, →, ↓, or ←) to indicate the direction of increasing value.
317328
*
318329
* For axes and legends only.
319330
*/
@@ -533,7 +544,8 @@ export interface ScaleOptions extends ScaleDefaults {
533544

534545
/**
535546
* The length of axis tick marks in pixels; negative values extend in the
536-
* opposite direction.
547+
* opposite direction. Defaults to 6 for *x* and *y* axes and *color* and
548+
* *opacity* *ramp* legends, and 0 for *fx* and *fy* axes.
537549
*
538550
* For axes and legends.
539551
*/
@@ -550,7 +562,8 @@ export interface ScaleOptions extends ScaleDefaults {
550562

551563
/**
552564
* The distance between an axis tick mark and its associated text label (in
553-
* pixels); defaults to 3.
565+
* pixels); often defaults to 3, but may be affected by **tickSize** and
566+
* **tickRotate**.
554567
*/
555568
tickPadding?: number;
556569

@@ -585,8 +598,13 @@ export interface ScaleOptions extends ScaleDefaults {
585598
ariaDescription?: string;
586599

587600
/**
588-
* Where to place the axis **label**; either *center* or one of the frame
589-
* sides: *top*, *right*, *bottom*, *left*.
601+
* Where to place the axis **label** relative to the plot’s frame. For
602+
* vertical position scales (*y* and *fy*), may be *top*, *bottom*, or
603+
* *center*; for horizontal position scales (*x* and *fx*), may be *left*,
604+
* *right*, or *center*. Defaults to *center* for ordinal scales (including
605+
* *fx* and *fy*), and otherwise *top* for *y*, and *right* for *x*.
606+
*
607+
* For position axes only.
590608
*/
591609
labelAnchor?: "top" | "right" | "bottom" | "left" | "center";
592610

0 commit comments

Comments
 (0)