Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

axis mark #1197

Merged
merged 156 commits into from
Feb 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
156 commits
Select commit Hold shift + click to select a range
d2b54b7
axis mark
mbostock Dec 23, 2022
e36bf48
deferred channels
mbostock Dec 23, 2022
9d029d2
vector tick
mbostock Dec 23, 2022
1aa729c
tickPadding
mbostock Dec 23, 2022
dbbe828
grid
mbostock Dec 23, 2022
1c1b911
grid
mbostock Dec 23, 2022
0811d59
no rounded stroke
mbostock Dec 24, 2022
e71972a
fix half-pixel offset
mbostock Dec 24, 2022
f90bdb0
more conditional axes
mbostock Dec 24, 2022
bb5d976
grid mark
mbostock Dec 24, 2022
c44c29d
DRY tick
mbostock Dec 24, 2022
8d838b4
tick[XY]
mbostock Dec 24, 2022
6fb3f78
explicit ticks
mbostock Dec 24, 2022
b9ac607
axisTick[XY]
mbostock Dec 24, 2022
f67dcc7
axis mark data
mbostock Dec 24, 2022
59239de
axis insets
mbostock Dec 24, 2022
df951b8
tickFormat
mbostock Dec 24, 2022
ec672c5
better default tick format
mbostock Dec 24, 2022
d273968
simpler inferTickFormat
mbostock Dec 24, 2022
8ef29d7
auto ticks; expose scale.interval
mbostock Dec 24, 2022
edb549a
anchor
mbostock Dec 24, 2022
c1046a0
manual axis label, for now
mbostock Dec 24, 2022
50f0d92
tickRotate
mbostock Dec 24, 2022
b204427
fix crash in sparse excludeIndex
mbostock Dec 26, 2022
564970e
facetAnchor; fix mark-level missing facet
mbostock Dec 26, 2022
e0d8ed2
simpler facet sorting
mbostock Dec 27, 2022
2e5663d
fix #522; better facetAnchor
mbostock Dec 27, 2022
a1fb2ac
fix #1198; better empty facets
mbostock Dec 27, 2022
754cd3c
fix for ordinal scales
mbostock Dec 27, 2022
d1b3c75
soft hyphen
mbostock Dec 27, 2022
dc77e25
test label wrapping
mbostock Dec 27, 2022
70e854a
facet grid
mbostock Dec 27, 2022
b03d2a3
better facet grid
mbostock Dec 27, 2022
3347586
better facet grid, again
mbostock Dec 27, 2022
a364e66
better grid
mbostock Dec 27, 2022
4e0e469
better facet axes; fix font variant
mbostock Dec 28, 2022
a041fdf
extract facetSkip
mbostock Dec 28, 2022
7923696
empty facets
mbostock Dec 28, 2022
0ae5493
destructure options
mbostock Dec 29, 2022
74b0840
remove redundant defaults
mbostock Dec 29, 2022
00535df
fix tickPadding, tickRotate
mbostock Dec 29, 2022
b41631d
better grid defaults
mbostock Dec 29, 2022
e22bf59
more empty facets
mbostock Dec 29, 2022
49c32af
simpler facet warning
mbostock Dec 29, 2022
6d892d3
decoration
mbostock Dec 29, 2022
3c651af
better empty facets
mbostock Dec 29, 2022
a2e3725
better facet sort
mbostock Dec 29, 2022
28b7afd
extract facetAnchor
mbostock Dec 29, 2022
4517a5b
extract more facet logic
mbostock Dec 29, 2022
0962cbb
const facets
mbostock Dec 29, 2022
426364a
unify code
mbostock Dec 29, 2022
bc70e1b
more facet anchors
mbostock Dec 29, 2022
68a1bbb
invert facetAnchor
mbostock Dec 30, 2022
2c76baf
checkpoint axis label
mbostock Dec 30, 2022
b854a09
checkpoint axis mark integration
mbostock Jan 1, 2023
9d94b22
fix minimum offset margin
mbostock Jan 1, 2023
319e59e
fix for null marks and scales
mbostock Jan 1, 2023
4fef6a0
better implicit axes
mbostock Jan 1, 2023
0d27b07
denote side-effect
mbostock Jan 1, 2023
7794fce
better axis options
mbostock Jan 1, 2023
93b1a77
implicit facet axes
mbostock Jan 1, 2023
7aad4ac
more implicit axis options
mbostock Jan 1, 2023
4797caf
inferAxes
mbostock Jan 1, 2023
cdda45e
delete old axes
mbostock Jan 1, 2023
5f54f60
minimize diff
mbostock Jan 1, 2023
ebc9394
fix default margins
mbostock Jan 1, 2023
0fc7d7d
remove mark.decoration
mbostock Jan 1, 2023
d3490e7
facet margin options
mbostock Jan 1, 2023
f1b71f2
move side effect
mbostock Jan 1, 2023
938c9d6
inheritScaleLabels
mbostock Jan 1, 2023
1ff510d
Merge branch 'main' into mbostock/axis-mark
mbostock Jan 2, 2023
027b13c
remove comment
mbostock Jan 2, 2023
5492bde
better ARIA labels; restore prior axis order
mbostock Jan 2, 2023
0b1fcb6
regenerate tests; smarter partial implicit axes
mbostock Jan 3, 2023
e58cac6
more smarter partial implicit axes
mbostock Jan 3, 2023
f6c9c38
axis line
mbostock Jan 3, 2023
d4915e4
text stroke options
mbostock Jan 3, 2023
924ec49
don’t inline text elements
mbostock Jan 3, 2023
a54c209
do inline title elements
mbostock Jan 3, 2023
5083551
axis label
mbostock Jan 3, 2023
a65946b
fix axes for interval scales
mbostock Jan 3, 2023
660d9b2
gridDasharray
mbostock Jan 3, 2023
2faf620
better implicit axis
mbostock Jan 3, 2023
c55990c
x-axis label
mbostock Jan 4, 2023
0be9887
another fancy axis example
mbostock Jan 4, 2023
8701c2f
polish example
mbostock Jan 4, 2023
8f21d24
fancy multi-line time ticks
mbostock Jan 4, 2023
a29691e
another fancy axis example
mbostock Jan 4, 2023
4df432e
remove secondary grid shorthand
mbostock Jan 4, 2023
819705c
tweak y-axis label position
mbostock Jan 4, 2023
70ebb1f
first stab at documentation
Fil Jan 5, 2023
c5e0cec
the grid doesn't follow anchor
Fil Jan 5, 2023
db310f1
Merge branch 'main' into mbostock/axis-mark
mbostock Jan 20, 2023
b60d2b8
better deferred channels
mbostock Jan 20, 2023
973aa59
better explicit built-in axes
mbostock Jan 20, 2023
8e69ee2
fix metroUnemploymentRidgeline test
mbostock Jan 20, 2023
773daa9
use insetTop for better semantics
mbostock Jan 20, 2023
3c8f5ec
fix label option inheritance
mbostock Jan 20, 2023
a6d91fe
axis = both
mbostock Jan 20, 2023
3bf205f
Merge branch 'main' into mbostock/axis-mark
mbostock Jan 20, 2023
3106285
fix comment
mbostock Jan 20, 2023
f3ad022
a few fixes to axis label position
mbostock Jan 24, 2023
96065f4
labelAnchor
mbostock Jan 24, 2023
ace8885
smarter default labelAnchor
mbostock Jan 25, 2023
30b3022
fix googleTrendsRidgeline
mbostock Jan 25, 2023
19a3502
fix longLabels
mbostock Jan 25, 2023
27ee28d
non-fix for named time intervals
mbostock Jan 25, 2023
ae038c7
fix projectionHeightGeometry
mbostock Jan 25, 2023
e0fd9f6
non-fix for x-axis label position
mbostock Jan 25, 2023
599ae3a
better axis label position
mbostock Jan 26, 2023
0b75819
inset axis label
mbostock Jan 26, 2023
d7fc5a7
fix #375; respect facet margins
mbostock Jan 26, 2023
5cd87f0
fix industryUnemploymentTrack
mbostock Jan 26, 2023
e4410be
restore grid in penguinCulmen
mbostock Jan 26, 2023
e80954b
facet margin collapse
mbostock Jan 26, 2023
f1a1e1e
better facet margin collapse
mbostock Jan 26, 2023
34afc03
drop comment
mbostock Jan 26, 2023
dfc2e5c
labelOffset
mbostock Jan 27, 2023
5d15a63
fix auto labels and arrows
mbostock Jan 27, 2023
57cde69
named exports for tests
mbostock Jan 27, 2023
366a045
enable facet axis labels
mbostock Jan 27, 2023
7022708
add non-faceted athletesSample test
mbostock Jan 27, 2023
245d7da
better facet axis label position
mbostock Jan 27, 2023
5d7c944
cleaner
mbostock Jan 27, 2023
7f3865a
enforce constant tick options
mbostock Jan 27, 2023
e789969
shorter athletesSportWeight
mbostock Jan 27, 2023
f6b71ff
remove dead code
mbostock Jan 27, 2023
c62d35d
checkpoint cross-facet marks
mbostock Jan 28, 2023
9da51d5
checkpoint supermarks
mbostock Jan 28, 2023
1187cda
super option
mbostock Jan 28, 2023
686fda6
better super marks
mbostock Jan 28, 2023
4c002c0
drop unused mid facet anchors
mbostock Jan 28, 2023
5745309
disallow superposition, for now
mbostock Jan 29, 2023
fdd950b
facet = super
mbostock Jan 29, 2023
9177f3e
minimize diff
mbostock Jan 29, 2023
6b9bd91
fix axis label position, finally?
mbostock Jan 29, 2023
0113c85
better hexbin tests
mbostock Jan 29, 2023
6159142
polish tests
mbostock Jan 29, 2023
2ea8f2c
fix named time intervals for ticks
mbostock Jan 29, 2023
a653e54
grid xy shorthand
mbostock Jan 29, 2023
8150d8f
consistent scale checks
mbostock Jan 29, 2023
3be2f7c
better axis options
mbostock Jan 29, 2023
25d0f29
tickSpacing option
mbostock Jan 30, 2023
b7baa23
propagate tickSpacing option
mbostock Jan 30, 2023
aba84ee
fix off-by-one with interval ticks
mbostock Jan 30, 2023
c071fa4
typo (thanks, @yurivish!)
Fil Jan 30, 2023
c785d93
only one label for both axes
mbostock Jan 30, 2023
9c57820
a bit of documentation for axisX
Fil Jan 31, 2023
61e1145
given data, don’t defer channels
mbostock Jan 31, 2023
6624e7a
reduce aaplCloseDataTicks test
mbostock Jan 31, 2023
2e9544e
implicit grid with explicit axis
mbostock Jan 31, 2023
9a06f17
more grid shorthand
mbostock Jan 31, 2023
cfd47ac
Update README
mbostock Jan 31, 2023
3e095a3
fix default facet axis anchor
mbostock Jan 31, 2023
be246de
axis plot shorthand
mbostock Feb 1, 2023
85e6456
Update README
mbostock Feb 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
113 changes: 105 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -293,19 +293,20 @@ For a *band* scale, you can further fine-tune padding:

Align defaults to 0.5 (centered). Band scale padding defaults to 0.1 (10% of available space reserved for separating bands), while point scale padding defaults to 0.5 (the gap between the first point and the edge is half the distance of the gap between points, and likewise for the gap between the last point and the opposite edge). Note that rounding and mark insets (e.g., for bars and rects) also affect separation between adjacent marks.

Plot automatically generates axes for position scales. You can configure these axes with the following options:
Plot automatically generates [axis](#axis) and optionally [grid](#grid) marks for position scales. (For more control, declare these marks explicitly.) You can configure the implicit axes with the following scale options:

* *scale*.**axis** - the orientation: *top* or *bottom* for *x*; *left* or *right* for *y*; null to suppress
* *scale*.**ticks** - the approximate number of ticks to generate
* *scale*.**tickSize** - the size of each tick (in pixels; default 6)
* *scale*.**axis** - the orientation: *top* or *bottom* for *x* and *fx*; *left* or *right* for *y* and *fy*; null to suppress
* *scale*.**ticks** - the approximate number of ticks to generate, or interval, or array of values
* *scale*.**tickSize** - the length of each tick (in pixels; default 6 for *x* and *y*, or 0 for *fx* and *fy*)
* *scale*.**tickSpacing** - the approximate number of pixels between ticks (if *scale*.**ticks** is not specified)
* *scale*.**tickPadding** - the separation between the tick and its label (in pixels; default 3)
* *scale*.**tickFormat** - to format tick values, either a function or format specifier string; see [Formats](#formats)
* *scale*.**tickFormat** - either a function or specifier string to format tick values; see [Formats](#formats)
* *scale*.**tickRotate** - whether to rotate tick labels (an angle in degrees clockwise; default 0)
* *scale*.**grid** - if true, draw grid lines across the plot for each tick
* *scale*.**line** - if true, draw the axis line
* *scale*.**line** - if true, draw the axis line (only for *x* and *y*)
* *scale*.**label** - a string to label the axis
* *scale*.**labelAnchor** - the label anchor: *top*, *right*, *bottom*, *left*, or *center*
* *scale*.**labelOffset** - the label position offset (in pixels; default 0, typically for facet axes)
* *scale*.**labelOffset** - the label position offset (in pixels; default depends on margins and orientation)
* *scale*.**fontVariant** - the font-variant attribute for axis ticks; defaults to tabular-nums for quantitative axes
* *scale*.**ariaLabel** - a short label representing the axis in the accessibility tree
* *scale*.**ariaDescription** - a textual description for the axis
Expand Down Expand Up @@ -585,6 +586,12 @@ When top-level faceting is used, the default *auto* setting is equivalent to *in

When mark-level faceting is used, the default *auto* setting is equivalent to *include*: the mark will be faceted if either the *mark*.**fx** or *mark*.**fy** channel option (or both) is specified. The null or false option will disable faceting, while *exclude* draws the subset of the mark’s data *not* in the current facet.

The <a name="facetanchor">*mark*.**facetAnchor**</a> option controls TK. It supports the following settings:

* null - display the mark on each non-empty facet (default for all marks, with the exception of axis marks)
* *top*, *right*, *bottom*, or *left* - display the mark on facets on the specified side
* *top-empty*, *right-empty*, *bottom-empty*, or *left-empty* - display the mark on facets that have an empty space on the specified side (the empty space being either the margin, or an empty facet); this is the default for axis marks

## Legends

Plot can generate legends for *color*, *opacity*, and *symbol* [scales](#scale-options). (An opacity scale is treated as a color scale with varying transparency.) For an inline legend, use the *scale*.**legend** option:
Expand Down Expand Up @@ -958,6 +965,50 @@ Returns a new arrow with the given *data* and *options*.

<!-- jsdocEnd arrow -->

### Axis

[Source](./src/marks/axis.js) · [Examples](https://observablehq.com/@observablehq/plot-axis) · Draws an axis.

Plot automatically generates axes for position scales, and draws them below the other marks. Each axis is composed of up to 5 marks: a grid, and an axis mark which might contain a line, ticks, tick labels, and axis label.

When you need more control, you can add axis and grid marks explicitly in the marks options. Note that Plot’s automatic axis for *x* is disabled when a mark’s aria-label property begins by `x-axis `—and likewise for *y*, *fx*, and *fy*.

The optional *data* is an array of tick values—it defaults to the scale’s ticks.

The axis options described in [position options](#position-options) are all supported, except the **grid** option which is handled by the [grid](#grid) mark. The **y** channel, if any, describes the vertical position of the tick and defaults to the axis anchor.

The **axis** option, in this context, is called **anchor** and is one of *top* or *bottom*.

The **color** option controls both **stroke** for the ticks, and the **fill** for labels. It defaults to currentColor.

The (rarely used) text label’s stroke is controlled by the **textStroke**,**textStrokeOpacity**, and **textStrokeWidth** options.

The **facetAnchor** option defaults to *bottom-empty* if anchor is bottom, and *top-empty* if anchor is top. This ensures the proper positioning of the axes with respect to empty facets.

#### Plot.axisX(*data*, *options*)

<!-- jsdoc axisX -->

```js
Plot.axisX({anchor: "bottom"})
```

Returns a new *x*-axis with the given *options*.

<!-- jsdocEnd axisX -->

#### Plot.axisY(*data*, *options*)

…same…

#### Plot.axisFx(*data*, *options*)

…same…

#### Plot.axisFy(*data*, *options*)

…same…

### Bar

[<img src="./img/bar.png" width="320" height="198" alt="a bar chart">](https://observablehq.com/@observablehq/plot-bar)
Expand Down Expand Up @@ -1358,6 +1409,52 @@ Plot.graticule()

Returns a new geo mark with a [default 10° global graticule](https://github.com/d3/d3-geo/blob/main/README.md#geoGraticule10) geometry object and the given *options*.

### Grid

[Source](./src/marks/axis.js) · [Examples](https://observablehq.com/@observablehq/plot-axis) · Draws an axis-aligned grid.

The optional *data* is an array of tick values—it defaults to the scale’s ticks. The grid mark draws a line for each tick value, across the whole frame.

The following options are supported:

* **strokeDasharray** - the [stroke dasharray](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray) for dashed lines, defaults to null

The following options are supported as constant or data-driven channels:

* **stroke** - the grid color, defaults to currentColor
* **strokeWidth** - the grid’s line width, defaults to 1
* **strokeOpacity** - the stroke opacity, defaults to 0.1
* **y1** - the start of the line, a channel of y positions.
* **y2** - the end of the line, a channel of y positions.

All the other common options are supported when applicable (e.g., **title**).

#### Plot.gridX(*data*, *options*)

<!-- jsdoc gridX -->

```js
Plot.gridX({strokeDasharray: "5,3"})
```

Returns a new *x*-grid with the given *options*.

<!-- jsdocEnd gridX -->

#### Plot.gridY(*data*, *options*)

…same…


#### Plot.gridFx(*data*, *options*)

…same…

#### Plot.gridFy(*data*, *options*)

…same…


### Hexgrid

The hexgrid mark can be used to support marks using the [hexbin](#hexbin) layout.
Expand Down Expand Up @@ -1950,7 +2047,7 @@ For example, to draw bars only for letters that commonly form vowels:
Plot.barY(alphabet, {filter: d => /[aeiou]/i.test(d.letter), x: "letter", y: "frequency"})
```

The **filter** transform is similar to filtering the data with [*array*.filter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter), except that it will preserve [faceting](#faceting) and will not affect inferred [scale domains](#scale-options); domains are inferred from the unfiltered channel values.
The **filter** transform is similar to filtering the data with [*array*.filter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter), except that it will preserve [faceting](#facet-options) and will not affect inferred [scale domains](#scale-options); domains are inferred from the unfiltered channel values.

```js
Plot.barY(alphabet.filter(d => /[aeiou]/i.test(d.letter)), {x: "letter", y: "frequency"})
Expand Down
192 changes: 21 additions & 171 deletions src/axes.js
Original file line number Diff line number Diff line change
@@ -1,172 +1,22 @@
import {extent} from "d3";
import {AxisX, AxisY} from "./axis.js";
import {formatDefault} from "./format.js";
import {isOrdinalScale, isTemporalScale, scaleOrder} from "./scales.js";
import {position, registry} from "./scales/index.js";

export function Axes(
{x: xScale, y: yScale, fx: fxScale, fy: fyScale},
{
x = {},
y = {},
fx = {},
fy = {},
axis = true,
grid,
line,
label,
facet: {axis: facetAxis = axis, grid: facetGrid, label: facetLabel = label} = {}
} = {}
) {
let {axis: xAxis = axis} = x;
let {axis: yAxis = axis} = y;
let {axis: fxAxis = facetAxis} = fx;
let {axis: fyAxis = facetAxis} = fy;
if (!xScale) xAxis = null;
else if (xAxis === true) xAxis = "bottom";
if (!yScale) yAxis = null;
else if (yAxis === true) yAxis = "left";
if (!fxScale) fxAxis = null;
else if (fxAxis === true) fxAxis = xAxis === "bottom" ? "top" : "bottom";
if (!fyScale) fyAxis = null;
else if (fyAxis === true) fyAxis = yAxis === "left" ? "right" : "left";
return {
...(xAxis && {x: new AxisX(xScale, {grid, line, label, ...x, axis: xAxis})}),
...(yAxis && {y: new AxisY(yScale, {grid, line, label, ...y, axis: yAxis})}),
...(fxAxis && {fx: new AxisX(fxScale, {name: "fx", grid: facetGrid, label: facetLabel, ...fx, axis: fxAxis})}),
...(fyAxis && {fy: new AxisY(fyScale, {name: "fy", grid: facetGrid, label: facetLabel, ...fy, axis: fyAxis})})
};
}

// Mutates axis.ticks!
// TODO Populate tickFormat if undefined, too?
export function autoAxisTicks({x, y, fx, fy}, {x: xAxis, y: yAxis, fx: fxAxis, fy: fyAxis}) {
if (fxAxis) autoAxisTicksK(fx, fxAxis, 80);
if (fyAxis) autoAxisTicksK(fy, fyAxis, 35);
if (xAxis) autoAxisTicksK(x, xAxis, 80);
if (yAxis) autoAxisTicksK(y, yAxis, 35);
}

function autoAxisTicksK(scale, axis, k) {
if (axis.ticks === undefined) {
const interval = scale.interval;
if (interval !== undefined) {
const [min, max] = extent(scale.scale.domain());
axis.ticks = interval.range(interval.floor(min), interval.offset(interval.floor(max)));
} else {
const [min, max] = extent(scale.scale.range());
axis.ticks = (max - min) / k;
}
}
// D3’s ordinal scales simply use toString by default, but if the ordinal
// scale domain (or ticks) are numbers or dates (say because we’re applying a
// time interval to the ordinal scale), we want Plot’s default formatter.
if (axis.tickFormat === undefined && isOrdinalScale(scale)) {
axis.tickFormat = formatDefault;
}
}

// Mutates axis.{label,labelAnchor,labelOffset} and scale.label!
export function autoScaleLabels(channels, scales, {x, y, fx, fy}, dimensions, options) {
if (fx) {
autoAxisLabelsX(fx, scales.fx, channels.get("fx"));
if (fx.labelOffset === undefined) {
const {facetMarginTop, facetMarginBottom} = dimensions;
fx.labelOffset = fx.axis === "top" ? facetMarginTop : facetMarginBottom;
}
}
if (fy) {
autoAxisLabelsY(fy, fx, scales.fy, channels.get("fy"));
if (fy.labelOffset === undefined) {
const {facetMarginLeft, facetMarginRight} = dimensions;
fy.labelOffset = fy.axis === "left" ? facetMarginLeft : facetMarginRight;
}
}
if (x) {
autoAxisLabelsX(x, scales.x, channels.get("x"));
if (x.labelOffset === undefined) {
const {marginTop, marginBottom, facetMarginTop, facetMarginBottom} = dimensions;
x.labelOffset = x.axis === "top" ? marginTop - facetMarginTop : marginBottom - facetMarginBottom;
}
}
if (y) {
autoAxisLabelsY(y, x, scales.y, channels.get("y"));
if (y.labelOffset === undefined) {
const {marginRight, marginLeft, facetMarginLeft, facetMarginRight} = dimensions;
y.labelOffset = y.axis === "left" ? marginLeft - facetMarginLeft : marginRight - facetMarginRight;
}
}
for (const [key, type] of registry) {
if (type !== position && scales[key]) {
// not already handled above
autoScaleLabel(key, scales[key], channels.get(key), options[key]);
}
}
}

// Mutates axis.labelAnchor, axis.label, scale.label!
function autoAxisLabelsX(axis, scale, channels) {
if (axis.labelAnchor === undefined) {
axis.labelAnchor = isOrdinalScale(scale) ? "center" : scaleOrder(scale) < 0 ? "left" : "right";
}
if (axis.label === undefined) {
axis.label = inferLabel(channels, scale, axis, "x");
}
scale.label = axis.label;
}

// Mutates axis.labelAnchor, axis.label, scale.label!
function autoAxisLabelsY(axis, opposite, scale, channels) {
if (axis.labelAnchor === undefined) {
axis.labelAnchor = isOrdinalScale(scale)
? "center"
: opposite && opposite.axis === "top"
? "bottom" // TODO scaleOrder?
: "top";
}
if (axis.label === undefined) {
axis.label = inferLabel(channels, scale, axis, "y");
}
scale.label = axis.label;
}

// Mutates scale.label!
function autoScaleLabel(key, scale, channels, options) {
if (options) {
scale.label = options.label;
}
if (scale.label === undefined) {
scale.label = inferLabel(channels, scale, null, key);
}
}

// Channels can have labels; if all the channels for a given scale are
// consistently labeled (i.e., have the same value if not undefined), and the
// corresponding axis doesn’t already have an explicit label, then the channels’
// label is promoted to the corresponding axis.
function inferLabel(channels = [], scale, axis, key) {
let candidate;
for (const {label} of channels) {
if (label === undefined) continue;
if (candidate === undefined) candidate = label;
else if (candidate !== label) return;
}
if (candidate !== undefined) {
// Ignore the implicit label for temporal scales if it’s simply “date”.
if (isTemporalScale(scale) && /^(date|time|year)$/i.test(candidate)) return;
if (!isOrdinalScale(scale)) {
if (scale.percent) candidate = `${candidate} (%)`;
if (key === "x" || key === "y") {
const order = scaleOrder(scale);
if (order) {
if (key === "x" || (axis && axis.labelAnchor === "center")) {
candidate = (key === "x") === order < 0 ? `← ${candidate}` : `${candidate} →`;
} else {
candidate = `${order < 0 ? "↑ " : "↓ "}${candidate}`;
}
}
}
}
}
return candidate;
import {format, utcFormat} from "d3";
import {formatIsoDate} from "./format.js";
import {constant, isTemporal, string} from "./options.js";
import {isOrdinalScale} from "./scales.js";

export function inferFontVariant(scale) {
return isOrdinalScale(scale) && scale.interval === undefined ? undefined : "tabular-nums";
}

// D3 doesn’t provide a tick format for ordinal scales; we want shorthand when
// an ordinal domain is numbers or dates, and we want null to mean the empty
// string, not the default identity format. TODO Remove this in favor of the
// axis mark’s inferTickFormat.
export function maybeAutoTickFormat(tickFormat, domain) {
return tickFormat === undefined
? isTemporal(domain)
? formatIsoDate
: string
: typeof tickFormat === "function"
? tickFormat
: (typeof tickFormat === "string" ? (isTemporal(domain) ? utcFormat : format) : constant)(tickFormat);
}
Loading