Skip to content

Commit 30f6216

Browse files
committed
interval for rect
1 parent ce19abb commit 30f6216

File tree

5 files changed

+214
-3
lines changed

5 files changed

+214
-3
lines changed

src/marks/rect.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {filter} from "../defined.js";
33
import {Mark, number} from "../mark.js";
44
import {isCollapsed} from "../scales.js";
55
import {applyDirectStyles, applyIndirectStyles, applyTransform, impliedString, applyAttr, applyChannelStyles} from "../style.js";
6+
import {maybeIntervalX, maybeIntervalY} from "../transforms/interval.js";
67
import {maybeStackX, maybeStackY} from "../transforms/stack.js";
78

89
const defaults = {};
@@ -64,13 +65,13 @@ export class Rect extends Mark {
6465
}
6566

6667
export function rect(data, options) {
67-
return new Rect(data, options);
68+
return new Rect(data, maybeIntervalX(maybeIntervalY(options)));
6869
}
6970

7071
export function rectX(data, options) {
71-
return new Rect(data, maybeStackX(options));
72+
return new Rect(data, maybeStackX(maybeIntervalY(options)));
7273
}
7374

7475
export function rectY(data, options) {
75-
return new Rect(data, maybeStackY(options));
76+
return new Rect(data, maybeStackY(maybeIntervalX(options)));
7677
}

src/transforms/interval.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import {labelof, maybeValue, valueof} from "../mark.js";
2+
3+
// TODO Allow the interval to be specified as a string, e.g. “day” or “hour”?
4+
// This will require the interval knowing the type of the associated scale to
5+
// chose between UTC and local time (or better, an explicit timeZone option).
6+
function maybeInterval(interval) {
7+
if (interval == null) return;
8+
if (typeof interval.floor !== "function" || typeof interval.offset !== "function") throw new Error("invalid interval");
9+
return interval;
10+
}
11+
12+
// The interval may be specified either as x: {value, interval} or as {x,
13+
// interval}. The former is used, for example, for Plot.rect.
14+
function maybeIntervalValue(value, {interval} = {}) {
15+
(value = {...maybeValue(value)});
16+
value.interval = maybeInterval(value.interval === undefined ? interval : value.interval);
17+
return value;
18+
}
19+
20+
function maybeIntervalK(k, options = {}) {
21+
const {[k]: v, [`${k}1`]: v1, [`${k}2`]: v2} = options;
22+
const {value, interval} = maybeIntervalValue(v, options);
23+
if (interval == null) return options;
24+
let V1;
25+
const tv1 = data => V1 || (V1 = valueof(data, value).map(v => interval.floor(v)));
26+
const label = labelof(v);
27+
return {
28+
...options,
29+
[k]: undefined,
30+
[`${k}1`]: v1 === undefined ? {transform: tv1, label} : v1,
31+
[`${k}2`]: v2 === undefined ? {transform: () => tv1().map(v => interval.offset(v)), label} : v2
32+
};
33+
}
34+
35+
export function maybeIntervalX(options) {
36+
return maybeIntervalK("x", options);
37+
}
38+
39+
export function maybeIntervalY(options = {}) {
40+
return maybeIntervalK("y", options);
41+
}

test/output/aaplCloseRect.svg

Lines changed: 153 additions & 0 deletions
Loading

test/plots/aapl-close-rect.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import * as Plot from "@observablehq/plot";
2+
import * as d3 from "d3";
3+
4+
export default async function() {
5+
const AAPL = (await d3.csv("data/aapl.csv", d3.autoType)).slice(-90);
6+
return Plot.plot({
7+
y: {
8+
grid: true
9+
},
10+
marks: [
11+
Plot.rectY(AAPL, {x: "Date", interval: d3.utcDay, y: "Close"}),
12+
Plot.ruleY([0])
13+
]
14+
});
15+
}

test/plots/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export {default as aaplBollinger} from "./aapl-bollinger.js";
22
export {default as aaplCandlestick} from "./aapl-candlestick.js";
33
export {default as aaplChangeVolume} from "./aapl-change-volume.js";
44
export {default as aaplClose} from "./aapl-close.js";
5+
export {default as aaplCloseRect} from "./aapl-close-rect.js";
56
export {default as aaplCloseUntyped} from "./aapl-close-untyped.js";
67
export {default as aaplMonthly} from "./aapl-monthly.js";
78
export {default as aaplVolume} from "./aapl-volume.js";

0 commit comments

Comments
 (0)