block by john-guerra 54ac510dbb3196f04bdd7db3bdcb5164

2017 US Federal Budget

Full Screen

Built with blockbuilder.org

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>US Federal Budget</title>
  <style>
    body {
      font-family: sans-serif;
    }
  </style>
  
</head>
<body>
  <input type="checkbox" id="chkBEA"><label for="chkBEA">Group by BEA Category</label>
  <input type="checkbox" id="chkGrant"><label for="chkGrant">Group by Grant</label>
  <div id="budget"></div>
  <script src="//d3js.org/d3.v4.min.js"></script>
  <script>
    /* global d3 */

    var width = 900,
      height = 400,
      svg = d3.select("#budget")
      .append("svg")
        .attr("width", width)
        .attr("height", height),
      rScale = d3.scalePow().exponent(0.5) // A scale for areas Pi*r^2
        .range([1, 50]),
      cScale = d3.scaleOrdinal(d3.schemeCategory10),
      yScale = d3.scaleBand()
        .range([50, height]),
      xScale = d3.scaleBand()
        .range([70, width]);




    function preprocess(row) {
      if (row["2017"]==="0") return null;
      row["2017"] = +(row["2017"].replace(new RegExp(",", "g"), ""));
      return row;
    }
    d3.csv("outlays.csv", preprocess, function (err, data) {
      if (err) throw err;

      var nestedData = d3.nest()
        .key(function (d) { return d["Grant/non-grant split"]; })
        .key(function (d) { return d["BEA Category"]; })
        .key(function (d) { return d["Agency Name"]; })
        // .key(function (d) { return d["Bureau Name"]; })
        .rollup(function(leaves) {
          return {
            "length": leaves.length,
            "budget": d3.sum(leaves, function(d) {
              return +d["2017"];
            })
          };
        })
        .entries(data);

      var flatAgencies = [];
      nestedData.forEach(function (g) {
        g.values.forEach(function (bea) {
          bea.values.forEach(function (a) {
            a.bea = bea.key;
            a.grant = g.key;
            flatAgencies.push(a);
          });
        });
      });

      xScale.domain(nestedData[0].values.map(function (d) { return d.key; }));
      yScale.domain(nestedData.map(function (d) { return d.key; }));
      rScale.domain([0, d3.max(flatAgencies, function (d) { return d.value.budget; })]);

      var simulation = d3.forceSimulation(flatAgencies)
        .force("collide", d3.forceCollide().radius(function (d) { return rScale(d.value.budget)+1; }))
        .force("x", d3.forceX(width/2))
        // .force("y", )
        .force("y", d3.forceY(height/2))
        .on("tick", ticked);


      var cs = svg.selectAll("circle")
        .data(flatAgencies);

      var csEnter = cs.enter()
        .append("circle")
        .style("fill", function (d) { return cScale(d.bea); })
        .attr("r", function (d) {
          return rScale(d.value.budget);
        });

      csEnter.append("title")
        .text(function (d) { return d.key + " $" + d.value.budget/1000000 + "M"; });

      svg.append("g")
        .attr("class", "axis y")
        .style("display", "none")
        .call(d3.axisLeft(yScale))
        .attr("transform", "translate(70,0)");
      svg.append("g")
        .attr("class", "axis x")
        .style("display", "none")
        .call(d3.axisTop(xScale))
        .attr("transform", "translate(0,50)");


      d3.select("#chkBEA").on("change", function () {
        simulation.force("x",
          d3.event.target.checked ?
            d3.forceX(function (d) { return xScale(d.bea) + xScale.bandwidth()/2; }).strength(0.3) :
            d3.forceX(width/2)
          );
        svg.select(".x.axis").style("display", d3.event.target.checked ? "block" : "none");
        simulation.alpha(0.3).restart();
      });
      d3.select("#chkGrant").on("change", function () {
        simulation.force("y",
          d3.event.target.checked ?
            d3.forceY(function (d) { return yScale(d.grant) + yScale.bandwidth()/2; }).strength(0.3) :
            d3.forceY(height/2)
          );
        svg.select(".y.axis").style("display", d3.event.target.checked ? "block" : "none");
        simulation.alpha(0.3).restart();
      });

      function ticked() {
        csEnter.merge(cs)
          .attr("cx", function (d) { return d.x; })
          .attr("cy", function (d) { return d.y; });
      }
    });
  </script>

</body>
</html>