Public
Edited
Oct 26, 2023
59 forks
Importers
96 stars
Insert cell
Insert cell
Insert cell
{
replay; // references the button above, causing this cell to run on click
return htl.html`<svg viewBox="0 0 ${width} ${height}">
${d3.select(htl.svg`<path d="${line(data)}" fill="none" stroke="steelblue" stroke-width="1.5" stroke-miterlimit="1" stroke-dasharray="0,1"></path>`).call(reveal).node()}
${d3.select(htl.svg`<g>`).call(xAxis).node()}
${d3.select(htl.svg`<g>`).call(yAxis).node()}
</svg>`;
}
Insert cell
Insert cell
Insert cell
reveal = path => path.transition()
.duration(5000)
.ease(d3.easeLinear)
.attrTween("stroke-dasharray", function() {
const length = this.getTotalLength();
return d3.interpolate(`0,${length}`, `${length},${length}`);
})
Insert cell
Insert cell
Insert cell
Insert cell
htl.html`<svg viewBox="0 0 ${width} ${height}">
<path d="${line(data)}" fill="none" stroke="steelblue" stroke-width="1.5" stroke-miterlimit="1" stroke-dasharray="${lineLength * t},${lineLength}"></path>
${d3.select(htl.svg`<g>`).call(xAxis).node()}
${d3.select(htl.svg`<g>`).call(yAxis).node()}
</svg>`
Insert cell
lineLength = htl.svg`<path d="${line(data)}">`.getTotalLength()
Insert cell
Insert cell
Insert cell
Insert cell
strokeDasharray = d3.interpolate(`0,${lineLength}`, `${lineLength},${lineLength}`)
Insert cell
strokeDasharray(t)
Insert cell
Insert cell
ramp(d3.interpolateRgb("steelblue", "orange"))
Insert cell
ramp(d3.interpolateRgb.gamma(2.2)("steelblue", "orange"))
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
replay2; // reference the button so this cell re-runs on click
for (let i = 0, n = 300; i < n; ++i) {
yield i;
}
}
Insert cell
{
replay2; // reference the button so this cell re-runs on click

const path = htl.svg`<path d="${line(data)}" fill="none" stroke="steelblue" stroke-width="1.5" stroke-miterlimit="1">`;

const chart = htl.html`<svg viewBox="0 0 ${width} ${height}">
${path}
${d3.select(htl.svg`<g>`).call(xAxis).node()}
${d3.select(htl.svg`<g>`).call(yAxis).node()}
</svg>`;

for (let i = 0, n = 300; i < n; ++i) {
const t = (i + 1) / n;
path.setAttribute("stroke-dasharray", `${t * lineLength},${lineLength}`);
yield chart;
}
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
chart = {
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, width, height])
.attr("style", "max-width: 100%; height: auto; height: intrinsic;");

const zx = x.copy(); // x, but with a new domain.

const line = d3.line()
.x(d => zx(d.date))
.y(d => y(d.close));

const path = svg.append("path")
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 1.5)
.attr("stroke-miterlimit", 1)
.attr("d", line(data));

const gx = svg.append("g")
.call(xAxis, zx);

const gy = svg.append("g")
.call(yAxis, y);

return Object.assign(svg.node(), {
update(domain) {
const t = svg.transition().duration(750);
zx.domain(domain);
gx.transition(t).call(xAxis, zx);
path.transition(t).attr("d", line(data));
}
});
}
Insert cell
update = chart.update(timeframe)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
data = FileAttachment("aapl-bollinger.csv").csv({typed: true})
Insert cell
line = d3.line().x(d => x(d.date)).y(d => y(d.close))
Insert cell
x = d3.scaleUtc()
.domain(d3.extent(data, d => d.date))
.range([margin.left, width - margin.right])
Insert cell
y = d3.scaleLinear()
.domain([0, d3.max(data, d => d.upper)])
.range([height - margin.bottom, margin.top])
Insert cell
xAxis = (g, scale = x) => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(scale).ticks(width / 80).tickSizeOuter(0))
Insert cell
yAxis = (g, scale = y) => g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(scale).ticks(height / 40))
.call(g => g.select(".domain").remove())
Insert cell
height = 240
Insert cell
margin = ({top: 20, right: 30, bottom: 30, left: 40})
Insert cell
import {Scrubber} from "@mbostock/scrubber"
Insert cell
import {ramp} from "@mbostock/color-ramp"
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more