Public
Edited
Mar 12, 2024
Insert cell
Insert cell
Plot.plot({
height: 900,
x: {axis: "top", type: "ordinal", tickFormat: "", inset: 40, label: null},
y: {axis: null, inset: 20},
marks: [
Plot.line(receipts, {x: "year", y: "cog_emp_rt", z: "state_abbrev", stroke: 'grey', strokeWidth: 0.35}),
d3.groups(receipts, (d) => d.year === 2014)
.map(([left, cog_emp_rt]) =>
Plot.text(cog_emp_rt, occlusionY({
x: "year",
y: "cog_emp_rt",
text: left
? (d) => `${d.state_abbrev} ${d.cog_emp_rt}`
: (d) => `${d.cog_emp_rt} ${d.state_abbrev}`,
textAnchor: left ? "end" : "start",
dx: left ? -3 : 3,
radius: 4.35,
fontSize: 8
}))
)
],
caption: "Employment rates for cognitively disabled individuals"
})
Insert cell
// OcclusionY adds an initializer that shifts nodes vertically with a tiny force simulation.
occlusionY = ({radius = 4.5, ...options} = {}) => Plot.initializer(options, (data, facets, { y: {value: Y}, text: {value: T} }, {y: sy}, dimensions, context) => {
for (const index of facets) {
const unique = new Set();
const nodes = Array.from(index, (i) => ({
fx: 0,
y: sy(Y[i]),
visible: unique.has(T[i]) // remove duplicate labels
? false
: !!unique.add(T[i]),
i
}));
d3.forceSimulation(nodes.filter((d) => d.visible))
.force("y", d3.forceY(({y}) => y)) // gravitate towards the original y
.force("collide", d3.forceCollide().radius(radius)) // collide
.stop()
.tick(300);
for (const { y, node, i, visible } of nodes) Y[i] = !visible ? NaN : y;
}
return {data, facets, channels: {y: {value: Y}}};
})
Insert cell
receipts = FileAttachment("slope_data@5.csv").csv({ typed: true })
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