Demographics treemap with population distribution and revenue obtained from that demographic associated with each node. The (fictitious) demographics data is loaded from a CSV file, whereas the revenue data is randomly generated.
Created
July 20, 2013 07:56
-
-
Save tgk/6044254 to your computer and use it in GitHub Desktop.
Demographic treemap with tooltip
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Group | Group description | Type | Type description | Percentage | |
---|---|---|---|---|---|
A | The Rich | A1 | Privileged | 3 | |
A | The Rich | A2 | Entrepaneurs | 7 | |
A | The Rich | A3 | Empty Nesters | 10 | |
B | Upper Class Families | B4 | Well-established Volvo | 23 | |
B | Upper Class Families | B5 | Optimist | 7 | |
C | Suburban | C6 | Small Business | 5 | |
C | Suburban | C7 | Never Left Home | 15 | |
E | Students | D8 | Students | 12 | |
F | Troubled | E9 | Borderline Beneficiaries | 8 | |
F | Welfare | F10 | Families on Benefits | 10 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<body> | |
<style> | |
form { | |
position: absolute; | |
left: 20px; | |
top: 10px; | |
} | |
.node { | |
border: solid 2px white; | |
position: absolute; | |
} | |
#tooltip { | |
position: absolute; | |
width: 220px; | |
height: auto; | |
padding: 10px; | |
background-color: white; | |
-webkit-border-radius: 10px; | |
-moz-border-radius: 10px; | |
border-radius: 10px; | |
-webkit-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); | |
-moz-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); | |
box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); | |
pointer-events: none; | |
} | |
#tooltip.hidden { | |
display: none; | |
} | |
#tooltip p { | |
margin: 0; | |
font-family: sans-serif; | |
font-size: 16px; | |
line-height: 20px; | |
} | |
</style> | |
<form> | |
<label><input type="radio" name="mode" value="population" checked> Population distribution</label> | |
<label><input type="radio" name="mode" value="revenue"> Revenue</label> | |
</form> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script> | |
var margin = { top: 40, right: 10, bottom: 10, left: 10 }, | |
width = 960 - margin.left - margin.right, | |
height = 500 - margin.top - margin.bottom; | |
var percentage = function(d) { return d["percentage"]; }; | |
var revenue = function(d) { return d["revenue"]; }; | |
var colorScale = d3.scale.category20c(); | |
var color = function(d) { return d.children ? colorScale(d["Group"]) : null; } | |
var treemap = d3.layout.treemap() | |
.size([width, height]) | |
.sticky(true) | |
.value(percentage); | |
var div = d3.select("body").append("div") | |
.style("position", "relative") | |
.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"); | |
var mousemove = function(d) { | |
var xPosition = d3.event.pageX + 5; | |
var yPosition = d3.event.pageY + 5; | |
d3.select("#tooltip") | |
.style("left", xPosition + "px") | |
.style("top", yPosition + "px"); | |
d3.select("#tooltip #heading") | |
.text(d["demographics"]["Group"] + " - " + d["demographics"]["Group description"]); | |
d3.select("#tooltip #percentage") | |
.text(d["demographics"]["Type description"] + "\n" + d["percentage"] + "%"); | |
d3.select("#tooltip #revenue") | |
.text("£" + d["revenue"].toFixed(0)); | |
d3.select("#tooltip").classed("hidden", false); | |
}; | |
var mouseout = function() { | |
d3.select("#tooltip").classed("hidden", true); | |
}; | |
var randomRevenue = function(data) { | |
var rows = []; | |
data.forEach(function(d){ | |
if (Math.random() < 0.75) { | |
rows.push({"Group": d["Group"], | |
"Type": d["Type"], | |
"Revenue": Math.random() * 100}); | |
} | |
}); | |
return rows; | |
} | |
var groupData = function(groupings, data, key){ | |
data.forEach(function(d){ | |
if(!groupings[d["Group"]]) { | |
groupings[d["Group"]] = {}; | |
} | |
if(!groupings[d["Group"]][d["Type"]]) { | |
groupings[d["Group"]][d["Type"]] = {}; | |
} | |
groupings[d["Group"]][d["Type"]][key] = d; | |
}); | |
} | |
d3.csv("demographics.csv", function(error, data) { | |
var revenueData = randomRevenue(data); | |
var groupings = {} | |
groupData(groupings, data, "demographics"); | |
groupData(groupings, revenueData, "revenue"); | |
var trees = []; | |
for(group in groupings){ | |
var children = []; | |
for(type in groupings[group]){ | |
var elm = groupings[group][type]; | |
elm["percentage"] = elm["demographics"]["Percentage"]; | |
elm["revenue"] = elm["revenue"] | |
? parseFloat(elm["revenue"]["Revenue"]) | |
: 0.0; | |
children.push(elm); | |
} | |
trees.push({"children": children, | |
"Group": group}); | |
} | |
var root = {"children": trees}; | |
var node = div.datum(root).selectAll(".node") | |
.data(treemap.nodes) | |
.enter().append("div") | |
.attr("class", "node") | |
.call(position) | |
.style("background", color) | |
.on("mousemove", mousemove) | |
.on("mouseout", mouseout); | |
d3.selectAll("input").on("change", function change() { | |
var value = this.value === "population" ? percentage : revenue; | |
node | |
.data(treemap.value(value).nodes) | |
.transition() | |
.duration(1500) | |
.call(position); | |
}); | |
}); | |
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 - 2) + "px"; }) | |
.style("height", function(d) { return Math.max(0, d.dy - 2) + "px"; }); | |
} | |
</script> | |
<div id="tooltip" class="hidden"> | |
<p><strong id="heading"></strong></p> | |
<p><span id="percentage"></span></p> | |
<p><span id="revenue"></span></p> | |
</div> | |
</body> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment