29 January 2014

Posted by: Duncan
Tags: JavaScript

While D3 is clearly the dataviz package for the cognoscenti, sometimes it's a bit over-the-top for a small task for which there is litte time. So I thought I'd better start looking properly at lightweight alternatives; this afternoon's subject is Google Charts. And, specifically, the rigging-up of time-series charts to plot meteorological data.

I grabbed some weather station data from the UK Met Office website, mangled it into an Sqlite3 database so I could serve it up through a simple Django view as a JSON feed, and fed the data to Google Charts. Here's the result;

The data is from Stornoway, from 1873 to 2014. The complete JavaScript code is;

google.load('visualization', '1.0', {'packages':['corechart','line']});
google.setOnLoadCallback(draw_chart);

function draw_chart() 
{
   // Create the data table.
   var data_table = new google.visualization.DataTable();
   data_table.addColumn('number', 'year');
   data_table.addColumn('number', 'tmin');
   data_table.addColumn('number', 'tmax');
      
   $.ajax(
   {
      url         : "/charts/",
      type        : "get",
      dataType    : "json",
      success     : function(data){
            
         for ( var i=0; i<data.data.length; i++)
         {
            data_table.addRow([
               data.data[i].year,
               parseFloat(data.data[i].tmin),
               parseFloat(data.data[i].tmax)
               ]);
         }
            
         var options = 
         {
               hAxis    : { title: 'Year', format: '####' },
               vAxis    : {},
               chartArea: { width: '90%' },
               legend   : { position: 'top'}
         };
            
         var chart = new google.visualization.LineChart( 
            $("#line-chart-div")[0] );
         chart.draw(data_table, options);
      },
      failure     : function(data){
      },
      error       : function(data){ 
      }
   });        
}

NB: I'm using jQuery in this test, hence the use of the $.ajax() function and the chart_div selector.

I've set the JSON feed up to resemble some established resource and in a format that is not directly usable by Google Charts. Records from my feed are in this format;

{"rainfall": "108.50", 
"tmax": "12.15", 
"sunshine": "100.64", 
"tmin": "6.89", 
"year": 2014}

Incidentally, Google offers its Data Source Python Library which can be used to feed a Google chart. The snag with this is, of course, that it is of no use where the feed format is already established (as with commercial feeds).

A big plus point with Google Charts is that it's easy to switch between chart types. For example, I can re-use the dataTable object above and switch to a columnar bar chart by simply using the ColumnChart type;

var column_chart = new google.visualization.ColumnChart( 
                     $("#column-chart-div")[0] );
column_chart.draw(data_table, options);

Which gives;

This data is a bit dense for a column chart so here is a stacked column chart showing tmin and tmax on the same column;

This isn't as easy as it could be because the data needs to be 'adjusted' so that the upper value is the difference between tmax-tmin and then, as this messes up the value shown in the tooltip, that has to be changed too;

for ( var i=0; i<data.data.length; i++)
{
   stacked_data_table.addRow([
      data.data[i].year,
      parseFloat(data.data[i].tmin),
      {
         v:parseFloat(data.data[i].tmax)-parseFloat(data.data[i].tmin), 
         f:data.data[i].tmax
      }
      ]);
}

So the data in the third column (tmax) uses a Google Charts column object, where v is the actual stacked value (not the absolute value) and f is the absolute value in text format, which is the value that is displayed. If this little cludge isn't done then the tooltip will display the wong value (it will show tmax-tmin).

In summary, I like Google Charts. It's slightly fiddly in places and the absence, as far as I can see, of locally-hosted resources may put some off but, in general, it's more than capable of implementing basic charts.

Links