← Examples
districts · choropleth · external data · cdc

US Counties — Depression Rates

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.

API Calls

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

Code

<!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>