Skip to content

Commit 44e4620

Browse files
committed
Rewrite population example to be easier to follow.
1 parent 41fece5 commit 44e4620

2 files changed

Lines changed: 86 additions & 77 deletions

File tree

examples/population/population.css

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,35 @@ svg {
22
font: 10px sans-serif;
33
}
44

5-
text.title {
6-
font: 300 78px Helvetica Neue;
7-
fill: #666;
5+
.y.axis path {
6+
display: none;
87
}
98

10-
.rule line {
9+
.y.axis line {
1110
stroke: #fff;
1211
stroke-opacity: .2;
1312
shape-rendering: crispEdges;
1413
}
1514

16-
.rule:first-child line {
15+
.y.axis .major line {
1716
stroke: #000;
1817
stroke-opacity: 1;
1918
}
2019

20+
.title {
21+
font: 300 78px Helvetica Neue;
22+
fill: #666;
23+
}
24+
25+
.birthyear,
26+
.age {
27+
text-anchor: middle;
28+
}
29+
30+
.birthyear {
31+
fill: #fff;
32+
}
33+
2134
rect {
2235
fill-opacity: .6;
2336
fill: #e377c2;

examples/population/population.js

Lines changed: 68 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,37 @@
1-
var width = 960,
2-
height = 500;
1+
var margin = {top: 10, right: 30, bottom: 20, left: 10},
2+
width = 960,
3+
height = 500 - margin.top - margin.bottom,
4+
barWidth = 48;
35

46
var x = d3.scale.linear()
5-
.range([0, width]);
7+
.range([barWidth / 2, width - barWidth / 2]);
68

79
var y = d3.scale.linear()
8-
.range([0, height - 40]);
10+
.range([height, 0]);
11+
12+
var yAxis = d3.svg.axis()
13+
.scale(y)
14+
.orient("right")
15+
.tickSize(-width)
16+
.tickFormat(function(d) { return Math.round(d / 1e6) + "M"; });
917

1018
// An SVG element with a bottom-right origin.
1119
var svg = d3.select("#chart").append("svg")
12-
.attr("width", width)
13-
.attr("height", height)
14-
.style("padding-right", "30px")
20+
.attr("width", width + margin.left + margin.right)
21+
.attr("height", height + margin.top + margin.bottom)
22+
.style("margin-left", -margin.left + "px")
1523
.append("g")
16-
.attr("transform", "translate(" + x(1) + "," + (height - 20) + ")scale(-1,-1)");
24+
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
1725

18-
// A sliding container to hold the bars.
19-
var body = svg.append("g")
26+
// A sliding container to hold the bars by birthyear.
27+
var birthyears = svg.append("g")
28+
.attr("class", "birthyears")
2029
.attr("transform", "translate(0,0)");
2130

22-
// A container to hold the y-axis rules.
23-
var rules = svg.append("g");
24-
2531
// A label for the current year.
2632
var title = svg.append("text")
2733
.attr("class", "title")
2834
.attr("dy", ".71em")
29-
.attr("transform", "translate(" + x(1) + "," + y(1) + ")scale(-1,-1)")
3035
.text(2000);
3136

3237
d3.csv("population.csv", function(data) {
@@ -39,92 +44,83 @@ d3.csv("population.csv", function(data) {
3944
});
4045

4146
// Compute the extent of the data set in age and years.
42-
var age0 = 0,
43-
age1 = d3.max(data, function(d) { return d.age; }),
47+
var age1 = d3.max(data, function(d) { return d.age; }),
4448
year0 = d3.min(data, function(d) { return d.year; }),
4549
year1 = d3.max(data, function(d) { return d.year; }),
4650
year = year1;
4751

4852
// Update the scale domains.
49-
x.domain([0, age1 + 5]);
53+
x.domain([year1 - age1, year1]);
5054
y.domain([0, d3.max(data, function(d) { return d.people; })]);
5155

52-
// Add rules to show the population values.
53-
rules = rules.selectAll(".rule")
54-
.data(y.ticks(10))
55-
.enter().append("g")
56-
.attr("class", "rule")
57-
.attr("transform", function(d) { return "translate(0," + y(d) + ")"; });
58-
59-
rules.append("line")
60-
.attr("x2", width);
61-
62-
rules.append("text")
63-
.attr("x", 6)
64-
.attr("dy", ".35em")
65-
.attr("transform", "rotate(180)")
66-
.text(function(d) { return Math.round(d / 1e6) + "M"; });
56+
// Produce a map from year and birthyear to [male, female].
57+
data = d3.nest()
58+
.key(function(d) { return d.year; })
59+
.key(function(d) { return d.year - d.age; })
60+
.rollup(function(v) { return v.map(function(d) { return d.people; }); })
61+
.map(data);
6762

68-
// Add labeled rects for each birthyear.
69-
var years = body.selectAll("g")
70-
.data(d3.range(year0 - age1, year1 + 5, 5))
63+
// Add an axis to show the population values.
64+
svg.append("g")
65+
.attr("class", "y axis")
66+
.attr("transform", "translate(" + width + ",0)")
67+
.call(yAxis)
68+
.selectAll("g")
69+
.filter(function(value) { return !value; })
70+
.classed("major", true);
71+
72+
// Add labeled rects for each birthyear (so that no enter or exit is required).
73+
var birthyear = birthyears.selectAll(".birthyear")
74+
.data(d3.range(year0 - age1, year1 + 1, 5))
7175
.enter().append("g")
72-
.attr("transform", function(d) { return "translate(" + x(year1 - d) + ",0)"; });
76+
.attr("class", "birthyear")
77+
.attr("transform", function(birthyear) { return "translate(" + x(birthyear) + ",0)"; });
7378

74-
years.selectAll("rect")
75-
.data(d3.range(2))
79+
birthyear.selectAll("rect")
80+
.data(function(birthyear) { return data[year][birthyear] || [0, 0]; })
7681
.enter().append("rect")
77-
.attr("x", 1)
78-
.attr("width", x(5) - 2)
79-
.attr("height", 1e-6);
80-
81-
years.append("text")
82-
.attr("y", -6)
83-
.attr("x", -x(5) / 2)
84-
.attr("transform", "rotate(180)")
85-
.attr("text-anchor", "middle")
86-
.style("fill", "#fff")
87-
.text(String);
88-
89-
// Add labels to show the age.
90-
svg.append("g").selectAll("text")
91-
.data(d3.range(0, age1 + 5, 5))
82+
.attr("x", -barWidth / 2)
83+
.attr("width", barWidth)
84+
.attr("y", y)
85+
.attr("height", function(value) { return height - y(value); });
86+
87+
// Add labels to show birthyear.
88+
birthyear.append("text")
89+
.attr("y", height - 4)
90+
.text(function(birthyear) { return birthyear; });
91+
92+
// Add labels to show age (separate; not animated).
93+
svg.selectAll(".age")
94+
.data(d3.range(0, age1 + 1, 5))
9295
.enter().append("text")
93-
.attr("text-anchor", "middle")
94-
.attr("transform", function(d) { return "translate(" + (x(d) + x(5) / 2) + ",-4)scale(-1,-1)"; })
96+
.attr("class", "age")
97+
.attr("x", function(age) { return x(year - age); })
98+
.attr("y", height + 4)
9599
.attr("dy", ".71em")
96-
.text(String);
97-
98-
// Nest by year then birthyear.
99-
data = d3.nest()
100-
.key(function(d) { return d.year; })
101-
.key(function(d) { return d.year - d.age; })
102-
.rollup(function(v) { return v.map(function(d) { return d.people; }); })
103-
.map(data);
100+
.text(function(age) { return age; });
104101

105102
// Allow the arrow keys to change the displayed year.
106103
d3.select(window).on("keydown", function() {
107104
switch (d3.event.keyCode) {
108105
case 37: year = Math.max(year0, year - 10); break;
109106
case 39: year = Math.min(year1, year + 10); break;
110107
}
111-
redraw();
108+
update();
112109
});
113110

114-
redraw();
115-
116-
function redraw() {
111+
function update() {
117112
if (!(year in data)) return;
118113
title.text(year);
119114

120-
body.transition()
115+
birthyears.transition()
121116
.duration(750)
122-
.attr("transform", function(d) { return "translate(" + x(year - year1) + ",0)"; });
117+
.attr("transform", "translate(" + (x(year1) - x(year)) + ",0)");
123118

124-
years.selectAll("rect")
125-
.data(function(d) { return data[year][d] || [0, 0]; })
119+
birthyear.selectAll("rect")
120+
.data(function(birthyear) { return data[year][birthyear] || [0, 0]; })
126121
.transition()
127122
.duration(750)
128-
.attr("height", y);
123+
.attr("y", y)
124+
.attr("height", function(value) { return height - y(value); });
129125
}
130126
});

0 commit comments

Comments
 (0)