Animated age pyramid

From JSXGraph Wiki
Revision as of 13: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".

 
 

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 for each year two 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>
This animation shows data from the 12th coordinated Population Projection from the "[http://destatis.de Statistisches Bundesamt]".
<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);
        } 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,d){ 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,d){ 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>