Published
Edited
Nov 10, 2021
4 forks
38 stars
Also listed in…
Plot
2. Charts
Insert cell
Insert cell
Insert cell
Insert cell
chart = {
const candleStick = Plot.plot({
width: width,
height: 350,
marginBottom: 10,
x: {label: null, round: false},
y: {axis: "right", grid: true, nice: true},
color: {type: "identity"},
marks: [
Plot.ruleX(data, {x: "Date", y1: "High", y2: "Low", stroke: getColor}),
Plot.barY(data, {x: "Date", y1: "Open", y2: "Close", fill: getColor})
]
});
candleStick.querySelector("g[text-anchor='middle']").remove();

const column = Plot.plot({
width: width,
height: 200,
x: {label: null, round: false, tickSize: 1, tickFormat: ticks},
y: {grid: true, axis: "right", tickFormat: "s"},
color: {type: "identity"},
marks: [Plot.barY(data, {x: "Date", y1: "Volume", fill: getColor})]
});

const overlay = Plot.plot({
width: width,
height: 570,
x: {label: null, round: false},
y: {axis: "right", type: "identity"},
color: {type: "identity"},
marks: [Plot.barY(data, {x: "Date", y1: 20, y2: 520})]
});
enableOverlay(overlay);

return html`<div>${[candleStick, column, overlay]}</div>`;
}
Insert cell
enableOverlay = overlay => {
[...overlay.querySelectorAll("g[text-anchor]")].forEach(g => g.remove());
const defaultTitle = "TSLA Historical Data";
const text = d3.select(overlay)
.append("text")
.attr("dy", "1em")
.attr("text-anchor", "start")
.attr("font-weight", "bold")
.text(defaultTitle);
const rect = d3.select(overlay)
.style("position", "absolute")
.style("top", 0)
.style("background-color", "transparent")
.selectAll("rect");
rect
.attr("fill", "#aaa")
.attr("fill-opacity", 0)
.on("pointerover", e => {
const i = rect.nodes().indexOf(e.currentTarget);
const d = data[i];
e.currentTarget.setAttribute("fill-opacity", 0.5);
text
.attr("fill", _ => getColor(d))
.text(getTitle(d));
})
.on("pointerout", e => {
e.currentTarget.setAttribute("fill-opacity", 0);
text
.attr("fill", "currentColor")
.text(defaultTitle);
});
}
Insert cell
ticks = d => {
if ((range === "5D" || range === "1M")) {
return d3.timeFormat("%m-%d")(d);
}
else if (firstDays.indexOf(d) >= 0) {
if (d.getMonth() === 0 || d === data[0].Date) {
return d.getFullYear();
}
else if (range === "5Y" || range === "Max") {
return d.getMonth() === 0 || d === data[0].Date ? d.getFullYear() : "";
}
else {
return d3.timeFormat("%B")(d).substring(0, 3);
}
}
return "";
}
Insert cell
firstDays = {
const dates = [];
let p = -1;
data.reverse().forEach(d => {
if (d.Date.getMonth() !== p) dates.push(d.Date);
p = d.Date.getMonth();
});
return dates;
}
Insert cell
getColor = d => d.Close >= d.Open ? "#649334" : "#cc392b"
Insert cell
getTitle = d => [
`${d3.timeFormat("%m/%d/%Y")(d.Date)}`,
`Open: ${d.Open}`,
`Close: ${d.Close}`,
`High: ${d.High}`,
`Low: ${d.Low}`,
`Volume: ${d3.format(",")(d.Volume)}`
].join(" ");
Insert cell
data = {
const src = await FileAttachment("Nasdaq_TSLA.csv").csv({typed: true});
src.forEach(d => d.Date = d3.timeParse("%m/%d/%Y")(d.Date));
let e = src[0].Date, s = new Date(e);
if (range === "5D") s.setDate(s.getDate() - 5);
else if (range === "1M") s.setMonth(s.getMonth() - 1);
else if (range === "3M") s.setMonth(s.getMonth() - 3);
else if (range === "6M") s.setMonth(s.getMonth() - 6);
else if (range === "YTD") s = new Date(`1/1/${s.getFullYear()}`);
else if (range === "1Y") s.setYear(s.getFullYear() - 1);
else if (range === "2Y") s.setYear(s.getFullYear() - 2);
else if (range === "5Y") s.setYear(s.getFullYear() - 5);
return range === "Max" ? src : src.filter(d => d.Date >= s && d.Date <= e);
}
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more