proportionalSymbols = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height]);
svg.append("path")
.datum(topojson.feature(basepolygons, basepolygons.objects.ca_counties_wgs84))
.attr("fill", "#f0f0f0")
.attr("stroke", "#999")
.attr("d", path_basemap);
svg.append("path")
.datum(topojson.mesh(basepolygons, basepolygons.objects.ca_counties_wgs84, (a, b) => a !== b))
.attr("fill", "none")
.attr("stroke", "white")
.attr("stroke-linejoin", "round")
.attr("d", path_basemap);
const counties = topojson.feature(basepolygons, basepolygons.objects.ca_counties_wgs84).features;
const centroids = counties.map(d => ({
GEOID: +d.properties.GEOID,
name: d.properties.NAME,
coordinates: path_basemap.centroid(d)
}));
const joined = centroids.map(d => {
const match = failingData.find(e => +e.GEOID === d.GEOID);
return {
...d,
Failing_System_Count: match ? +match.Failing_System_Count : 0
};
});
const radius = d3.scaleSqrt()
.domain([0, d3.max(joined, d => d.Failing_System_Count)])
.range([0, 40]); // Increased max radius
// Add circles
svg.append("g")
.attr("fill", "#e34a33") // orange-red, bold
.attr("fill-opacity", 0.6)
.attr("stroke", "#b30000")
.attr("stroke-width", 0.6)
.selectAll("circle")
.data(joined.sort((a, b) => b.Failing_System_Count - a.Failing_System_Count))
.join("circle")
.attr("cx", d => d.coordinates[0])
.attr("cy", d => d.coordinates[1])
.attr("r", d => radius(d.Failing_System_Count))
.append("title")
.text(d => `${d.name}\n${d.Failing_System_Count} failing systems`);
const legendValues = [d3.max(joined, d => d.Failing_System_Count), 200, 50];
const format = d3.format(",");
const legend = svg.append("g")
.attr("fill", "#555")
.attr("transform", "translate(120, 470)")
.attr("text-anchor", "start")
.style("font", "11px sans-serif");
legend.append("text")
.attr("x", 0)
.attr("y", -radius(legendValues[0]) - 25)
.attr("font-weight", "bold")
.text("Failing Systems");
const legendCircles = legend.selectAll("g")
.data(legendValues)
.join("g")
.attr("transform", d => `translate(0, ${-radius(d)})`);
legendCircles.append("circle")
.attr("r", radius)
.attr("fill", "none")
.attr("stroke", "#999");
legendCircles.append("text")
.attr("x", radius(legendValues[0]) + 6) // horizontal offset to right of biggest circle
.attr("dy", "0.35em")
.text(d => `${format(d)}`);
return svg.node();
}