Datavisualisering – kul med statistik och D3.js

Datavisualisering – och "infographics" – är verkligen något som jag alltid har älskat och varit fascinerad av. När jag var liten kunde jag spendera timmar på att studera grafer och diagram i olika uppslagsverk och tidningar. Idag är den stora "förebilden" Nicholas Feltron (tycka vad man vill om Facebooks "Timeline" som han var med och skapade) som minutiöst håller reda på all möjligt statistik om sitt liv, och sedan släpper dem som "årliga rapporter" som visar grafer över allt som han har varit med om och gjort under året.

Att skapa infografik själv är inget som jag varken är vidare duktig på, eller har försökt göra. Men jag håller just nu på med ett projekt där jag ska visualisera viss data för att ge en snabb överblick – och hade tänkt att testa något annat än Google Charts API, nämligen D3.js (D3 = Data Driven Documents) som är ett mycket kraftfullt JavaScript-bibliotek för att plottra ut grafer och diagram från data. Haken med D3.js är ju dock att man bör hantera sin gymnasiematte för att få ett någorlunda bra resultat...

Här nedan visar jag en mycket simpelt diagram över de fem mest förekommande internetleverantörerna (procentuellt) som besökarna av min webbplats använder (fungerar endast i "moderna webbläsare", alltså inte < IE9. Försökt att göra så att den anpassas på bredden – men kan se lite lustigt ut på t.ex. en iPhone). Och om du missade animationen, ladda om sidan:

Det var betyderligt lättare att komma igång med än vad jag hade räknat med, och tänker definitivt fortsätta att experimentera med det för att försöka göra mer avancerade saker.

Här nedan finns den fulla källkoden (kommenterad) för den som är intresserad:

<script type="text/javascript">

    //Ange höjden och bredden på svg-elementet
    var svgHeight = 220;
    var svgWidth = '100%';
    //Skapa en skala med 10 färger som vi kan använda
    var color = d3.scale.category10();

    //Ange datan i JSON
    var data = [
        {name: 'Telia', visitors: 30},
        {name: 'ComHem', visitors: 18},
        {name: 'Tele2', visitors: 12},
        {name: 'Telenor', visitors: 10},
        {name: 'Tre', visitors: 5},
    ];

    //Skapa svg-elementet och append:a den till div#isp
    var svg = d3.select('#isp').append('svg:svg')
    .attr("width", svgWidth)
    .attr("height", svgHeight);

    var elementWidth = document.getElementById("isp");
    //Ett litet extra steg, då den här webbplatsen använder
    //responsiv design, så vill man ju ha bredden på #isp
    elementWidth = elementWidth.offsetWidth;
    //Avståndet mellan cirklarna
    var spacing = elementWidth / (data.length+1);

    //Skapa cirklar
    svg.selectAll("circle")
    .data(data)
    .enter().append("svg:circle")
    .attr("class", "circle")
    //Koordinater i x och y-led, samt radien
    .attr("cx", 0)
    .attr("cy", 100)
    .attr("r", function(d) {
        // d = datum (data i singular)
        // besökarantalet i procent ggr 3
        // anger cirkelns radie
        return d.visitors * 3}
    )
    .style("stroke", "#fff")
    //"Mappa" en färg till cirkeln
    .style("fill", function(d, i) {
        return color(i % 3)
    })
    //En fin liten animation.
    //Cirklarna börjar alla på koordinaterna
    // 0x 100y, men animeras till sin "riktiga"
    // x-position
    .transition()
    .delay(100)
    .duration(2000)
    .attr("x", function(d, i) {
        // Placera cirkeln i x-led:
        // avståndet mellan cirklarna + indexet för
        // datan (ex. 0 = telia, 1 = ComHem etc.)
        return spacing * (i+1);
    });

    //Typ samma som för ovan, men append:ar text
    svg.selectAll("text")
    .data(data)
    .enter().append("svg:text")
    .attr("x", 0)
    .attr("y", 105)
    .attr("text-anchor", "middle")
    .text(function(d) { return d.name;})
    .attr("fill", "#000;")
    .transition()
    .delay(100)
    .duration(2000)
    .attr("x", function(d, i) {
        return spacing * (i+1);
    });
</script>