Skip to content

Commit e31a7ae

Browse files
Filclaudembostock
authored
Support interval+reduce in the area mark (#2329)
* fix: areaY dense interval without explicit y option (#2328) Fixed areaY to work with dense intervals (interval + reduce) without requiring an explicit y option, matching lineY behavior. 🤖 Generated with [Claude Code](https://claude.ai/code) Total cost: $5.51 Total duration (API): 23m 31.3s Total duration (wall): 14h 30m 4.3s Total code changes: 208 lines added, 53 lines removed Token usage by model: claude-3-5-haiku: 204.7k input, 4.8k output, 0 cache read, 0 cache write claude-sonnet: 18.9k input, 28.4k output, 8.3m cache read, 629.5k cache write * a human fix: when y is undefined, default to y: reduce * add vertical tests * fix test merge * lift dense interval defaults * unused import * don’t need maybeIdentity for area? * simpler maybeIdentity * minimize diff * line can follow the same (simpler) pattern as area * re-apply edits --------- Co-authored-by: Claude Code <noreply@anthropic.com> Co-authored-by: Mike Bostock <mbostock@gmail.com>
1 parent 3542325 commit e31a7ae

11 files changed

Lines changed: 334 additions & 38 deletions

File tree

src/marks/area.js

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,10 @@ import {area as shapeArea} from "d3";
22
import {create} from "../context.js";
33
import {maybeCurve} from "../curve.js";
44
import {Mark} from "../mark.js";
5-
import {first, indexOf, maybeZ, second} from "../options.js";
6-
import {
7-
applyDirectStyles,
8-
applyIndirectStyles,
9-
applyTransform,
10-
applyGroupedChannelStyles,
11-
groupIndex
12-
} from "../style.js";
5+
import {first, maybeZ, second} from "../options.js";
6+
import {applyDirectStyles, applyIndirectStyles, applyTransform, applyGroupedChannelStyles} from "../style.js";
7+
import {groupIndex} from "../style.js";
138
import {maybeDenseIntervalX, maybeDenseIntervalY} from "../transforms/bin.js";
14-
import {maybeIdentityX, maybeIdentityY} from "../transforms/identity.js";
159
import {maybeStackX, maybeStackY} from "../transforms/stack.js";
1610

1711
const defaults = {
@@ -77,11 +71,11 @@ export function area(data, options) {
7771
}
7872

7973
export function areaX(data, options) {
80-
const {x, y = indexOf, fill, z = x === fill ? null : undefined, ...rest} = maybeDenseIntervalY(options);
81-
return new Area(data, maybeStackX(maybeIdentityX({...rest, x, y1: y, y2: undefined, z, fill}, y === indexOf ? "x2" : "x"))); // prettier-ignore
74+
const {x, y, fill, z = x === fill ? null : undefined, ...rest} = maybeDenseIntervalY(options);
75+
return new Area(data, maybeStackX({...rest, x, y1: y, y2: undefined, z, fill}));
8276
}
8377

8478
export function areaY(data, options) {
85-
const {x = indexOf, y, fill, z = y === fill ? null : undefined, ...rest} = maybeDenseIntervalX(options);
86-
return new Area(data, maybeStackY(maybeIdentityY({...rest, x1: x, x2: undefined, y, z, fill}, x === indexOf ? "y2" : "y"))); // prettier-ignore
79+
const {x, y, fill, z = y === fill ? null : undefined, ...rest} = maybeDenseIntervalX(options);
80+
return new Area(data, maybeStackY({...rest, x1: x, x2: undefined, y, z, fill}));
8781
}

src/marks/line.js

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,9 @@ import {create} from "../context.js";
33
import {curveAuto, maybeCurveAuto} from "../curve.js";
44
import {Mark} from "../mark.js";
55
import {applyGroupedMarkers, markers} from "../marker.js";
6-
import {coerceNumbers, indexOf, identity, maybeTuple, maybeZ} from "../options.js";
7-
import {
8-
applyDirectStyles,
9-
applyIndirectStyles,
10-
applyTransform,
11-
applyGroupedChannelStyles,
12-
groupIndex
13-
} from "../style.js";
6+
import {coerceNumbers, maybeTuple, maybeZ} from "../options.js";
7+
import {applyDirectStyles, applyIndirectStyles, applyTransform, applyGroupedChannelStyles} from "../style.js";
8+
import {groupIndex} from "../style.js";
149
import {maybeDenseIntervalX, maybeDenseIntervalY} from "../transforms/bin.js";
1510

1611
const defaults = {
@@ -103,10 +98,12 @@ export function line(data, {x, y, ...options} = {}) {
10398
return new Line(data, {...options, x, y});
10499
}
105100

106-
export function lineX(data, {x = identity, y = indexOf, stroke, z = stroke === x ? null : undefined, ...options} = {}) {
107-
return new Line(data, maybeDenseIntervalY({...options, x, y, z, stroke}));
101+
export function lineX(data, options) {
102+
const {x, y, stroke, z = stroke === x ? null : undefined, ...rest} = maybeDenseIntervalY(options);
103+
return new Line(data, {...rest, x, y, z, stroke});
108104
}
109105

110-
export function lineY(data, {x = indexOf, y = identity, stroke, z = stroke === y ? null : undefined, ...options} = {}) {
111-
return new Line(data, maybeDenseIntervalX({...options, x, y, z, stroke}));
106+
export function lineY(data, options) {
107+
const {x, y, stroke, z = stroke === y ? null : undefined, ...rest} = maybeDenseIntervalX(options);
108+
return new Line(data, {...rest, x, y, z, stroke});
112109
}

src/options.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -214,18 +214,18 @@ export function slice(values, type = Array) {
214214
}
215215

216216
// Returns true if any of x, x1, or x2 is not (strictly) undefined.
217-
export function hasX({x, x1, x2}) {
218-
return x !== undefined || x1 !== undefined || x2 !== undefined;
217+
export function hasX(options) {
218+
return options?.x !== undefined || options?.x1 !== undefined || options?.x2 !== undefined;
219219
}
220220

221221
// Returns true if any of y, y1, or y2 is not (strictly) undefined.
222-
export function hasY({y, y1, y2}) {
223-
return y !== undefined || y1 !== undefined || y2 !== undefined;
222+
export function hasY(options) {
223+
return options?.y !== undefined || options?.y1 !== undefined || options?.y2 !== undefined;
224224
}
225225

226226
// Returns true if has x or y, or if interval is not (strictly) undefined.
227227
export function hasXY(options) {
228-
return hasX(options) || hasY(options) || options.interval !== undefined;
228+
return hasX(options) || hasY(options) || options?.interval !== undefined;
229229
}
230230

231231
// Disambiguates an options object (e.g., {y: "x2"}) from a primitive value.

src/transforms/bin.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
coerceDate,
1414
coerceNumbers,
1515
identity,
16+
indexOf,
1617
isInterval,
1718
isIterable,
1819
isTemporal,
@@ -77,12 +78,12 @@ function maybeDenseInterval(bin, k, options = {}) {
7778
return bin(outputs, options);
7879
}
7980

80-
export function maybeDenseIntervalX(options = {}) {
81-
return maybeDenseInterval(binX, "y", withTip(options, "x"));
81+
export function maybeDenseIntervalX({y = identity, x = indexOf, ...options} = {}) {
82+
return maybeDenseInterval(binX, "y", withTip({x, y, ...options}, "x"));
8283
}
8384

84-
export function maybeDenseIntervalY(options = {}) {
85-
return maybeDenseInterval(binY, "x", withTip(options, "y"));
85+
export function maybeDenseIntervalY({x = identity, y = indexOf, ...options} = {}) {
86+
return maybeDenseInterval(binY, "x", withTip({x, y, ...options}, "y"));
8687
}
8788

8889
function binn(

src/transforms/identity.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import {hasX, hasY, identity} from "../options.js";
22

3-
export function maybeIdentityX(options = {}, k = "x") {
4-
return hasX(options) ? options : {...options, [k]: identity};
3+
export function maybeIdentityX(options) {
4+
return hasX(options) ? options : {...options, x: identity};
55
}
66

7-
export function maybeIdentityY(options = {}, k = "y") {
8-
return hasY(options) ? options : {...options, [k]: identity};
7+
export function maybeIdentityY(options) {
8+
return hasY(options) ? options : {...options, y: identity};
99
}

test/output/denseIntervalAreaX.svg

Lines changed: 64 additions & 0 deletions
Loading

test/output/denseIntervalAreaY.svg

Lines changed: 64 additions & 0 deletions
Loading

test/output/denseIntervalLineX.svg

Lines changed: 64 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)