02 August 2015

Posted by: Duncan
Tags: JavaScript | D3

My brain hurts!, as Mr Gumby would say. Mine certainly did after an afternoon with D3 and Dr. Voronoi.

D3 is not your average dataviz library. It almost always needs a bit of coaxing to do what you want. For example, to work in a responsive, multi-platform app, some tinkering with wrapper CSS was required; to implement user-feedback on a multi-line chart similarly needs some effort as it's not available out-of-the-box.

There are two practical ways to implement feedback on multi-line charts. One is to use a Voronoi mesh (or tessellation); the other is to capture the x-position of the mouse cursor and return all y-data at the same time. The first approach is the subject of this entry. But, rather than rambling on about something that's available on the net, here's the finished Voronoi-flavoured article;



The data is weather data for Stornoway, courtesy of the Met Office, and shows annualised min/max temperatures over a given period. The chart uses a new EGD3Line class and is used as follows;

$.ajax(
   {
      url         : "/charts/?limit=960",
      type        : "get",
      dataType    : "json",
      success     : function(data)
      {
         var max_y = d3.max(data.data, function(d) {
            return parseFloat(d.tmax); 
         });
         
         try
         {
            var line_chart = new EGD3Line({
               container       : 'responsive-container',
               margin          : {top: 10, right: 10, bottom: 40, left: 50},
               max_y           : Math.round(max_y + Math.ceil(2)),
               min_y           : 0,
               x_key           : 'year',
               x_axis_title    : 'Year',
               y_axis_title    : 'Temp \u2103 (annualised)',
               interpolate     : false,
               aspect_ratio    : 1.667,
               horizontal_grid : true,
               vertical_grid   : true
            });
            
            line_chart.attach_data(data.data);
            line_chart.draw_chart();
            line_chart.draw_lines ([ 
               {y_key: 'tmin', class_name: 'line-tmin' }, 
               {y_key: 'tmax', class_name: 'line-tmax' } ]);
         } 
            catch(e)
         {
            console.log(e.name + ", " + e.message);
         }
      }
   });

Although the new class is both reusable and responsive, the Voronoi technique makes dynamic data hard to achieve; if the data changes, for example in an active time-series chart showing some real-time properties, then the Voronoi mesh has to be recreated constantly. However, for static data, this may be a usable option.

The wrapper class is styled with an external CSS file. Both can be grabbed from github.

Links