Skip to content

Instantly share code, notes, and snippets.

@MingboPeng
Last active February 15, 2018 23:23
Show Gist options
  • Save MingboPeng/13ec44bfe1f49cc2f590dce8bb060df8 to your computer and use it in GitHub Desktop.
Save MingboPeng/13ec44bfe1f49cc2f590dce8bb060df8 to your computer and use it in GitHub Desktop.
Sized Donut Multiples
license: mit

This example demonstrates how to use selection.each to create a context to access parent and child data simultaneously. The donut multiples are sized such that the area of each donut is proportionate to the total population, such that the area of the arcs is comparable across states.

This is a technical demonstration rather than a design recommendation; you probably don’t want to use this visual form. A normalized stacked bar chart is better at comparing the age distribution across states, and a stacked or grouped bar chart is better at comparing absolute values.

forked from mbostock's block: Sized Donut Multiples

Case Heating Cooling Interior Lighting Exterior Lighting Interior Equipment Exterior Equipment Fans Pumps Heat Rejection Humidification Heat Recovery Water Systems Refrigeration Generators
LEED VAV 16.07592931 6.930099542 7.277139497 0.552092707 19.14650332 0 4.282649382 3.106940357 1.902710223 0 0 1.49065031 0 0
SFP 7.394718681 5.652032529 5.309806823 0.552092707 19.14650332 0 8.494244434 1.374191874 0 0 0 1.49065031 0 0
SFP_ERV 2.043996268 5.5734863 5.309806823 0.552092707 19.14650332 0 8.888433106 0.386547709 0 0 0 1.49065031 0 0
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px Helvetica,sans-serif;
}
svg {
padding: 50px 0 0 50px;
}
.legend {
vertical-align: top;
}
.label {
text-anchor: middle;
font-size:7em;
font-family: 'Open Sans', sans-serif;
font-weight:300;
}
.label-name {
font-size:0.3em;
font-weight:700;
}
.label-unit {
font-size:0.3em;
font-weight:700;
}
</style>
<body>
<script src="//d3js.org/d3.v4.0.0-alpha.15.min.js"></script>
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,700" rel="stylesheet">
<script>
var matchKeys = [
"Case",
"Heat Rejection",
"Heating",
"Heat Recovery",
"Interior Lighting",
"Exterior Lighting",
"Generators",
"Refrigeration",
"Humidification",
"Interior Equipment",
"Exterior Equipment",
"Water Systems",
"Cooling",
"Fans",
"Pumps"
]
var formatSum = d3.format(".0f");
var padding = 10;
var radius = d3.scaleSqrt()
.range([0, 250]);
var colors = {
"Heat Rejection":"#9F5164",
"Heating":"#cb2e2e",
"Heat Recovery":"#ED7D30",
"Interior Lighting":"#FFDC6F",
"Exterior Lighting":"#F4E1AF",
"Generators":"#EDEDEE",
"Refrigeration":"#dfdfe1",
"Humidification":"#CDE7CA",
"Interior Equipment":"#B9EACD",
"Exterior Equipment":"#B5D0DD",
"Water Systems":"#66A5D8",
"Cooling":"#3076B6",
"Fans":"#604987",
"Pumps":"#9d5282"
}
var shortName = {
"Heat Rejection":"Heat Rej",
"Heating":"Heating",
"Heat Recovery":"HeatRcy",
"Interior Lighting":"IntLight",
"Exterior Lighting":"ExtLight",
"Generators":"Generator",
"Refrigeration":"Refrigeration",
"Humidification":"Humidification",
"Interior Equipment":"Int Equip",
"Exterior Equipment":"Ext Equip",
"Water Systems":"DHW",
"Cooling":"Cooling",
"Fans":"Fans",
"Pumps":"Pumps"
}
var arc = d3.arc()
.padRadius(63);
var pie = d3.pie()
.sort(null)
.padAngle(0.05)
.value(function(d) { return d.population; });
d3.csv("data.csv", function(d, i, columns) {
var total = d3.sum(columns.slice(1), function(key) { return +d[key]; })
return {
state: d.Case,
sum: total,
ages: columns.slice(1).map(function(key) {
return {
age: key,
population: d[key],
percent:d3.format(",.1%")(d[key]/total)
};
})
};
}, function(error, data) {
if (error) throw error;
radius.domain([0, d3.max(data, function(d) { return d.sum; })]);
var legend = d3.select("body").append("svg")
.attr("class", "legend")
.attr("width", 120)
.attr("height", (data.columns.length - 1) * 20)
.selectAll("g")
.data(matchKeys.slice(1))
.enter().append("g")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("width", 18)
.attr("height", 18)
.style("fill", function(d) { return colors[d]; });
legend.append("text")
.attr("x", 24)
.attr("y", 9)
.attr("dy", ".35em")
.text(function(d) { return d; });
//console.log("dd"+data);
var svg = d3.select("body").selectAll(".pie")
.data(data)
.enter().append("svg")
.attr("class", "pie")
.each(multiple)
.select("g");
var label = svg.append("text")
.attr("class", "label");
label.append("tspan")
.attr("class", "label-name")
.attr("x", 0)
.attr("dy", "-1.768em")
.attr("fill", "#afafaf")
.text(function(d) { return d.state; });
label.append("tspan")
.attr("class", "label-value")
.attr("x", 0)
.attr("dy", "0.974400000000001em")
.text(function(d) { return formatSum(d.sum); });
label.append("tspan")
.attr("class", "label-unit")
.attr("x", 0)
.attr("dy", "1.55584em")
.attr("fill", "#595959")
.text("kBTU/Sf");
function multiple(d) {
var r = radius(d.sum);
var svg = d3.select(this)
.attr("width", r * 2)
.attr("height", r * 2)
.append("g")
.attr("transform", "translate(" + r + "," + r + ")");
var filted = []
d.ages.forEach(function(d) {
var dataValue = d.population;
if(matchKeys.includes(d.age)){}
if(matchKeys.includes(d.age) && dataValue>0){
return filted.push(d);
};
});
var filted2 = filted.sort(function(a, b) {
return matchKeys.indexOf(a.age) - matchKeys.indexOf(b.age);
});
console.log(filted2);
var data = pie(filted2);
var svg = svg.selectAll(".arc")
.data(data)
.enter();
var g = svg.append("g")
.attr("class", "arc");
g.append("path").attr("d", arc.outerRadius(r).innerRadius(r * 0.75))
.style("fill", function(d) { return colors[d.data.age]; });
svg.append("text")
.attr("text-anchor","middle")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("dy", "-0.2em")
.attr("dx", "0em")
.attr("font-size", "1.2em")
.text(function(d) { return d.data.percent; });
svg.append("text")
.attr("text-anchor","middle")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("dy", "1.5em")
.attr("dx", "0em")
.attr("font-size", "1.2em")
.text(function(d) { return shortName[d.data.age]; });
}
});
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment