Published
Edited
May 23, 2022
Insert cell
Insert cell
commits = FileAttachment("bim_commits.csv").csv({typed:true})

Insert cell
commits.reverse()
Insert cell
x = d3.scaleUtc()
.domain(d3.extent(commits, d=>d.date))
.range([margin.left, width - margin.right])

Insert cell
y = d3.scaleLinear()
.domain([0, d3.max(commits, d=>d.count)])
.range([height - margin.bottom, margin.top])

Insert cell
//assembles path string with M (Moveto) and L (Lineto)
{
let path = `M${x(commits[0].date)}, ${y(commits[0].count)}`;
for (let i = 1; i < commits.length; ++i){
path += `L${x(commits[i].date)}, ${y(commits[i].count)}`;
}
return path;
}
Insert cell
//the equivalent is simply d3.line().x(attribute).y(attribute)
line = d3.line()
.x(d => x(d.date))
.y(d => y(d.count))
Insert cell
line(commits)
Insert cell
viewof replay = Inputs.button("Replay")
Insert cell
{
replay;
//render path, call xAxis, call yAxis
return htl.html`<svg viewBox="0 0 ${width} ${height}">
${d3.select(htl.svg`<path d="${line(commits)}" fill="none" stroke="steelblue" stroke-width="2" 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
area = d3.area()
.x(d => x(d.date))
.y0(y(0))
.y1(d => y(d.count))

Insert cell
//what does node() do here?
htl.html`<svg viewBox = "0 0 ${width} ${height}">
<path fill="steelblue" d="${area(commits)}"></path>
<g fill="none" stroke-width="5" stroke-miterlimit="1">
<path d="${area.lineY1()(commits)}" stroke="#b77"></path>
</g>
${d3.select(htl.svg`<g>`).call(xAxis).node()}
${d3.select(htl.svg`<g>`).call(yAxis).node()}
</svg>`

Insert cell
areaBand = d3.area()
.x0(d => x(d.date))
.x1(d => x(d.simpledate))
.y(d => y(d.count))

Insert cell
htl.html`<svg viewBox="0 0 ${width} ${height}">
<path d="${areaBand(commits)}" fill="steelblue"></path>
${d3.select(htl.svg`<g>`).call(xAxis).node()}
${d3.select(htl.svg`<g>`).call(yAxis).node()}
</svg>`
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
## Appendix
Insert cell
height = 300
Insert cell
margin = ({top: 20, right: 0, bottom: 20, left: 30})
Insert cell
xAxis = g => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x).ticks(width/80).tickSizeOuter(0))

Insert cell
yAxis = g => g
.attr("transform", `translate(${margin.left}, 0)`)
.call(d3.axisLeft(y).ticks(height/40))
.call(g => g.select(".domain").remove())
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