An adaptation of the NPR hexgrid that sets hexagon size in play as a thematic variable.
Still needs a legend, but:
- Hex size = relative population
- Hex color = approximate solar energy potential
| license: mit |
An adaptation of the NPR hexgrid that sets hexagon size in play as a thematic variable.
Still needs a legend, but:
| <!DOCTYPE html> | |
| <meta charset="utf-8"> | |
| <!-- Load d3.js --> | |
| <script src="https://d3js.org/d3.v4.js"></script> | |
| <script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script> | |
| <script src="https://d3js.org/d3-geo-projection.v2.min.js"></script> | |
| <style> | |
| body { background-color: #fff; } | |
| </style> | |
| <svg id="cartogram" width="800" height="500"></svg> | |
| <script> | |
| // The svg | |
| var svg = d3.select("svg"), | |
| width = +svg.attr("width"), | |
| height = +svg.attr("height"); | |
| // Map and projection | |
| var projection = d3.geoMercator() | |
| .scale(600) // This is the zoom | |
| .translate([1500, 750]); // You have to play with these values to center your map | |
| // Path generator | |
| var path = d3.geoPath() | |
| .projection(projection) | |
| // Colors | |
| var lowColor = '#ffffff' | |
| var highColor = '#bc2a66' | |
| // load in the data | |
| d3.queue() | |
| .defer(d3.json, "us_states_hexgrid.geojson") | |
| .defer(d3.csv, "sn.csv") | |
| .await(ready); | |
| function ready(error, geo, sn) { | |
| if (error) throw error; | |
| // get min/max of everything | |
| var getArray = function(data,name) { | |
| var dataArray = []; | |
| for (var d = 0; d < data.length; d++) { | |
| dataArray.push(parseInt(data[d][name])) | |
| } | |
| return dataArray | |
| } | |
| var min1 = d3.min(getArray(sn,'population')) | |
| var max1 = d3.max(getArray(sn,'population')) | |
| var min2 = d3.min(getArray(sn,'avg_sn')) | |
| var max2 = d3.max(getArray(sn,'avg_sn')) | |
| // create color scale | |
| var colorRamp = d3.scaleSqrt() | |
| .domain([min2,max2]) | |
| .range([lowColor,highColor]) | |
| // Join geojson and CSV (gotta be a better way of doing this) | |
| for (var i = 0; i < sn.length; i++) { | |
| // Grab State Name | |
| var dataState = sn[i].state; | |
| // Grab grouped record count | |
| var dataPop = sn[i].population; | |
| var dataSn = sn[i].avg_sn | |
| // Find the corresponding state inside the GeoJSON | |
| for (var j = 0; j < geo.features.length; j++) { | |
| var geoState = geo.features[j].properties.abbrv; | |
| if (dataState == geoState) { | |
| // Copy the data value into the JSON | |
| geo.features[j].properties.population = parseInt(dataPop); | |
| geo.features[j].properties.avg_sn = parseInt(dataSn); | |
| // Stop looking through the JSON | |
| break; | |
| } | |
| } | |
| } | |
| // Draw the scaled features | |
| svg.append("g") | |
| .selectAll("path") | |
| .data(geo.features) | |
| .enter() | |
| .append("path") | |
| .attr("fill", function(d) { return colorRamp(d.properties.avg_sn) || 'rgba(255,255,255,0.2)' }) | |
| .attr("d", path) | |
| .attr("stroke", "rgba(100,100,100,0.9)") | |
| // create resize scale (via http://bl.ocks.org/rveciana/5928736) | |
| .attr("transform", function(d) { | |
| scale_factor = Math.sqrt(d.properties.population/(max1-min1)); | |
| var centroid = path.centroid(d), | |
| x = centroid[0], | |
| y = centroid[1]; | |
| return "translate(" + x + "," + y + ")" | |
| + "scale(" + scale_factor + ")" | |
| + "translate(" + -x + "," + -y + ")"; | |
| }); | |
| // Draw the mesh | |
| svg.append("g") | |
| .selectAll("path") | |
| .data(geo.features) | |
| .enter() | |
| .append("path") | |
| .attr("fill", "none") | |
| .attr("d", path) | |
| //.attr("stroke", "rgba(50,50,50,0.2)") | |
| // Add the labels | |
| svg.append("g") | |
| .selectAll("labels") | |
| .data(geo.features) | |
| .enter() | |
| .append("text") | |
| .attr("x", function(d){return path.centroid(d)[0]}) | |
| .attr("y", function(d){return path.centroid(d)[1]}) | |
| .text(function(d){ return d.properties.abbrv}) | |
| .attr("text-anchor", "middle") | |
| .attr("alignment-baseline", "central") | |
| .style("font-size", 11) | |
| .style("fill", "rgba(25,25,25,0.6)") | |
| .attr("transform","translate(0,-15)") | |
| } | |
| </script> |
| id | state | population | avg_sn | |
|---|---|---|---|---|
| 2 | AK | 733375 | ||
| 1 | AL | 4830620 | 72 | |
| 5 | AR | 2958208 | 65 | |
| 4 | AZ | 6641928 | 89 | |
| 6 | CA | 38421464 | 83 | |
| 8 | CO | 5278906 | 84 | |
| 9 | CT | 3593222 | 73 | |
| 11 | DC | 647484 | 64 | |
| 10 | DE | 926454 | 72 | |
| 12 | FL | 19645772 | 79 | |
| 13 | GA | 10006693 | 68 | |
| 15 | HI | 1406299 | 87 | |
| 19 | IA | 3093526 | 75 | |
| 16 | ID | 1616547 | 77 | |
| 17 | IL | 12873761 | 73 | |
| 18 | IN | 6568645 | 76 | |
| 20 | KS | 2892987 | 71 | |
| 21 | KY | 4397353 | 76 | |
| 22 | LA | 4625253 | 75 | |
| 25 | MA | 6705586 | 69 | |
| 24 | MD | 5930538 | 75 | |
| 23 | ME | 1329100 | 71 | |
| 26 | MI | 9900571 | 62 | |
| 27 | MN | 5419171 | 72 | |
| 29 | MO | 6045448 | 77 | |
| 28 | MS | 2988081 | 73 | |
| 30 | MT | 1014699 | 77 | |
| 37 | NC | 9845333 | 70 | |
| 38 | ND | 721640 | 73 | |
| 31 | NE | 1869365 | 78 | |
| 33 | NH | 1324201 | 71 | |
| 34 | NJ | 8904413 | 72 | |
| 35 | NM | 2084117 | 86 | |
| 32 | NV | 2798636 | 91 | |
| 36 | NY | 19673174 | 77 | |
| 39 | OH | 11575977 | 77 | |
| 40 | OK | 3849733 | 77 | |
| 41 | OR | 3939233 | 75 | |
| 42 | PA | 12779559 | 77 | |
| 44 | RI | 1053661 | 78 | |
| 45 | SC | 4777576 | 76 | |
| 46 | SD | 843190 | 70 | |
| 47 | TN | 6499615 | 70 | |
| 48 | TX | 26538614 | 80 | |
| 49 | UT | 2903379 | 79 | |
| 51 | VA | 8256630 | 75 | |
| 50 | VT | 626604 | 77 | |
| 53 | WA | 6985464 | 71 | |
| 55 | WI | 5742117 | 70 | |
| 54 | WV | 1851420 | 79 | |
| 56 | WY | 579679 | 76 |