Published
Edited
Mar 22, 2022
Insert cell
Insert cell
Insert cell
Insert cell
FileAttachment("fivethirtyeight_rounded.png").image()
Insert cell
Insert cell
fetched = FileAttachment("leebron_james@1.json").json()
Insert cell
data=fetched.years
Insert cell
Insert cell
var_x = 'year'
Insert cell
var_y = 'war_mean'
Insert cell
xAccessor = getMetricAccessor(getMetricType(data.map((d) => d[var_x])), var_x)
Insert cell
yAccessor = getMetricAccessor(getMetricType(data.map((d) => d[var_y])), var_y)
Insert cell
Insert cell
xScale = d3
.scaleLinear()
.domain([d3.min(d3.extent(data, xAccessor)), d3.max(d3.extent(data, xAccessor))])
.range([10, dms.boundedWidth-20])

Insert cell
yScale = d3
.scaleLinear()
.domain([0, 22])
.nice()
.range([dms.boundedHeight, 0])

Insert cell
Insert cell
/// axis
function drawAxes(bounds) {
bounds
.append("g")
.attr("transform", move(0, dms.boundedHeight))
.call(xAxis.tickSize(25))
.call((g) => g.select(".domain").remove())
.call((g) => g.selectAll(".tick").attr("stroke-opacity", 0.2))
.call((g) =>
g
.selectAll(".tick text")
.attr("class", "xlabel")
.attr("x", 0)
.attr("dy", 10)
);

bounds
.append("g")
.call(yAxis.tickSize(25))
.call((g) => g.select(".domain").remove())
.call((g) => g.selectAll(".tick line").attr("stroke-opacity", 0.2))
.call((g) =>
g
.selectAll(".tick text")
.attr("class", "ylabel")
.attr("x", -35)
.attr("dy", 5)
);

bounds.append("g").call(grid);
}
Insert cell
Insert cell
/// draw
function drawData(bounds, data) {
//rulers
bounds
.append("line")
.attr("x1", -25)
.attr("y1", yScale(0))
.attr("x2", dms.boundedWidth)
.attr("y2", yScale(0))
.style("stroke", "black")
.style("stroke-width", "0.5");

bounds
.append("line")
.attr("x1", xScale(2021))
.attr("y1", 0)
.attr("x2", xScale(2021))
.attr("y2", dms.boundedHeight + 25)
.style("stroke", "black")
.style("stroke-width", "0.5");

//line
bounds
.append("path")
.datum(data.filter((d) => xAccessor(d) < 2022))
.attr("fill", "none")
.attr("stroke", "black")
.attr("stroke-width", 3.8)
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")

.attr(
"d",
d3
.line()
.x((d) => xScale(xAccessor(d)))
.y((d) => yScale(yAccessor(d)))
);
bounds
.append("path")
.datum(data.filter((d) => xAccessor(d) >= 2021))
.attr("fill", "none")
.attr("stroke", "black")
.attr("stroke-width", 3.8)
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")

.attr(
"d",
d3
.line()
.x((d) => xScale(xAccessor(d)))
.y((d) => yScale(yAccessor(d)))
)
.style("stroke-dasharray", "1,9");

//points
bounds
.selectAll("circle")
.data(data)
.join("circle")
.attr("cx", x)
.attr("cy", y)
.attr("r", 5.5)
.attr("stroke", "white")
.attr("stroke-width", "1")
.attr("fill", "black");

//text
bounds
.append("g")
.selectAll("dot")
.data(data)
.enter()
.append("text")
.attr("class", "score")
.attr("x", x)
.attr("y", y)
.style("text-anchor", "start")
.attr("dx", -12)
.attr("dy", -22)
.text((d) => d3.format(".1f")(yAccessor(d)));

//rect
bounds
.append("g")
.selectAll("rect")
.data(data.filter((d) => xAccessor(d) >= 2022))
.enter()
.append("rect")
.attr("width", 15)
.attr("height", (d) => yScale(d.war_lo) - yScale(d.war_mean))
.attr("x", (d, i) => xScale(xAccessor(d)) - 7.5)
.attr("y", y)
.attr("fill", "grey")
.style("opacity", 0.3);

bounds
.append("g")
.selectAll("rect")
.data(data.filter((d) => xAccessor(d) >= 2022))
.enter()
.append("rect")
.attr("width", 15)
.attr("height", (d) => yScale(d.war_mean) - yScale(d.war_hi))
.attr("x", (d, i) => xScale(xAccessor(d)) - 7.5)
.attr("y", (d) => yScale(d.war_hi))
.attr("fill", "grey")
.style("opacity", 0.3);
}
Insert cell
Insert cell
Insert cell
htl.html`${comparison_image}`
Insert cell
/// render
chart = {
const svg = d3.select("#chrt");
// Append our donut container group
svg.selectAll("*").remove();
svg
.style("overflow", "visible")
.style("background-color", "#FAFAFA")
.style("filter", "drop-shadow(2px 3px 2px rgb(0 0 0 / 0.4)");

svg.append("g").attr("transform", move(dms.marginLeft, dms.marginTop));

drawAxes(svg);
drawData(svg, data);
}
Insert cell
///
md`## chart structure`
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
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