This diagram shows the distribution of age groups in the United States over the last 150 years. Use the arrow keys to observe the changing population. Data from the Minnesota Population Center. Use the arrow keys to change the displayed year. The blue bars are the male population for each five-year age bracket, while the pink bars are the female population; the bars are partially transparent so that you can see how they overlap, unlike the traditional side-by-side display which makes it difficult to compare the relative distribution of the sexes.
xxxxxxxxxx
<meta charset="utf-8">
<style>
form {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
position: absolute;
left: 10px;
top: 10px;
}
label {
display: block;
}
</style>
<form>
<label><input type="radio" name="mode" value="grouped"> Grouped</label>
<label><input type="radio" name="mode" value="stacked" checked> Stacked</label>
</form>
<svg width="960" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var n = 5, // The number of series.
m = 6; // The number of values per series.
// The xz array has m elements, representing the x-values shared by all series.
// The yz array has n elements, representing the y-values of each of the n series.
// Each yz[i] is an array of m non-negative numbers representing a y-value for xz[i].
// The y01z array has the same structure as yz, but with stacked [y₀, y₁] instead of y.
var xz = d3.range(m),
yz = [[4,3,12,6,2,0],
[63,76,88,67,68,31],
[155,174,162,167,35,8],
[123,154,163,159,176,40],
[25,29,28,26,31,8]],
y01z = d3.stack().keys(d3.range(n))(d3.transpose(yz)),
yMax = d3.max(yz, function(y) { return d3.max(y); }),
y1Max = d3.max(y01z, function(y) { return d3.max(y, function(d) { return d[1]; }); });
var svg = d3.select("svg"),
margin = {top: 40, right: 10, bottom: 20, left: 10},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var x = d3.scaleBand()
.domain(xz)
.rangeRound([0, width])
.padding(0.08);
var y = d3.scaleLinear()
.domain([0, y1Max])
.range([height, 0]);
var color = d3.scaleOrdinal()
.domain(d3.range(n))
.range(d3.schemeCategory20c);
var series = g.selectAll(".series")
.data(y01z)
.enter().append("g")
.attr("fill", function(d, i) { return color(i); });
var rect = series.selectAll("rect")
.data(function(d) { return d; })
.enter().append("rect")
.attr("x", function(d, i) { return x(i); })
.attr("y", height)
.attr("width", x.bandwidth())
.attr("height", 0);
rect.transition()
.delay(function(d, i) { return i * 10; })
.attr("y", function(d) { return y(d[1]); })
.attr("height", function(d) { return y(d[0]) - y(d[1]); });
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x)
.tickSize(0)
.tickPadding(6));
d3.selectAll("input")
.on("change", changed);
var timeout = d3.timeout(function() {
d3.select("input[value=\"grouped\"]")
.property("checked", true)
.dispatch("change");
}, 2000);
function changed() {
timeout.stop();
if (this.value === "grouped") transitionGrouped();
else transitionStacked();
}
function transitionGrouped() {
y.domain([0, yMax]);
rect.transition()
.duration(500)
.delay(function(d, i) { return i * 10; })
.attr("x", function(d, i) { return x(i) + x.bandwidth() / n * this.parentNode.__data__.key; })
.attr("width", x.bandwidth() / n)
.transition()
.attr("y", function(d) { return y(d[1] - d[0]); })
.attr("height", function(d) { return y(0) - y(d[1] - d[0]); });
}
function transitionStacked() {
y.domain([0, y1Max]);
rect.transition()
.duration(500)
.delay(function(d, i) { return i * 10; })
.attr("y", function(d) { return y(d[1]); })
.attr("height", function(d) { return y(d[0]) - y(d[1]); })
.transition()
.attr("x", function(d, i) { return x(i); })
.attr("width", x.bandwidth());
}
// Returns an array of m psuedorandom, smoothly-varying non-negative numbers.
// Inspired by Lee Byron’s test data generator.
// https://leebyron.com/streamgraph/
function bumps(m) {
var values = [], i, j, w, x, y, z;
// Initialize with uniform random values in [0.1, 0.2).
for (i = 0; i < m; ++i) {
values[i] = 0.1 + 0.1 * Math.random();
}
// Add five random bumps.
for (j = 0; j < 5; ++j) {
x = 1 / (0.1 + Math.random());
y = 2 * Math.random() - 0.5;
z = 10 / (0.1 + Math.random());
for (i = 0; i < m; i++) {
w = (i / m - y) * z;
values[i] += x * Math.exp(-w * w);
}
}
// Ensure all values are positive.
for (i = 0; i < m; ++i) {
values[i] = Math.max(0, values[i]);
}
return values;
}
</script>
https://d3js.org/d3.v4.min.js