Data fetching and visualization using d3.js

complex-664440_1280

Data fetching is the process of grabbing data from a data source. In our lora network, packets are shipped off to The Things Network API.

On the web, javascript is what we got for doing computation in a browser. Ajax is a set of techniques used on the client-side to create asynchronous web applications.

ALSO READ: Temperature monitoring with lora

To fetch resources asynchronously, utilize the XMLHttpRequest object:

var trtHttp = (function (my) {
    var http = new XMLHttpRequest();

    my.getJson = function (url, cb) {
        http.onreadystatechange = function () {
            if (http.readyState === XMLHttpRequest.DONE) {
                if (http.status === 200) {
                    cb(JSON.parse(http.responseText));
                }
            }
        };

        http.open("GET", url, true);
        http.send();
    }

    return my;
}(trtHttp || {}));

The wrapping of getJson inside trtHttp is a javascript way of namespacing functions.
With this pattern, member functions of trtHttp can be spread out in different files.

Fetch data from our temperature sensor:

var url = 'http://thethingsnetwork.org/api/v0/nodes/02031003/?limit=200&format=json';

trtHttp.getJson(url, function (data) {
    console.log(data);
});

If you don’t feel the need for going this lowlevel, you can use jQuery:

$.getJSON(url, function (data) {
    console.log(data);
});

This achieve the same thing.

ALSO READ: Sending text with lorawan towards the things network

Data visualization

D3.js is a javaScript library for manipulating documents based on data. Let’s create a bar chart from a dataset containing integers between 0 and 10.

barchart-integers-2

var data = [1,2,3,4,5,6,7,8,9]

var margin = {
    bottom: 10,
    top: 10,
    left: 50,
    right: 20
};

var width = 500;
var height = 300;

var chartWidth = width - margin.left - margin.right;
var chartHeight = height - margin.top - margin.bottom;

var yScale = d3.scale.linear()
    .domain([0, 10])
    .range([chartHeight, margin.bottom + margin.top])

var yAxis = d3.svg.axis()
    .scale(yScale)
    .orient('left');

var svg = d3.select('body')
    .append('svg')
    .attr('width', width)
    .attr('height', height)

var chart = svg.append('g')
    .attr('width', chartWidth)
    .attr('height', chartHeight)
    .attr('transform', "translate(" + margin.left + ",0)")

svg.append('g')
    .attr('transform', "translate(30,0)")
    .attr("class","axis")
    .call(yAxis)

chart.selectAll('rect')
    .data(data)
    .enter()
    .append('rect')
    .attr('fill', function (d) {
        return "rgb(0, 0, " + (d * 30) + ")";
    })

    .attr('x', function (d, i) {
        return i * chartWidth / data.length
    })

    .attr('y', function (d) {
        return yScale(d);
    })

    .attr('width', chartWidth / data.length-1)

    .attr('height', function (d) {
        return yScale(0) - yScale(d);
    })

To fit our data of integers onto an svg we need to convert the integer range [0, 10] to [0, 300]. This is needed because otherwise the bars would be very small since the height of the svg is 300 pixels.
The d3.scale function performs the conversion. We need only provide it with an input domain and an output range.

To use the data from our temperature node, we simply wrap the code inside a json data fetch block:

trtHttp.getJson(url, function (data) {

    var data = data.map(function (item) {
        return item.data_json;
    })

    [...]
})

The temperature node location is in our office right now, so temperature values vary between 22 and 23 celcius.
The graph is not particurlarly exciting. Here it is:

barchart-temperatures

  • Dag Jomar Mersland

    Very cool 🙂

    Btw, you can simplify the http request by using jQuery 😉