Animated age pyramid

From JSXGraph Wiki
Revision as of 16:59, 23 November 2009 by A WASSERMANN (talk | contribs)
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

This animation shows data from the 12th coordinated Population Projection from the "Statistisches Bundesamt (destatis)". A much more elaborate version programmed by destatis can be seen on their webpage.

 
 

How to create this animation

  • Download the data from destatis.de
  • Save the table which should be displayed as csv file.
  • Transform the csv file into a JavaScript file containing an 2 dimensional array:
dataV1W1EJ = [["2009"," ","m"," 40 070 ","  341 ","  350 ","  353 ","  348 ",...,"  2 "],
["    "," ","w"," 41 665 ","  323 ","  333 ","  335 ","  329 ",...,"  12 "],
["    "," ","i"," 81 735 ","  663 ","  683 ","  688 ","  677 ",...,"  13 "],
["2010"," ","m"," 39 987 ","  339 ","  341 ","  350 ","  353 ",...,"  2 "],
   .
   .
   .
[" "," ","i"," 64 651 ","  465 ","  470 ","  476 ","  481 ",...,"  169 "]];

Every third row labeled by 'i' in the third column will be deleted later on.

  • Now read the data
function readFile(dataArr) {
    var len = dataArr.length, 
        i, male, female, y,
        data = [];
    for (i=len-1;i>=0;i--) {
        if (i%3==2) {
            dataArr.splice(i,1);
        } else {
            if (i%3==1) {
                female = dataArr[i][3].replace(/ /g,'')*1;
            } else if (i%3==0) {
                y = dataArr[i][0]*1;
                male = dataArr[i][3].replace(/ /g,'')*1;
                data.push([y,male,female]);
            } 
            dataArr[i].splice(0,4); // year,'',m/w,no,
        }
    }
    data.reverse();
    ages = JXG.Math.Matrix.transpose(dataArr);
    return {matrix:ages, total: data};
};
var stat1 = readFile(dataV1W1EJ);
  • Create the filled rectangles (men, women)
brd = JXG.JSXGraph.initBoard('jxgbox', {boundingbox:[-850,110,850,-10],axis:false});
createCurves(stat1,brd,'#658cb2','#b23f8c');

The complete JavaScript code

<script type="text/javascript" src="/ajax/ageV1W1EJ.js"></script>
<jsxgraph width="500" height="500">
var i, t = '', yearIndex = 0, brd;
var stat1 = readFile(dataV1W1EJ);

function readFile(dataArr) {
    var len = dataArr.length, 
        i, male, female, y,
        data = [];
    for (i=len-1;i>=0;i--) {
        if (i%3==2) {
            dataArr.splice(i,1);                  //delete redundant row
        } else {
            if (i%3==1) {
                female = dataArr[i][3].replace(/ /g,'')*1;  
            } else if (i%3==0) {
                y = dataArr[i][0]*1;
                male = dataArr[i][3].replace(/ /g,'')*1;
                data.push([y,male,female]);
            } 
            dataArr[i].splice(0,4); // year,'',m/w,no,
        }
    }
    data.reverse();
    ages = JXG.Math.Matrix.transpose(dataArr);
    return {matrix:ages, total: data};
};

brd = JXG.JSXGraph.initBoard('jxgbox', {boundingbox:[-850,110,850,-10],axis:false});
function createCurves(stat,brd, c1, c2) {
    var i, m = [], w = [],
        op = 1,
        off = 80,
        len = stat.matrix.length;
    for (i=0;i<len;i++) {
        m[i] = brd.create('curve',[[0],[0]],
                {fillColor:c1,strokeColor:c1,
                strokeOpacity:op,fillOpacity:op,
                strokeWidth:1,
                highlightFillColor:'yellow',highlightStrokeColor:'yellow'});
        m[i].updateDataArray = (function(xArr, y) { return function() {
                this.dataX = [-off,-off-xArr[2*yearIndex]*1,-off-xArr[2*yearIndex]*1,-off,-off];
                this.dataY = [y,y,y+1,y+1,y];
            }; })(stat.matrix[i], i);
        JXG.addEvent(m[i].rendNode, 'mouseover', 
            (function(g){ return function(){
                                g.highlight(); w[g._number].highlight(); setText(g._number);
                            };})(m[i]), m[i]);
        JXG.addEvent(m[i].rendNode, 'mouseout', 
            (function(g){ return function(){
                                g.noHighlight(); w[g._number].noHighlight(); 
                            };})(m[i]), m[i]);
        m[i].hasPoint = function(){return false;};
        m[i]._number = i;
    
        w[i] = brd.create('curve',[[0],[0]],
                {fillColor:c2,strokeColor:c2,
                strokeWidth:1,
                strokeOpacity:op,fillOpacity:op,
                highlightFillColor:'yellow',highlightStrokeColor:'yellow'});
        w[i].updateDataArray = (function(xArr, y) { return function() {
                this.dataX = [off,off+xArr[2*yearIndex+1]*1,off+xArr[2*yearIndex+1]*1,off,off];
                this.dataY = [y,y,y+1,y+1,y];
            }; }    )(stat.matrix[i], i);
        JXG.addEvent(w[i].rendNode, 'mouseover', 
            (function(g){ return function(){
                                g.highlight(); m[g._number].highlight(); setText(g._number);
                            };})(w[i]), w[i]);
        JXG.addEvent(w[i].rendNode, 'mouseout',  
            (function(g){ return function(){
                                g.noHighlight(); m[g._number].noHighlight();
                            };})(w[i]), w[i]);
        w[i].hasPoint = function(){return false;};
        w[i]._number = i;
        
    }
    var t = brd.create('turtle',[],{strokeColor:'#999999', highlightStrokeColor:'#999999'}); t.ht().pu().rt(90);
    for (i=0;i<=90;i+=10) { 
        t.moveTo([-750,i]).penDown().forward(750-off+10).penUp();
        t.moveTo([off-10,i]).penDown().forward(750-off+10).penUp();
        brd.create('text',[-15,i,i.toFixed(0)]);
    }
    return [m,w];
};

brd.suspendUpdate();
createCurves(stat1,brd,'#658cb2','#b23f8c');
brd.create('text',[-300,45,'men']/*,{strokeColor:'white',fontSize:20}*/);
brd.create('text',[200,45,'women']/*,{strokeColor:'white',fontSize:20}*/);
brd.unsuspendUpdate();

function changeYear() {
    yearIndex = document.getElementById('years').selectedIndex;
    setTextYear();
    brd.update();
};

function setText(n) {
    var age = n,
        male = ages[n][2*yearIndex]*1,
        female = ages[n][2*yearIndex+1]*1;
    textout.innerHTML = 'age:'+age+
                        ', born in '+(2009+yearIndex-age)+
                        '<br> male:'+male+
                        ', female:'+female+
                        ', together:'+(male+female)+
                        ' (thousand)<br> ratio w/m:'+(female/male).toFixed(2);
};
function setTextYear() {
    var n = yearIndex,
        data = stat1.total;
    textout2.innerHTML = 'Year:'+data[n][0]+
                        '<br> male:'+data[n][1]+
                        ', female:'+data[n][2]+
                        ', together:'+(data[n][1]+data[n][2])+
                        ' (million)<br> ratio w/m:'+(data[n][2]/data[n][1]).toFixed(3);
};

function animation() {
    yearIndex = (yearIndex+1)%52;
    document.getElementById('years').selectedIndex = yearIndex;
    setTextYear();
    brd.update();
    animate = setTimeout(animation,500);
};

function player(){
    if (!animate) {
        document.getElementById('playbutton').value = 'stop';
        animation();
    } else {
        document.getElementById('playbutton').value = 'play';
        clearTimeout(animate);
        animate = null;
    }
};
</jsxgraph>

<form><select id="years" onChange="changeYear()"></select>
<input type="button" id="playbutton" value="play" onClick="player();">
</form>
<div id="output2" style="padding:20px; background-color:#bbbbbb; width:500px; font-family:Arial,Helvetica">&nbsp; </div>
<div id="output" style="padding:20px; background-color:#dddddd; width:500px; font-family:Arial,Helvetica"> &nbsp;</div>
<script type="text/javascript">
    var textout = document.getElementById('output');
    var textout2 = document.getElementById('output2');
    var animate = null;
    selectYear = document.getElementById('years');
    var opt;
    for (i=2009;i<=2060;i++) {
       opt = document.createElement('option');
       opt.text = i;
       try {
          selectYear.add(opt,null);
       } catch(e) {
          selectYear.add(opt); // IE
       }
    }
    setTextYear();

</script>