viewof scatter = {
const groupedTraced = d3.groups(tracedIndustryData, d => d.industry);
const svg = Plot.plot({
width: 800,
height: 500,
marginLeft: 70,
marginBottom: 60,
x: {
label: "Employment",
domain: employmentExtent,
grid: true
},
y: {
label: "Annual Wage ($)",
domain: wageExtent,
grid: true
},
color: null,
marks: [
Plot.dot(
tracedIndustryData.filter(d => d.year < selectedYear && d.employment > 0 && d.wage > 0),
{
x: "employment",
y: "wage",
r: 2,
fill: "#ccc",
opacity: 0.8,
tip: true,
title: d =>
`${d.industry} (${d.year})\nYear: ${d.year}\nEmployment: ${d3.format(",")(d.employment)}\nWage: $${d3.format(",")(d.wage)}`
}
),
...groupedTraced.flatMap(([industry, values]) => {
const sorted = values.sort((a, b) => a.year - b.year);
const segments = [];
let segment = [];
for (const point of sorted) {
const isValid = point.wage > 0 && point.employment > 0;
if (isValid) {
segment.push(point);
} else if (segment.length > 1) {
segments.push([...segment]);
segment = [];
} else {
segment = [];
}
}
if (segment.length > 1) {
segments.push(segment);
}
return segments.map(segment =>
Plot.line(segment, {
x: "employment",
y: "wage",
stroke: "#ccc",
strokeWidth: 1
})
);
}),
Plot.dot(top15Data, {
x: "employment",
y: "wage",
r: 6,
fill: d => industryColor[d.industry],
tip: true,
title: d =>
`${d.industry}\nYear: ${d.year}\nEmployment: ${d3.format(",")(d.employment)}\nWage: $${d3.format(",")(d.wage)}`
}),
Plot.ruleY([usMedianWage], {
stroke: "red",
strokeWidth: 1.5,
strokeDasharray: "4"
}),
Plot.text([{
x: employmentExtent[0] * 1.05,
y: usMedianWage + 2000,
text: "US Median Wage ($60k)"
}], {
x: "x",
y: "y",
text: "text",
fontSize: 10,
fill: "red",
textAnchor: "start"
}),
Plot.text([{
x: employmentExtent[1] * 0.98,
y: wageExtent[1] * 0.98,
text: selectedYear
}], {
x: "x",
y: "y",
text: "text",
fontSize: 40,
fill: "#eee",
textAnchor: "end"
})
]
});
return svg;
}