block by almccon b4b61fe3066cf4b99180269ebf6137e6

USA 2016 vs 2012 presidential election proportional circles

Full Screen

Built with blockbuilder.org

click on the map to toggle between 2012 and 2016.

NOTE: 2016 data is still preliminary, and votes are still being counted, especially in Washington, Oregon, and California.

2016 data from: https://github.com/Ryan-J-Smith/presidential_election_county_results_2016

forked from almccon‘s block: USA 2012 presidential election proportional circles

index.html

<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <script src="//d3js.org/d3.v4.js"></script>
  <script src="//d3js.org/topojson.v1.min.js"></script>
  <script src="https://d3js.org/d3-queue.v3.min.js"></script>
  <style>
    body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
    svg { width:100%; height: 100% }
  </style>
</head>

<body>
  <script>
    var width = 1000,
        height = 800;

    var year = '2016';

    // Note: with d3.v4 we can't use "fallback projections"
    var projection = d3.geoAlbersUsa()
      //.scale(500)
      //.translate([width / 2, height / 2]);

    var color = d3.scaleLinear()
        .domain([20,50,80])
        .range(['blue','purple','red']);

    var svg = d3.select("body").append("svg");

    var label = d3.select("body").append("div")
      .classed('label', true)
      .html(year);

    var background_g = svg.append("g");
    var foreground_g = svg.append("g");

    var path = d3.geoPath(projection);
    d3.json("elpo12p010g.topojson", function(error, usa2012) {

      // Add the background
      background_g.append("path")
        .datum(topojson.feature(usa2012, usa2012.objects.elpo12p010g))
        .attr("d", path)
        .style("fill", "#ddd")
        .on("click", function(d) { updateCircles(); })
    });

    var countyLookup = {};

    var barHeight,
        circleRadius,
        countyCircles;

    d3.queue()
      .defer(d3.csv, "elpo12p010g.csv")
      .defer(d3.csv, "2016_US_County_Level_Presidential_Results.csv")
      .awaitAll(function(error, results) {

      //var counties = usa2012.features;
      var counties = results[0];
      var counties2016 = results[1];

      counties2016.forEach(function(county) {
        // convert county.fips to 5 digit string (pad leading zero with "05")
        var currentCounty = countyLookup[d3.format("05")(county.combined_fips)];
        if (!currentCounty) {
          countyLookup[d3.format("05")(county.combined_fips)] = county;
        }
      });


      barHeight = d3.scaleLinear()
        .domain([0, d3.max(counties, function(d) { return +d.ttl_vt; })])
        .range([0, 100]); // 0 to maximum height in pixels

      circleRadius = d3.scaleSqrt()
        .domain([0, d3.max(counties, function(d) { return +d.ttl_vt; })])
        .range([0, 50]); // 0 to maximum radius in pixels

      /*
      // add vertical bars for each county
      var countyBars = foreground_g.append("g").attr("id", "countyBars");

      countyBars.selectAll("path")
          .data(counties.sort(function(a,b) { if (a.geometry.coordinates[1] < b.geometry.coordinates[1]) return 1; if (a.geometry.coordinates[1] > b.geometry.coordinates[1]) return -1; return 0; }))
        .enter().append("rect")
          .attr("x", function(d) { return projection(d.geometry.coordinates)[0] - 3; }) // Subtract 3 because width of bar will be 6
          .attr("y", function(d) { return projection(d.geometry.coordinates)[1] - barHeight(+d.properties.ttl_vt); })
          .attr("width", 6)
          .attr("height", function(d) { return  barHeight(+d.properties.ttl_vt); })
          .style("fill", function(d) { return color(+d.properties.pct_rom);});
      */

      // add proportional circles for each county
      var countyGroup = foreground_g.append("g").attr("id", "countyCircles");

      countyCircles = countyGroup.selectAll("path")
          //.data(counties)
          // Big counties on the bottom:
          .data(counties.sort(function(a,b) { if (+a.properties.ttl_vt > +b.properties.ttl_vt) return 1; if (+a.properties.ttl_vt < +b.properties.ttl_vt) return -1; return 0;}))
          // Big counties on top:
          //.data(counties.sort(function(a,b) { if (+a.properties.ttl_vt > +b.properties.ttl_vt) return 1; if (+a.properties.ttl_vt < +b.properties.ttl_vt) return -1; return 0;}))
        .enter().append("circle")
          .attr("transform", function(d) { return "translate(" + projection([+d.lon,+d.lat]) + ")"; })
          .attr("r", function(d) {
            if (countyLookup[d.fips]) {
              return circleRadius(+countyLookup[d.fips].total_votes);
            } else {
              console.log("couldn't find lookup", d.fips);
              return 0;
            }
          })
          //.attr("r", function(d) { return circleRadius(+d.ttl_vt); })
          .style("fill", function(d) {
            if (countyLookup[d.fips]) {
              return color(100 * +countyLookup[d.fips].per_gop);
            } else {
              return 'black';
            }
          })
          .classed("countycircle", true)
          .on("click", function(d) { updateCircles(); })
          .on("mouseover", function(d) { console.log(d); });

    });

    function updateCircles() {
      //var countyCircles = d3.select('.countycircle');

      if (year == '2016')
        year = '2012';
      else
        year = '2016';

      if (year == '2016') {
        countyCircles
          .transition()
          .attr("r", function(d) { 
            if (countyLookup[d.fips]) {
              return circleRadius(+countyLookup[d.fips].total_votes);
            } else {
              console.log("couldn't find lookup", d.fips);
              return 0;
            }
          })
          .style("fill", function(d) {
            if (countyLookup[d.fips]) {
              return color(100 * +countyLookup[d.fips].per_gop);
            } else {
              return 'black';
            }
          })
      } else {
        countyCircles
          .transition()
          .attr("r", function(d) { return circleRadius(+d.ttl_vt); })
          .style("fill", function(d) { return color(+d.pct_rom); });
      }
      return year;
    }

  </script>
</body>