{
const width = 600;
const height = 400;
const margin = { top: 70, bottom: 50, left: 50, right: 100 };
const div = htl.html`<div></div>`;
const categories = [["All Sites", barley], ...d3.groups(barley, d => d.site)];
const buttons = d3
.select(div)
.selectAll("button")
.data(categories)
.join("button");
buttons.text((d) => d[0]);
const svg = d3
.select(div)
.append("div")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
svg.append("text")
.attr("x", (width + margin.left + margin.right) / 2)
.attr("y", margin.top / 2)
.attr("text-anchor", "middle")
.attr("font-size", "16px")
.attr("font-weight", "bold")
.text("Scatterplot of Barley Yield in Minnesota by Variety and Site");
svg.append("text")
.attr("text-anchor", "middle")
.attr("x", margin.left + width / 2)
.attr("y", height + margin.top + margin.bottom - 5)
.text("Barley Variety");
svg.append("text")
.attr("text-anchor", "middle")
.attr("transform", `rotate(-90)`)
.attr("x", -margin.top - height / 2)
.attr("y", 15)
.text("Yield");
const g = svg
.append("g")
.attr("transform", `translate(${margin.left}, ${margin.top})`);
const x = d3
.scalePoint()
.domain(varieties)
.range([0, width]);
const y = d3
.scaleLinear()
.domain(d3.extent(barley, (d) => d["yield"]))
.range([height, 0]);
const color = d3
.scaleOrdinal()
.domain(categories.map((d) => d[0]))
.range(d3.schemeDark2);
g.append("g").call(d3.axisLeft(y));
g.append("g")
.attr("transform", `translate(0, ${height})`)
.call(d3.axisBottom(x));
const circles = g
.selectAll("circle")
// initializing scatterplot with all data
.data(barley)
.join("circle")
.attr("r", 4)
//.style("stroke", "#000")
// changing border color based on year
.style("stroke", d => Number(d.year) === 1931 ? "#000" : "#666")
.style("stroke-width", 2)
.attr("cx", (d) => x(d.variety))
.attr("cy", (d) => y(d.yield))
.style("fill", (d) => color(d.site))
.style("opacity", 0.7)
// code from Part 5
.style("cursor", "pointer")
.on("click", (event, d) => {
text.text(JSON.stringify(d))
});
buttons.on("click", (event, d) => {
// selecting circles
g.selectAll("circle")
.data(d[1], (d) => d)
.join(
// allows for animation and changing of data being shown
(enter) =>
enter
.append("circle")
.attr("r", 4)
//.style("stroke", "#000")
.style("stroke", d => Number(d.year) === 1931 ? "#000" : "#666")
.style("stroke-width", 2)
.attr("cx", (d) => x(d.variety))
.attr("cy", (d) => y(d.yield))
.style("fill", (d) => color(d.site))
.style("opacity", 0.7)
.style("cursor", "pointer")
.on("click", (event, d) => {
text.text(JSON.stringify(d));
}),
(update) =>
update
.attr("cx", (d) => x(d.variety))
.attr("cy", (d) => y(d.yield))
.style("fill", (d) => color(d.site))
.style("opacity", 0.7),
// shrinking animation
(exit) =>
exit
.attr("fill", "red")
.call((exit) =>
exit.transition().duration(1000).attr("r", 0).remove()
)
);
});
// code from Part 5
const text = svg
.append("text")
.style("font", "12px sans-serif")
.attr("y", 15)
.text("Click on a circle to read the data!");
// creating a legend
// creating array with data for legend
const legendData = [
{ year: 1931, color: "#000", label: "1931" },
{ year: 1932, color: "#666", label: "1932" }
];
// appending legend group to SVG in top right corner
const legend = svg.append("g")
.attr("transform", `translate(${width + margin.left + 25}, ${margin.top})`);
// creatining legend items
legendData.forEach((entry, index) => {
// creating a rectangle for each year indicating border color
legend.append("rect")
.attr("x", 0)
.attr("y", index * 30)
.attr("width", 20)
.attr("height", 20)
.style("fill", entry.color);
// creating legend labels
legend.append("text")
.attr("x", 30)
.attr("y", index * 30 + 10)
.text(entry.label)
.attr("font-size", "12px")
.attr("alignment-baseline", "middle");
});
return div;
}