d3.jstime-seriesc3.jstimeserieschart

Assume value 0 on days with no data (C3js time series chart)


When given an array of non-consecutive days rendered in a C3js chart, lines are drawn directly between points. Is there a setting that allows C3js to interpret days not supplied as having value 0, such that lines between non-consecutive days will drop to value 0 first on the intervening days before rising back up to the next supplied day's value?

An temporary alternative, I could imagine, would be the use of a bar chart, but I would prefer a line graph.

Undesirable results Above is an image of an undesirable result, wherein dispersed data points are connected directly, without dropping to value 0 for the intervening period.

Temporary solution

A method that I have created, as a temporary solution, is to write a function that just produces an array of dates that go from the first to the last date of the day values array. It provides a 0 value then for days that have index of -1 in the original date array.

var newKeysDay = getDatesArray(firstDay, lastDay);
var newValsDay = [];
newKeysDay.forEach(function (day) {
  var i = keysDay.indexOf(day);
  if (i > -1) newValsDay.push(valsDay[i]);
  else newValsDay.push(0);
});

Solution

  • The trouble is c3 doesn't interpret missing dates as nulls or 0's, just dates you haven't declared an interest in, so your solution looks like the way to go.

    I'm assuming you already set connectNull to true as your screenshot has two series where some data points are present in one series and not in another, but they are jumped over like connectNull would do.

    You could make your code more efficient by only placing "zero days" before and after existing dates and not fill in all the in-between dates too. Example adapted from http://c3js.org/samples/timeseries.html. It might render a bit faster and it doesn't produce loads of extra ticks.

    var dates = ['2013-01-01', '2013-01-02', '2013-01-03', '2013-01-11', '2013-01-08', '2013-01-09', '2013-05-02'],
        val1 = [30, 200, null, 400, 150, 250],
        val2 = [130, 340, 200, 500, 250, 350];
    
        var dateSet = d3.set(dates);
        var df = d3.time.format("%Y-%m-%d");
    
        var addIfNeeded = function (d, inc) {
            var nbour = new Date (d);
            nbour.setDate (nbour.getDate() + inc);
            var nf = df(nbour);
    
            if (!dateSet.has(nf)) {
                dateSet.add (nf);
                dates.push (nf);
                val1.push (0);
                val2.push(0);
            };
        }
    
        dates.slice(0).forEach (function(date) {
            var d = new Date(date);
            if (val1[i] === null) { val1[i] = 0; }
            if (val2[i] === null) { val2[i] = 0; }
            addIfNeeded (d, 1);
            addIfNeeded (d, -1);
        })
    
        console.log ("dates", dates, val1, val2);
    
    
    
    var chart = c3.generate({
        data: {
            x: 'x',
            columns: [
                ['x'].concat(dates),
                ['data1'].concat(val1),
                ['data2'].concat(val2)
            ]
        },
        axis: {
            x: {
                type: 'timeseries',
                tick: {
                    format: '%Y-%m-%d'
                }
            }
        }
    });