Skip to content

Instantly share code, notes, and snippets.

@gmculp
Last active May 21, 2019 14:41
Show Gist options
  • Save gmculp/2cc6cc0b81bcd18669d1 to your computer and use it in GitHub Desktop.
Save gmculp/2cc6cc0b81bcd18669d1 to your computer and use it in GitHub Desktop.
Spatially Ordered Treemap
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
margin: auto;
position: relative;
width: 90%;
}
form {
position: absolute;
right: 10px;
top: 10px;
}
.node {
border: solid 1px white;
font: 10px sans-serif;
line-height: 12px;
overflow: hidden;
position: absolute;
text-indent: 2px;
}
</style>
<form>
<label><input type="radio" name="mode" value="size"> Land Area</label>
<label><input type="radio" name="mode" value="Population" checked> Total Population</label>
<label><input type="radio" name="mode" value="Minors"> Minor Population</label>
<label><input type="radio" name="mode" value="Seniors"> Senior Population</label>
<!--<label><input type="radio" name="mode" value="Females"> Female Population</label>
<label><input type="radio" name="mode" value="Males"> Male Population</label>-->
</form>
<!--[if lte IE 8]><script src="http://cdnjs.cloudflare.com/ajax/libs/r2d3/0.2.0/r2d3.min.js"></script><![endif]-->
<!--[if gte IE 9]><!-->
<script type="text/javascript" src="http://d3js.org/d3.v3.js"></script>
<!--<![endif]-->
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script type="text/javascript">
var census_var = [
{name:"P001001",label:"Total Population",type:"Population"},
<!--{name:"P0120002",label:"Male:",type:"Males"},-->
{name:"P012003",label:"Male: !! Under 5 years",type:"Minors"},
{name:"P012004",label:"Male: !! 5 to 9 years",type:"Minors"},
{name:"P012005",label:"Male: !! 10 to 14 years",type:"Minors"},
{name:"P012006",label:"Male: !! 15 to 17 years",type:"Minors"},
{name:"P012020",label:"Male: !! 65 and 66 years",type:"Seniors"},
{name:"P012021",label:"Male: !! 67 and 69 years",type:"Seniors"},
{name:"P012022",label:"Male: !! 70 and 74 years",type:"Seniors"},
{name:"P012023",label:"Male: !! 75 and 79 years",type:"Seniors"},
{name:"P012024",label:"Male: !! 80 and 84 years",type:"Seniors"},
{name:"P012025",label:"Male: !! 85 years and over",type:"Seniors"},
<!--{name:"P0120026",label:"Female:",type:"Females"},-->
{name:"P012027",label:"Female: !! Under 5 years",type:"Minors"},
{name:"P012028",label:"Female: !! 5 to 9 years",type:"Minors"},
{name:"P012029",label:"Female: !! 10 to 14 years",type:"Minors"},
{name:"P012030",label:"Female: !! 15 to 17 years",type:"Minors"},
{name:"P012044",label:"Female: !! 65 and 66 years",type:"Seniors"},
{name:"P012045",label:"Female: !! 67 and 69 years",type:"Seniors"},
{name:"P012046",label:"Female: !! 70 and 74 years",type:"Seniors"},
{name:"P012047",label:"Female: !! 75 and 79 years",type:"Seniors"},
{name:"P012048",label:"Female: !! 80 and 84 years",type:"Seniors"},
{name:"P012049",label:"Female: !! 85 years and over",type:"Seniors"}
];
//var census_path = "https://api.census.gov/data/2010/sf1?key=c8b757f7e16f108647304131056db5bb63ba2e93&get=";
var census_path = "https://api.census.gov/data/2010/dec/sf1?key=c8b757f7e16f108647304131056db5bb63ba2e93&get=";
for (i = 0; i < census_var.length; ++i) {
census_path += (i==(census_var.length-1))?census_var[i].name:census_var[i].name+",";
}
census_path += "&for=state:*";
var tree_path = "states_tree.json";
var win_w = $( window ).width()*0.9;
var win_h = $( window ).height()*0.9;
var margin = {top: 60, right: 10, bottom: 10, left: 10},
width = win_w - margin.left - margin.right,
height = win_h - margin.top - margin.bottom;
var l_width = 200 - margin.left;
var l_height = margin.top - (margin.left*2);
var values = d3.range(l_width);
var color2 = d3.scale.linear()
.range(["rgb(0,155,255)","rgb(150,150,150)","rgb(255,100,0)"])
.interpolate(d3.interpolateRgb)
.domain([0, (values.length - 1)/2, values.length - 1]);
var x = d3.scale.ordinal()
.domain(values)
.rangeRoundBands([0, l_width]);
var svg = d3.select("body").append("svg")
.attr("width", l_width+margin.left)
.attr("height", l_height+(margin.left*2));
var g = svg.append("g").attr("transform", function(d) { return "translate(" + margin.left + "," + margin.left + ")"; });
var r = g.selectAll("rect")
.data(values)
.enter().append("rect")
.attr("x", x)
.attr("y",l_height/2)
.attr("width", x.rangeBand())
.attr("height", l_height/2)
.style("fill", color2);
g.append("line")
.attr("x1", l_width/2)
.attr("x2", l_width/2)
.attr("y1", 0)
.attr("y2", l_height)
.style("stroke","black")
.style("stroke-width","2");
g.append("text")
.attr("x", 0)
.attr("y", l_height/ 2)
.attr("dy", "-0.35em")
.attr("text-anchor", "start")
.text("contract");
g.append("text")
.attr("x", l_width)
.attr("y", l_height/ 2)
.attr("dy", "-0.35em")
.attr("text-anchor", "end")
.text("expand");
var treemap = d3.layout.treemap()
.size([width, height])
.sticky(true)
.mode("slice-dice")
.sort(function(d) { return d.order; }); //order by JSON field
var div = d3.select("body").append("div")
.attr("id", "chart")
.attr("class", "chart")
.style("position", "absolute")
.style("width", (width + margin.left + margin.right) + "px")
.style("height", (height + margin.top + margin.bottom) + "px")
.style("left", margin.left + "px")
.style("top", margin.top + "px");
$.getJSON(census_path, function(c_json) {
//grab variable names
var c_var = c_json.shift();
//assign variable names as keys
var cdata2=[];
for (i = 0; i < c_json.length; ++i) {
var c = c_json[i];
var temp_OL = {};
for (j = 0; j < c.length; ++j) {
temp_OL[c_var[j]] = c[j];
}
cdata2.push(temp_OL);
}
//get type for each variable name
var type_OL = {};
for (i = 0; i < census_var.length; ++i) {
type_OL[census_var[i].name] =census_var[i].type;
}
//create object for each state with variables summed by type
var cdata={};
for (i = 0; i < cdata2.length; ++i) {
var temp_OL = {};
var p = cdata2[i];
for (var key in p) {
if (p.hasOwnProperty(key)) {
if (type_OL.hasOwnProperty(key)) {
if (temp_OL.hasOwnProperty(type_OL[key])) {
temp_OL[type_OL[key]] = temp_OL[type_OL[key]] + parseInt(p[key]);
}
else {
temp_OL[type_OL[key]] =parseInt(p[key]);
}
}
}
}
cdata[p["state"]]=temp_OL;
}
$.getJSON(tree_path, function(root) {
var this_tree = treemap.value(function(d) { return d.size; }).nodes(root);
this_tree.forEach(function(d) { d.real_size=d.dx * d.dy;});
var node = div.selectAll(".node")
.data(this_tree)
.enter().append("div")
.attr("class", "node")
.attr("id", function(d){ return d.id;})
.call(position)
.text(function(d) { return d.children ? null : d.name; });
$( "input" ).change(function () {
var radio_value = $("input[name='mode']:checked").val();
var value = (radio_value === "size")
? function(d) { return d.size; } //return square feet from JSON
: function(d) { return cdata[d.id][radio_value]; }; //return census data from Census API
//update color scale domain based on selected variable
if (radio_value === "size") {
color2.domain([0, 1, 2]);
}
else {
var that_tree = treemap.value(value).nodes(root).map(function(d) { return (d.dx * d.dy)/d.real_size; });
color2.domain([d3.min(that_tree), 1, d3.max(that_tree)]);
}
node.data(treemap.value(value).nodes)
.transition()
.duration(1500)
.call(position);
}).change();
});
});
function position() {
this.style("left", function(d) { return d.x + "px"; })
.style("top", function(d) { return d.y + "px"; })
.style("width", function(d) { return Math.max(0, d.dx - 1) + "px"; })
.style("height", function(d) { return Math.max(0, d.dy - 1) + "px"; })
.style("background",function(d) { return color2((d.dx * d.dy)/d.real_size);});
}
</script>
{
"name": "states_tree",
"children": [
{
"name": "col1", "order": 1,
"children": [
{"name": "AK", "id":"05", "size": 576594, "order": 1, "hue": 3},
{"name": "HI", "id":"15", "size": 6381, "order": 2, "hue": 1}
]
},
{
"name": "col2", "order": 2,
"children": [
{"name": "WA", "id":"53", "size": 67290, "order": 1, "hue": 1},
{"name": "OR", "id":"41", "size": 97074, "order": 2, "hue": 4},
{"name": "CA", "id":"06", "size": 157776, "order": 3, "hue": 2}
]
},
{"name": "col3", "order": 3,
"children": [
{"name": "col3a", "order": 1,
"children": [
{"name": "MT", "id":"30", "size": 147245, "order": 1, "hue": 2}
]},
{"name": "col3b", "order": 2,
"children": [
{"name": "ID", "id":"16", "size": 83344, "order": 1, "hue": 3},
{"name": "WY", "id":"56", "size": 97803, "order": 2, "hue": 1}
]},
{"name": "col3c", "order": 3,
"children": [
{"name": "NV", "id":"32", "size": 110670, "order": 1, "hue": 1},
{"name": "UT", "id":"49", "size": 84872, "order": 2, "hue": 2},
{"name": "CO", "id":"08", "size": 104101, "order": 3, "hue": 3}
]},
{"name": "col3d", "order": 4,
"children": [
{"name": "AZ", "id":"04", "size": 113713, "order": 1, "hue": 3},
{"name": "NM", "id":"35", "size": 121757, "order": 1, "hue": 1}
]}
]},
{
"name": "col4", "order": 4,
"children": [
{"name": "ND", "id":"38", "size": 70812, "order": 1, "hue": 1},
{"name": "SD", "id":"46", "size": 77195, "order": 2, "hue": 3},
{"name": "NE", "id":"31", "size": 77330, "order": 3, "hue": 2},
{"name": "KS", "id":"20", "size": 82197, "order": 4, "hue": 1},
{"name": "OK", "id":"40", "size": 70003, "order": 5, "hue": 2},
{"name": "TX", "id":"48", "size": 264436, "order": 6, "hue": 3}
]
},
{
"name": "col5", "order": 5,
"children": [
{"name": "MN", "id":"30", "size": 84520, "order": 1, "hue": 2},
{"name": "IA", "id":"19", "size": 56258, "order": 2, "hue": 1},
{"name": "MO", "id":"29", "size": 69833, "order": 3, "hue": 3},
{"name": "AR", "id":"04", "size": 52913, "order": 4, "hue": 1},
{"name": "LA", "id":"22", "size": 45836, "order": 5, "hue": 2}
]
},
{"name": "col7", "order": 6,
"children": [
{"name": "col7a", "order": 1,
"children": [
{"name": "WI", "id":"55", "size": 56088, "order": 1, "hue": 3},
{"name": "MI", "id":"26", "size": 84520, "order": 2, "hue": 1}
]},
{"name": "col7b", "order": 2,
"children": [
{"name": "IL", "id":"17", "size": 56299, "order": 1, "hue": 2},
{"name": "IN", "id":"18", "size": 36400, "order": 2, "hue": 4},
{"name": "OH", "id":"39", "size": 41194, "order": 3, "hue": 3}
]},
{"name": "col7c", "order": 3,
"children": [
{"name": "KY", "id":"21", "size": 40320, "order": 1, "hue": 1}
]},
{"name": "col7d", "order": 4,
"children": [
{"name": "TN", "id":"47", "size": 42092, "order": 1, "hue": 2}
]},
{"name": "col7e", "order": 5,
"children": [
{"name": "MS", "id":"28", "size": 47619, "order": 1, "hue": 3},
{"name": "AL", "id":"01", "size": 51716, "order": 2, "hue": 1}
]}
]},
{"name": "col6", "order": 7,
"children": [
{"name": "col6a", "order": 1,
"children": [
{"name": "VT", "id":"50", "size": 9603, "order": 1, "hue": 1},
{"name": "NH", "id":"33", "size": 9260, "order": 2, "hue": 2},
{"name": "ME", "id":"23", "size": 32162, "order": 2, "hue": 1}
]},
{"name": "col6b", "order": 2,
"children": [
{"name": "MA", "id":"25", "size": 8173, "order": 1, "hue": 3}
]},
{"name": "col6c", "order": 3,
"children": [
{"name": "CT", "id":"09", "size": 4977, "order": 1, "hue": 1},
{"name": "RI", "id":"44", "size": 1045, "order": 2, "hue": 4}
]},
{"name": "col6d", "order": 2,
"children": [
{"name": "NY", "id":"36", "size": 48562, "order": 1, "hue": 2}
]},
{"name": "col6e", "order": 3,
"children": [
{"name": "PA", "id":"42", "size": 45360, "order": 1, "hue": 4},
{"name": "NJ", "id":"34", "size": 7508, "order": 2, "hue": 1}
]},
{"name": "col6f", "order": 4,
"children": [
{"name": "WV", "id":"54", "size": 24229, "order": 1, "hue": 2},
{"name": "MD", "id":"24", "size": 9740, "order": 2, "hue": 1},
{"name": "DE", "id":"10", "size": 2055, "order": 2, "hue": 2}
]},
{"name": "col6g", "order": 5,
"children": [
{"name": "VA", "id":"51", "size": 39820, "order": 1, "hue": 3}
]},
{"name": "col6g", "order": 6,
"children": [
{"name": "NC", "id":"37", "size": 49048, "order": 1, "hue": 1}
]},
{"name": "col6h", "order": 7,
"children": [
{"name": "GA", "id":"13", "size": 58629, "order": 1, "hue": 3},
{"name": "SC", "id":"45", "size": 30867, "order": 2, "hue": 2}
]},
{"name": "col6i", "order": 8,
"children": [
{"name": "FL", "id":"12", "size": 55815, "order": 1, "hue": 4}
]}
]
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment