Selles loengus esitatakse:
Üks tähtsamaid mingi maa arengu- ja elatustaseme näitajaid on sisemajanduse koguprodukt ühe elaniku kohta - GDP Per Capita (Gross Domestic Product per capita) - kui palju (rahas) maa iga elanik aasta jooksul toodab; see määrab ka maa elatustaseme - keegi ei saa kulutada rohkem kui toodab.
Valime andmed (näiteks) rahvusvahelise rahafondi IMF (International Monetary Fund) euro-ala riikide andmebaasist. Valime võrdlemiseks mõned riigid (järgnevas: Eesti, Soome, Saksamaa, Sloveenia) ja näitajaks sisemajanduse koguprodukti ühe elaniku kohta (Gross domestic product per capita, constant prices) - see on tähtsaim riigi elatustaset mõjutav näitaja - kui elanike tootlikus on väike, ei saa ka elamistase kõrge olla.
Valime ajavahemikuks 1993..2013 (Eesti anmed algavad alles aastast 1993), jätame ära maakohased märkused, tühjad read ja valime reaalosa eraldajaks koma (eemaldame 'Append Country/Series-specific Notes', "'Remove rows with no data' ) ja salvestame raporti.
Saadud faili weoreptc.aspx (see on puhas ASCII) avamisel Notepad++-is, kui Notepad++-s valida "View- Show symbol - Show All Characters" näeme, et tekst koosneb seitsmest reast, mis on eraldatud sümbolitega (CRLF - Carriage Return, reavahetus, LF - Line Feed - uus rida, standartne rea-eraldaja Windows-is) ja sait on siiski lisanud ka ühe tühja rea (eelviimase). Kuna Javascript ei oska nende sümbolitega midagi peale hakata, asendame nad Notepad++ 'Otsi ja Asenda' laiendatud asendamisfunktsiooniga (Search - Replace - Extended):
Find what: \r\n\r\n Replace with: \r\n\ \\eemaldame tühja rea Find what: \r\n Replace with: *RV* \\ asendame reavahetuse märkidega *RV*
Sellega kõik muutub üheks reaks; võtame selle kõik jutumärkidesse, nii et see muutub üheks Javascripti stringiks ja lisame selle ette var data = ; salvestame modifitseeritud teksti failina weoreptc.js - see on nüüd ühe Javascripti stringi kirjeldus.
Faili Notepad++-is vaadates näeme, et viimased veerud (aasta 2013 ja pärast seda) pole kasutamiskõlblikud, kuid Notepad++-is on veerude eemaldamijne tülikas, seda peab tegema juba Javascriptiga.
Kuna andmeobjekt sisaldab kogu infot (millist muutujat, milliste maade jaoks ja millal mõõdeti, s.t. mõõtmiste algus- ja lõpuaasta) saab seda taas kasutada graafikule allkirja moodustamiseks, sellepärast vormistame html-lehel kanvaa kahe div-i abil: välimise abil saab määrata kanvaa asukoha lehel, sisemine (div inf kanvaa all) esitab graafiku allkirja, näiteks siin
<div class="pilt_paremal"> <canvas id="canvas" width="500" height="300"></canvas> <div id="inf"></div> </div>
Impordime html5-faili peas selle andmefaili (andmed peavad juba olemas olema enne graafiku joonistamise skripti!) ja värvime kanvaa tausta õrnalt sinakaks (siis on see html-lehel kohe näha):
<style> canvas{ background-color:#fdfdff;} </style> <script src="js/data.js"> </script>
Kogu graafikut joonistav programm on funktsioonis draw() , mis käivitatakse html5-lehe keha (body) laadimisel:
<body onload="draw();">
Funktsioon draw() algab kanvaa leidmise, joonistamiskonteksti ctx loomise, kanvaa mõõtmete salvestamisega muutujates w,h.
Andmed on muutujas data ühe stringina, jagame selle ridadeks split('*RV*) moodustab massiivi, kus iga rida on element; kuna pärast seda on kõik read üks string, jagame ka read massiiviks.
Nüüd saab tabeli iga ruutu selle kahekordse massiivi indeksite abil addresseerida.
Leiame andmetest kasutamiskõlblikud veerud - veerud, kus esimeses reas on arv (aasta), viiimane tuleb eemaldada; testimiseks laseme need väärtused ka konsoolile (ilmub brauserites - Firefox, Chrome) IE F12 vajutamisel:
function draw(){ var canvas = document.getElementById("canvas"); if (canvas.getContext) { var ctx = canvas.getContext("2d"); } else alert("This browser does not recognize canvas - update your browser!"); var inf = document.getElementById("inf"); //info esitamiseks var w = canvas.width; var h = canvas.height; //data.replace(',',''); // kui arvutis on reaalarvu eraldajaks määratud '.' data = data.split('*RV*'); // data - ridade massiiv for(var i = 0; i < data.length; i++) data [i] = data[i].split('\t'); //iga rida - massiiv //console.log(data[0].length) //kontrolliks; //maad on esimene sõna teisest kuni eelviimase reani var countries = []; for (var i = 1; i < data.length - 1; i++) countries.push(data[i][0]); console.log(countries); var dataInd = []; //indeksid kus esimeses reas on arv, s.t. aasta for (var i = 0; i < data[0].length-1; i++){ //viimane veerg ei kõlba if (!(isNaN(data[0][i]))) dataInd.push(i); } dataInd.pop(); // viimane ei kõlba ! console.log(dataInd); var n = dataInd.length;
Graafiku telgede joonistamisel jätame selle ümber vaba ruumi, selle laius-kõrgus on määratud muutujatega xPadding, yPadding. Täiendame funktsiooni draw() telgede joonistamisega; erinevate maade graafikud joonistame eri värviga
var xPadding = 40; //vaba ala x-telje suunas var yPadding = 40; //vaba ala y-telje suunas ctx.strokeStyle = '#333'; //r=g=b - tume (3) hall ctx.beginPath(); ctx.moveTo(xPadding, yPadding); ctx.lineTo(xPadding, h - yPadding); // vahe ääreni ctx.lineTo(canvas.width-xPadding, h - yPadding); ctx.stroke(); //teeb jooned nähtavaks var allColors = ["#FF0000","#00FF00","#0000FF","#990033","#339900","#FFFF00","#00FFFF","#FF00FF","#003399"];
Paigutame graafiku nii, et see maksimaalselt täidab telgedega piiratud ala, selleks peab leidma nii argumendi väärtuste (aastate) kui ka funktsiooni väärtuste minimaalsed ja maksimaalsed väärtused. Funktsioon getMaxMin() on kirjeldatud nii, et see kohe ka käivitatakse;
Et y-teljel väärtuste tähistused oleks tuhandetes, modifitseerime minY, maxY väärtusi kuni järgimse täis-tuhandeni:
// get max min values var minX = minY = 100000, maxX = maxY = 0; // kindlasti kõigist suurem/väiksem ! (function getMaxMin(){ for(var i = dataInd[0]; i < dataInd[0]+dataInd.length-1; i++){ if (parseFloat(data[0][i]) < minX) minX = parseFloat(data[0][i]); if (parseFloat(data[0][i]) > maxX) maxX = parseFloat(data[0][i]); for(var j = 1; j < data.length - 1; j++) { if (parseFloat(data[j][i]) < minY) minY = parseFloat(data[j][i]); if (parseFloat(data[j][i]) > maxY) maxY = parseFloat(data[j][i]); } }})(); console.log(minX,maxX,minY,maxY); // //ümmardame Y väärtused : minY = minY - minY%1000; maxY = maxY + (1000-maxY%1000); console.log(minY,maxY);
Argumendi ja funktsiooni väärtuste graafikule kandmiseks on tarvis funktsioone, mis skaleerivad väärtuse pikslite asukohaks:
function getXPixel(val) { return (((w - 2*xPadding) / n) * (val - minX) + xPadding); } function getYPixel(val) { return (((h - 2*yPadding) / (maxY - minY)) * (maxY - val) + yPadding); }
Kanname X-teljele argumendi minimaalse ja maksimaalse väärtuse, nende vahele 5-ega jaguvad väärtused ja joonistame graafiku;
for(var i = 0; i < n; i ++) { if (data[0][dataInd[i]]%5 == 0) //kanname X-telejele vaid 50-ga jaguvad aastad ctx.fillText(data[0][dataInd[i]], getXPixel(data[0][dataInd[i]]), h - yPadding/2 ); } //lisame esimese ja viimase ctx.fillText(data[0][dataInd[0]], getXPixel(data[0][dataInd[0]]), h - yPadding/2 ); ctx.fillText(data[0][dataInd[dataInd.length-1]], getXPixel(data[0][dataInd[dataInd.length-1]]), h - yPadding/2 ); // kanname y-teljele 2000-ga jaguvad väärtused ctx.textAlign = "right"; for(var i = minY; i <= maxY; i +=2000) ctx.fillText(i, xPadding-2, getYPixel(i) ); inf.innerHTML=data[1][1]+", "+minX+".."+maxX;
Joonistame maade graafikud, vaides iga maa jaoks erineva värvi ja kirjutades maa nime selle graafiku algusesse:
//joonistame graafikud, valides iga maa jaoks värvi massiivist allColors: ctx.lineWidth = "2"; ctx.textAlign = "left"; ctx.font="16px Arial"; for (var j = 0; j < countries.length; j++){ ctx.strokeStyle = ctx.fillStyle = allColors[j]; // // = allColors[j]; //ctx.fillText(countries[j],1.5*xPadding+j*100,2*yPadding); ctx.fillText(countries[j],1.5*xPadding,getYPixel(parseFloat(data[j+1][dataInd[0]]))); ctx.beginPath(); ctx.moveTo(getXPixel(data[0][dataInd[0]]), getYPixel(parseFloat(data[j+1][dataInd[0]]))); console.log(data[0][dataInd[0]], data[j+1][dataInd[0]]); console.log(getXPixel(data[0][dataInd[0]]), getYPixel(parseFloat(data[j+1][dataInd[0]]))); for(var i = 1; i < n; i ++) { ctx.lineTo(getXPixel(data[0][dataInd[i]]), getYPixel(parseFloat(data[j+1][dataInd[i]]))); } ctx.stroke(); inf.innerHTML += countries[j]+" "; }
Nagu näha, oli Eesti elatustase 90-ndate alguses peaaegu kaks korda kehvem kui post-sotsialistlikus Sloveenias ja 6-7 korda kehvem kui Soomes ja Saksamaal. Kuigi Eesti GPD elaniku kohta on tõusnud ja erinevus Sloveeniaga veidi vähenenud, kuid Sakamaale või Soomele järele jõudmisest ei paista mingit märki.
Ülesandeid
1. Modifitseeri graafikut nii, et see näitab näitajate suhet, näiteks mitu korda teiste maade GDP on Eesti omast suurem (eesti on siin kõige väiksem väärtus) - see võimaldab näha arengudententse, kas suhteline erinevus kasvab või kahaneb.
2. Kasutataud IMF-i andmebaasis on paljude maade andmed; lae alla kõigi maade andmed samal ajavahemikul 1993..2013. Nende korraga näitamine samal graafikul muudab pildi liiga kirjuks ja ebaülevaatlikuks - tee graafik, kus on vorm, millest kasutaja saab valida korraga graafikul näidatavad (võrreldavad) maad.
© Jaak Henno