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
46var x = d3 . scale . linear ( )
5- . range ( [ 0 , width ] ) ;
7+ . range ( [ barWidth / 2 , width - barWidth / 2 ] ) ;
68
79var 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.
1119var 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.
2632var 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
3237d3 . 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