diff --git a/src/marks/bollinger.js b/src/marks/bollinger.js
index 03b46189d2..8b0528785d 100644
--- a/src/marks/bollinger.js
+++ b/src/marks/bollinger.js
@@ -1,10 +1,10 @@
import {deviation, mean} from "d3";
import {marks} from "../mark.js";
+import {identity, isNoneish} from "../options.js";
import {map} from "../transforms/map.js";
import {window} from "../transforms/window.js";
import {areaX, areaY} from "./area.js";
import {lineX, lineY} from "./line.js";
-import {identity} from "../options.js";
const defaults = {
n: 20,
@@ -32,14 +32,18 @@ export function bollingerX(
} = {}
) {
return marks(
- areaX(
- data,
- map(
- {x1: bollinger({k: -k, ...options}), x2: bollinger({k, ...options})},
- {x1: x, x2: x, y, fill, fillOpacity, ...options}
- )
- ),
- lineX(data, map({x: bollinger(options)}, {x, y, stroke, strokeOpacity, strokeWidth, ...options}))
+ isNoneish(fill)
+ ? null
+ : areaX(
+ data,
+ map(
+ {x1: bollinger({k: -k, ...options}), x2: bollinger({k, ...options})},
+ {x1: x, x2: x, y, fill, fillOpacity, ...options}
+ )
+ ),
+ isNoneish(stroke)
+ ? null
+ : lineX(data, map({x: bollinger(options)}, {x, y, stroke, strokeOpacity, strokeWidth, ...options}))
);
}
@@ -60,14 +64,18 @@ export function bollingerY(
} = {}
) {
return marks(
- areaY(
- data,
- map(
- {y1: bollinger({k: -k, ...options}), y2: bollinger({k, ...options})},
- {x, y1: y, y2: y, fill, fillOpacity, ...options}
- )
- ),
- lineY(data, map({y: bollinger(options)}, {x, y, stroke, strokeOpacity, strokeWidth, ...options}))
+ isNoneish(fill)
+ ? null
+ : areaY(
+ data,
+ map(
+ {y1: bollinger({k: -k, ...options}), y2: bollinger({k, ...options})},
+ {x, y1: y, y2: y, fill, fillOpacity, ...options}
+ )
+ ),
+ isNoneish(stroke)
+ ? null
+ : lineY(data, map({y: bollinger(options)}, {x, y, stroke, strokeOpacity, strokeWidth, ...options}))
);
}
diff --git a/test/output/aaplBollingerCandlestick.svg b/test/output/aaplBollingerCandlestick.svg
new file mode 100644
index 0000000000..6e8c439860
--- /dev/null
+++ b/test/output/aaplBollingerCandlestick.svg
@@ -0,0 +1,2619 @@
+
\ No newline at end of file
diff --git a/test/plots/aapl-bollinger.ts b/test/plots/aapl-bollinger.ts
index 7d554d301e..5b90ed3561 100644
--- a/test/plots/aapl-bollinger.ts
+++ b/test/plots/aapl-bollinger.ts
@@ -2,20 +2,20 @@ import * as Plot from "@observablehq/plot";
import * as d3 from "d3";
export async function aaplBollinger() {
- const AAPL = await d3.csv("data/aapl.csv", d3.autoType);
+ const aapl = await d3.csv("data/aapl.csv", d3.autoType);
return Plot.plot({
y: {
grid: true
},
marks: [
- Plot.bollingerY(AAPL, {x: "Date", y: "Close", stroke: "blue"}),
- Plot.line(AAPL, {x: "Date", y: "Close", strokeWidth: 1})
+ Plot.bollingerY(aapl, {x: "Date", y: "Close", stroke: "blue"}),
+ Plot.line(aapl, {x: "Date", y: "Close", strokeWidth: 1})
]
});
}
export async function aaplBollingerGridInterval() {
- const AAPL = await d3.csv("data/aapl.csv", d3.autoType);
+ const aapl = await d3.csv("data/aapl.csv", d3.autoType);
return Plot.plot({
marks: [
Plot.frame({fill: "#eaeaea"}),
@@ -25,14 +25,14 @@ export async function aaplBollingerGridInterval() {
Plot.gridX({tickSpacing: 40, stroke: "#fff", strokeOpacity: 1, strokeWidth: 0.5}),
Plot.gridX({tickSpacing: 80, stroke: "#fff", strokeOpacity: 1}),
Plot.axisX({tickSpacing: 80}),
- Plot.bollingerY(AAPL, {x: "Date", y: "Close", stroke: "blue"}),
- Plot.line(AAPL, {x: "Date", y: "Close", strokeWidth: 1})
+ Plot.bollingerY(aapl, {x: "Date", y: "Close", stroke: "blue"}),
+ Plot.line(aapl, {x: "Date", y: "Close", strokeWidth: 1})
]
});
}
export async function aaplBollingerGridSpacing() {
- const AAPL = await d3.csv("data/aapl.csv", d3.autoType);
+ const aapl = await d3.csv("data/aapl.csv", d3.autoType);
return Plot.plot({
marks: [
Plot.frame({fill: "#eaeaea"}),
@@ -42,8 +42,29 @@ export async function aaplBollingerGridSpacing() {
Plot.gridX({interval: "3 months", stroke: "#fff", strokeOpacity: 1, strokeWidth: 0.5}),
Plot.gridX({interval: "1 year", stroke: "#fff", strokeOpacity: 1}),
Plot.axisX({interval: "1 year"}),
- Plot.bollingerY(AAPL, {x: "Date", y: "Close", stroke: "blue"}),
- Plot.line(AAPL, {x: "Date", y: "Close", strokeWidth: 1})
+ Plot.bollingerY(aapl, {x: "Date", y: "Close", stroke: "blue"}),
+ Plot.line(aapl, {x: "Date", y: "Close", strokeWidth: 1})
+ ]
+ });
+}
+
+export async function aaplBollingerCandlestick() {
+ const aapl = await d3.csv("data/aapl.csv", d3.autoType);
+ return Plot.plot({
+ x: {domain: [new Date("2014-01-01"), new Date("2014-06-01")]},
+ y: {domain: [68, 92], grid: true},
+ color: {domain: [-1, 0, 1], range: ["red", "black", "green"]},
+ marks: [
+ Plot.bollingerY(aapl, {x: "Date", y: "Close", stroke: "none", clip: true}),
+ Plot.ruleX(aapl, {x: "Date", y1: "Low", y2: "High", strokeWidth: 1, clip: true}),
+ Plot.ruleX(aapl, {
+ x: "Date",
+ y1: "Open",
+ y2: "Close",
+ strokeWidth: 3,
+ stroke: (d) => Math.sign(d.Close - d.Open),
+ clip: true
+ })
]
});
}