Published unlisted
Edited
May 6, 2020
Insert cell
Insert cell
chart = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.style("overflow", "visible");

svg.append("g")
.call(xAxis);

svg.append("g")
.call(yAxis);

const path = svg.append("g")
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 1.5)
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.selectAll("path")
.data(data.series)
.join("path")
.style("mix-blend-mode", "multiply")
.attr("d", d => line(d.values));

svg.call(hover, path);

return svg.node();
}
Insert cell
data = {
const data = d3.tsvParse(await FileAttachment("unemployment.tsv").text());
const columns = data.columns.slice(1);
return {
y: "% Unemployment",
series: data.map(d => ({
name: d.name.replace(/, ([\w-]+).*/, " $1"),
values: columns.map(k => +d[k])
})),
dates: columns.map(d3.utcParse("%Y-%m"))
};
}
Insert cell
Changed in target
function hover(svg, path) { if ("ontouchstart" in document) svg .style("-webkit-tap-highlight-color", "transparent") .on("touchmove", moved) .on("touchstart", entered) .on("touchend", left) else svg .on("mousemove", moved) .on("mouseenter", entered) .on("mouseleave", left); const dot = svg.append("g") .attr("display", "none"); dot.append("circle") .attr("r", 2.5); dot.append("text") .attr("font-family", "sans-serif") .attr("font-size", 10) .attr("text-anchor", "middle") .attr("y", -8); function moved() { d3.event.preventDefault();
-
const ym = y.invert(d3.event.layerY); const xm = x.invert(d3.event.layerX);
+
const mouse = d3.mouse(svg.node()) const ym = y.invert(mouse[1]); const xm = x.invert(mouse[0]);
const i1 = d3.bisectLeft(data.dates, xm, 1); const i0 = i1 - 1; const i = xm - data.dates[i0] > data.dates[i1] - xm ? i1 : i0; const s = d3.least(data.series, d => Math.abs(d.values[i] - ym)); path.attr("stroke", d => d === s ? null : "#ddd").filter(d => d === s).raise(); dot.attr("transform", `translate(${x(data.dates[i])},${y(s.values[i])})`); dot.select("text").text(s.name); } function entered() { path.style("mix-blend-mode", null).attr("stroke", "#ddd"); dot.attr("display", null); } function left() { path.style("mix-blend-mode", "multiply").attr("stroke", null); dot.attr("display", "none"); } }
Insert cell
height = 600
Insert cell
margin = ({top: 20, right: 20, bottom: 30, left: 30})
Insert cell
x = d3.scaleUtc()
.domain(d3.extent(data.dates))
.range([margin.left, width - margin.right])
Insert cell
y = d3.scaleLinear()
.domain([0, d3.max(data.series, d => d3.max(d.values))]).nice()
.range([height - margin.bottom, margin.top])
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))
.call(g => g.select(".domain").remove())
.call(g => g.select(".tick:last-of-type text").clone()
.attr("x", 3)
.attr("text-anchor", "start")
.attr("font-weight", "bold")
.text(data.y))
Insert cell
line = d3.line()
.defined(d => !isNaN(d))
.x((d, i) => x(data.dates[i]))
.y(d => y(d))
Insert cell
d3 = require("d3@5", "d3-array@2")
Insert cell