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 |