{
const plotWidth = 520;
const keyWidth = 240;
const width = plotWidth + keyWidth;
const height = 400;
const margin = { top: 30, bottom: 20, left: 80, right: 20 };
const svg = d3
.create("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
const instruction = "Mouse over a circle or label to read the data!";
const text = svg
.append("text")
.style("font", "12px sans-serif")
.attr("y", 15)
.text(instruction);
const g = svg
.append("g")
.attr("transform", `translate(${margin.left}, ${margin.top})`);
g.append("rect")
.attr("width", plotWidth)
.attr("height", height)
.style("fill", "#eee");
const x = d3
.scaleBand()
.domain(Array.from(new Set(barleyForVarietySiteVis.map((d) => d[0]))))
.range([0, plotWidth]);
const y = d3
.scaleBand()
.domain(Array.from(new Set(barleyForVarietySiteVis.map((d) => d[1]))))
.range([height, 0]);
const rMax = d3.min([x.bandwidth() / 2, y.bandwidth() / 2]);
const rFactor =
rMax /
d3.max(
barleyForVarietySiteVis.map((d) => d3.max(d[2].map((d) => d["yield"])))
);
const red = "#b00";
const green = "#0b0";
{
const xKey = margin.left + plotWidth + 36;
let y = 65;
const xGap = 10;
const yGap = 10;
const r1 = rMax * 0.75;
const r2 = rMax * 0.5;
const r3 = rMax;
const heading = svg
.append("text")
.style("font-size", "28px")
.attr("x", xKey + r3)
.attr("y", y)
.attr("text-anchor", "middle")
.text("Key");
y += yGap;
svg
.append("circle")
.attr("r", r1)
.attr("cx", xKey + r3)
.attr("cy", y + r3)
.style("fill", red)
.style("fill-opacity", "0.5");
svg
.append("text")
.attr("x", xKey + 2 * r3 + xGap)
.attr("y", y + r3)
.attr("dominant-baseline", "middle")
.text("- 1931 yield");
y += 2 * r3 + yGap;
svg
.append("circle")
.attr("r", r1)
.attr("cx", xKey + r3)
.attr("cy", y + r3)
.style("fill", green)
.style("fill-opacity", "0.5");
svg
.append("text")
.attr("x", xKey + 2 * r3 + xGap)
.attr("y", y + r3)
.attr("dominant-baseline", "middle")
.text("- 1932 yield");
y += 2 * r3 + yGap;
svg
.append("circle")
.attr("r", r1)
.attr("cx", xKey + r3)
.attr("cy", y + r3)
.style("fill", red)
.style("fill-opacity", "0.5");
svg
.append("circle")
.attr("r", r1)
.attr("cx", xKey + r3)
.attr("cy", y + r3)
.style("fill", green)
.style("fill-opacity", "0.5");
svg
.append("text")
.attr("x", xKey + 2 * r3 + xGap)
.attr("y", y + r3)
.attr("dominant-baseline", "middle")
.text("- common yield");
y += 2 * r3 + yGap;
svg
.append("circle")
.attr("r", r2)
.attr("cx", xKey + r3)
.attr("cy", y + r3)
.style("fill", red)
.style("fill-opacity", "0.5");
svg
.append("circle")
.attr("r", r3)
.attr("cx", xKey + r3)
.attr("cy", y + r3)
.style("fill", green)
.style("fill-opacity", "0.5");
svg
.append("text")
.attr("x", xKey + 2 * r3 + xGap)
.attr("y", y + r3)
.attr("dominant-baseline", "middle")
.text("- increased yield");
y += 2 * r3 + yGap;
svg
.append("circle")
.attr("r", r3)
.attr("cx", xKey + r3)
.attr("cy", y + r3)
.style("fill", red)
.style("fill-opacity", "0.5");
svg
.append("circle")
.attr("r", r2)
.attr("cx", xKey + r3)
.attr("cy", y + r3)
.style("fill", green)
.style("fill-opacity", "0.5");
svg
.append("text")
.attr("x", xKey + 2 * r3 + xGap)
.attr("y", y + r3)
.attr("dominant-baseline", "middle")
.text("- decreased yield");
}
const num = d3.format(".1f");
const diff = d3.format("+.1%");
const gs = g
.append("g")
.selectAll("g")
.data(barleyForVarietySiteVis)
.join("g")
.on("mouseenter", (event, d) => {
if (d[2][0]["year"] !== "1931" || d[2][1]["year"] !== "1932") {
throw d;
}
const y1 = d[2][0]["yield"];
const y2 = d[2][1]["yield"];
let s = "";
text.text(
diff((y2 - y1) / y1) +
" ︱ " +
num(y1) +
" -> " +
num(y2) +
" ︱ " +
d[0] +
" @ " +
d[1]
);
d3.select(event.currentTarget).select("rect").attr("opacity", "0.05");
})
.on("mouseleave", (event, d) => {
text.text(instruction);
d3.select(event.currentTarget).select("rect").attr("opacity", "0");
});
gs.append("rect")
.attr("opacity", "0")
.attr("x", (d) => x(d[0]))
.attr("y", (d) => y(d[1]))
.attr("width", x.bandwidth())
.attr("height", y.bandwidth());
gs.selectAll("circle")
.data((d) => d[2])
.join("circle")
.attr("r", (d, i) => d["yield"] * rFactor)
.attr("cx", (d) => x(d["variety"]) + x.bandwidth() / 2)
.attr("cy", (d) => y(d["site"]) + y.bandwidth() / 2)
.style("fill", (d) =>
d["year"] === "1931" ? red : "1932" ? green : "#fff"
)
.style("fill-opacity", 0.5);
g.append("g")
.attr("transform", `translate(0, ${height})`)
.attr("class", "x-axis")
.call(d3.axisBottom(x));
g.append("g").attr("class", "y-axis").call(d3.axisLeft(y));
svg
.selectAll(".x-axis .tick")
.on("mouseover", (event, d) => {
const yields = barleyForVarietyLabel.get(d);
const y1 = yields.get("1931");
const y2 = yields.get("1932");
text.text(
diff((y2 - y1) / y1) + " ︱ " + num(y1) + " -> " + num(y2) + " ︱ " + d
);
})
.on("mouseleave", (event, d) => {
text.text(instruction);
});
svg
.selectAll(".y-axis .tick")
.on("mouseover", (event, d) => {
const yields = barleyForSiteLabel.get(d);
const y1 = yields.get("1931");
const y2 = yields.get("1932");
text.text(
diff((y2 - y1) / y1) + " ︱ " + num(y1) + " -> " + num(y2) + " ︱ " + d
);
})
.on("mouseleave", (event, d) => {
text.text(instruction);
});
return svg.node();
}