All continental US counties colored by depression prevalence — crude percentage of adults reporting ever being diagnosed with depression, from the CDC PLACES 2023 dataset. County geometry comes from the districts layer; rates are fetched directly from the CDC's Socrata API and joined by 5-digit FIPS code. State borders are drawn using topojson.mesh. Hover any county to see its name and rate.
https://api.mapjson.com/v1/geo?layer=districts&filter=US https://data.cdc.gov/resource/swc5-untb.json?measureid=DEPRESSION&year=2023&datavaluetypeid=CrdPrv&$limit=4000&$select=locationid,data_value
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/d3@7/dist/d3.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/topojson-client@3/dist/topojson-client.min.js"></script>
<style>
body { background: #f7f4f0; margin: 0; }
svg { width: 100%; display: block; }
#tooltip { position: fixed; background: #000; color: #fff; font-size: 11px;
padding: 3px 8px; pointer-events: none; opacity: 0; }
</style>
</head>
<body>
<div id="map"></div>
<div id="tooltip"></div>
<script>
const WIDTH = 960, HEIGHT = 580;
const svg = d3.select("#map").append("svg").attr("viewBox", `0 0 ${WIDTH} ${HEIGHT}`);
const tooltip = d3.select("#tooltip");
const CDC = "https://data.cdc.gov/resource/swc5-untb.json?measureid=DEPRESSION&year=2023&datavaluetypeid=CrdPrv&$limit=4000&$select=locationid,data_value";
const GEO = "https://api.mapjson.com/v1/geo?layer=districts&filter=US";
Promise.all([d3.json(GEO), d3.json(CDC)]).then(([topo, cdcRows]) => {
// Build FIPS → depression rate lookup
const rate = new Map();
for (const row of cdcRows) {
rate.set(row.locationid, +row.data_value);
}
const all = topojson.feature(topo, topo.objects.geo);
// Continental US: exclude Alaska (02), Hawaii (15), territories (> 56)
const isContiguous = f => {
const s = f.properties.gid.slice(0, 2);
return s !== "02" && s !== "15" && +s <= 56;
};
const features = all.features.filter(isContiguous);
const continental = { type: "FeatureCollection", features };
const projection = d3.geoAlbers()
.fitExtent([[20, 20], [WIDTH - 20, HEIGHT - 20]], continental);
const path = d3.geoPath().projection(projection);
const [minRate, maxRate] = d3.extent([...rate.values()]);
const color = d3.scaleSequential(d3.interpolatePurples).domain([minRate, maxRate]);
// County fills
svg.append("g").selectAll("path")
.data(features)
.join("path")
.attr("d", path)
.attr("fill", d => {
const r = rate.get(d.properties.gid);
return r != null ? color(r) : "#ddd";
})
.attr("stroke", "white")
.attr("stroke-width", 0.2)
.on("mouseover", function(event, d) {
d3.select(this).raise().attr("stroke", "#333").attr("stroke-width", 1);
const r = rate.get(d.properties.gid);
tooltip.style("opacity", 1)
.text(d.properties.name + (r != null ? " — " + r.toFixed(1) + "% depression" : ""));
})
.on("mousemove", event => {
tooltip.style("left", event.clientX + 12 + "px")
.style("top", event.clientY - 28 + "px");
})
.on("mouseout", function() {
d3.select(this).attr("stroke", "white").attr("stroke-width", 0.2);
tooltip.style("opacity", 0);
});
// State borders: arcs shared between counties in different states
const stateBorders = topojson.mesh(
topo, topo.objects.geo,
(a, b) => a !== b && a.properties.gid.slice(0, 2) !== b.properties.gid.slice(0, 2)
);
svg.append("path")
.datum(stateBorders)
.attr("fill", "none")
.attr("stroke", "#2c2317")
.attr("stroke-width", 0.7)
.attr("pointer-events", "none")
.attr("d", path);
});
</script>
</body>
</html>