A treemap of counties by state. Counties are colored in green if they grew from 2010 to 2014 and shades of red if they shrunk in that same period.
On mouseover, all counties in the moused-over county’s parent state are shaded by their population growth rate, on a color scale ranging from:
the minimum growth rate for the state to 0 (for the “red” counties that lost population)
0 to the maximum growth rate for the state (for the “green” counties whose population grew)
An iteration on the bl.ock Treemap from emeeks
To improve on County Treemap I, this treemap uses a color scale for each state, which results in bolder colors that better showcase the variation in county population growth rates within each state. Like County Treemap I, this treemap only shows one gradient color scale at once to ensure we suggest valid comparisons to the user.
Thanks to enjalot for talking through ideas for this bl.ock.
<!DOCTYPE html>
<head>
<title>County Treemap</title>
</head>
<meta charset="utf-8">
<style>
svg {
height: 500px;
width: 1000px;
}
</style>
<body>
<div id="viz">
<svg></svg>
</div>
</body>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script>
d3.csv("PEP_2014_PEPANNRES_with_ann.csv", cleanCensus);
function cleanCensus(data){
// loop through the data and parse out some useful variables
// append these useful variables to each object in the data array
data.forEach(function(county) {
county.name = county.label.split(", ")[0]
county.state = county.label.split(", ")[1]
county.pop = parseInt(county["pop2014"]);
county.trend = county["pop2014"] - county["pop2010"] > 0 ? "growth" : "loss";
county.rate = (county["pop2014"] - county["pop2010"]) / county["pop2010"];
})
// loop through the data again and calculate growth(loss) rates by state
data.forEach(function(county) {
var stateSubset = data.filter(function(d) {
return d.state === county.state;
});
// calculate the minimum rate of population change for the parent state
// and store it on the county
county.stateMinChange = d3.min(stateSubset, function(county) {
return (county["pop2014"] - county["pop2010"]) / county["pop2010"];
})
// calculate the maximum rate of population change for the parent state
// and store it on the county
county.stateMaxChange = d3.max(stateSubset, function(county) {
return ((county["pop2014"] - county["pop2010"]) / county["pop2010"])
})
})
/*
var minChange = d3.min(data, function(county) {
return (county["pop2014"] - county["pop2010"]) / county["pop2010"];
})
console.log("minChange", minChange);
var maxChange = d3.max(data, function(county) {
return (county["pop2014"] - county["pop2010"]) / county["pop2010"];
})
console.log("maxChange", maxChange);
*/
// a scale for generating values from 0 to 1 to use in our HSL color interpolators
var colorLinearLoss = d3.scale.linear()
.range([1,0]);
var colorLinearGrowth = d3.scale.linear()
.range([0,1]);
//colors can be specified as any CSS color string
var colorInterpolatorGrowth = d3.interpolateHsl("lightgray", "green");
var colorInterpolatorLoss = d3.interpolateHsl("lightgray", "red");
// loop through the data once more and set leaf colors
data.forEach(function (county) {
// set the color based on the rate of population change between 2010 and 2014
// use a different color scale for positive rates (growth) and negative rates (loss)
if(county.trend === "growth") {
colorLinearGrowth.domain([ 0, county["stateMaxChange"] ]);
county.leafColorSelected = colorInterpolatorGrowth(colorLinearGrowth(county["rate"]));
county.leafColorStatic = "green";
} else { // loss
colorLinearLoss.domain([ county["stateMinChange"], 0 ]);
county.leafColorSelected = colorInterpolatorLoss(colorLinearLoss(county["rate"]));
county.leafColorStatic = "red";
}
county.leafData = parseInt(county["pop2014"]);
})
packableData = nesting(data);
treemap(packableData);
}
function nesting(data) {
nestedData = d3.nest()
.key(function (d) {
return d.state;
})
.key(function (d) {
return d.trend
})
.entries(data);
return packableData = {id: "root", key: "root", values: nestedData}
}
function treemap(data) {
treemap = d3.layout.treemap();
treemap
.size([500,500])
.children(function(d) {return d["values"]})
.padding(function (d) {return d["values"] ? 2 : 1})
.value(function(d) {return d.leafData ? d.leafData : 1})
treemapData = treemap(data);
var chartG = d3.select("svg")
.append("g")
.attr("class", "dendrogram")
.attr("transform", "translate(0,0)");
chartG.selectAll("rect")
.data(treemapData)
.enter()
.append("rect")
.attr("x", function (d) {return d.x})
.attr("y", function (d) {return d.y})
.attr("height", function (d) {return d.dy})
.attr("width", function (d) {return d.dx})
.attr("class", function (d) {return d.state})
.style("fill", function (d) {return d.leafColorStatic ? d.leafColorStatic : "grey"})
.style("fill-opacity", function (d) {return d.leafColorStatic ? .6 : .1})
.style("stroke", function (d) {return d.leafColorStatic ? d3.rgb(d.leafColorStatic).darker() : "black"})
.on("mouseover", function (d) {
var stateClass = "." + d.state
d3.selectAll(stateClass)
.transition()
.style("fill", function (d) {return d.leafColorSelected ? d.leafColorSelected : "grey"})
.style("fill-opacity", function (d) {return d.leafColorSelected ? 1 : .1})
.style("stroke", function (d) {return d.leafColorSelected ? d3.rgb(d.leafColorSelected).darker() : "black"})
})
.on("mouseout", function (d) {
var stateClass = "." + d.state
d3.selectAll(stateClass)
.transition()
.style("fill", function (d) {return d.leafColorStatic ? d.leafColorStatic : "grey"})
.style("fill-opacity", function (d) {return d.leafColorStatic ? .6 : .1})
.style("stroke", function (d) {return d.leafColorStatic ? d3.rgb(d.leafColorStatic).darker() : "black"})
})
chartG.selectAll("text")
.data(treemapData.filter(function (d) {return d.depth === 1}))
.enter()
.append("text")
.attr("x", function (d) {return d.x})
.attr("y", function (d) {return d.y + 15})
.text(function (d) {return d["key"] ? d["key"].substr(0, parseInt(d.dx / 8)) : ""})
}
</script>