c3js › Timeseries x values not evenly spaced

2dvisio picture 2dvisio · Dec 14, 2014 · Viewed 15.8k times · Source

I am having an issue with the labels assigned to the values of my graph.

The graph is a timeseries. I add values using the 'columns' property of c3js.

I use pure timestamps (in seconds) and then convert them into strings using the label.format.

However, this is what happens:

https://drive.google.com/file/d/0B9GDftIYQFIVb2Z3N2JfS2pzVjg/view?usp=sharing

as you can notice the space is not evenly distributed, between 18-21, 25-28 October and 1-4, 4-7 November just two days while all others have three days between the dates.

What is causing this?

I would like to have evenly spaces gaps (same number of days).

Here is a jfiddle with the code: http://jsfiddle.net/ok1k6yjo/

var array_times = [1414540800, 1414627200];
var array_values = [67, 66.22];

var labelWeight = 'weight in kg';

var window_period = (30 * 24 * 3600); // last 30 days

var today = Math.floor(new Date(2014,10,20,0,0,0,0).getTime() / 1000);
var timeEnd = today;
var timeStart = today - window_period;

var toShowTime = [1414540800, 1414627200];
var toShowValues = [67, 66.22];


var minT = Math.min.apply(null, array_times),
    maxT = Math.max.apply(null, array_times.concat(today));

var minV = Math.min.apply(null, array_values),
    maxV = Math.max.apply(null, array_values);

function dateToString(e) {
    var date = new Date(e * 1000);
    return date.toDateString().substring(4);
}


var chart = c3.generate({
    bindto: '#chart',
    data: {
        x: 'times',
        columns: [
            ['times'].concat(toShowTime), 
            [labelWeight].concat(toShowValues)],
        labels: {
            format: {
                y: d3.format('.2')
            }
        },
        type: 'scatter'
    },
    point: {
        r: 6
    },
    legend: {
        show: false
    },
    grid: {
        x: {
            show: true
        },
        y: {
            show: true
        }
    },
    axis: {
        x: {
            label: {
                text: 'Time [days]'
            },
            type: 'timeseries',
            tick: {
                fit: false,
                //count: 29,
                rotate: -75,
                multiline: false,
                format: function (e, d) {
                    return dateToString(e);
                }
            },
            height: 100
        },
        y: {
            label: {
                text: 'Weight [kg]',
                position: 'outer',
                min: minV - 10,
                max: maxV + 10
            },
            tick: {
                format: function (e, d) {
                    return parseFloat(e).toFixed(2);
                }
            },
        }
    }
});

chart.axis.range({min: {x:timeStart, y:minV-10}, max: {x:timeEnd, y:maxV+10}});

The slight difference is due to a different starting date.

Here is another fiddle with similar issues. http://jsfiddle.net/hfznh45w/5/

var d = (24 * 3600); // last 30 days


//var array_times = [1414540800-8*d, 1414540800-d, 1414540800, 1414627200, 1414627200 + d, 1414627200 + 2 * d, 1414627200 + 3 * d];
//var array_values = [61, 60, 67, 66.22, 68, 68, 68];

var array_times = [];
var array_values = [];

for (var i = -8; i < 30; i++) {
    array_times.push(1414540800 + (i * d));
    array_values.push(60 + i);
}

console.log(array_times);
console.log(array_values);

var labelWeight = 'weight in kg';

var window_period = (30 * 24 * 3600); // last 30 days

var today = Math.floor(new Date(2014, 10, 20, 0, 0, 0, 0).getTime() / 1000);
var timeEnd = today;
var timeStart = today - window_period;


var minT = Math.min.apply(null, array_times),
    maxT = Math.max.apply(null, array_times.concat(today));

var minV = Math.min.apply(null, array_values),
    maxV = Math.max.apply(null, array_values);

function dateToString(e) {
    var date = new Date(e * 1000);
    return date.toDateString().substring(4);
}


var chart = c3.generate({
    bindto: '#chart',
    data: {
        x: 'times',
        columns: [
            ['times'].concat(array_times), [labelWeight].concat(array_values)],
        labels: {
            format: {
                y: d3.format('.2')
            }
        },
        type: 'scatter'
    },
    point: {
        r: 6
    },
    legend: {
        show: false
    },
    grid: {
        x: {
            show: true
        },
        y: {
            show: true
        }
    },
    axis: {
        x: {
            padding: {
                left: 0,
                right: 0,
            },
            label: {
                text: 'Time [days]'
            },
            type: 'timeseries',
            tick: {
                fit: false,
                rotate: -75,
                multiline: false,
                format: function (e, d) {
                    return dateToString(e);
                }
            },
            height: 100
        },
        y: {
            padding: {
                top: 0,
                bottom: 0
            },
            label: {
                text: 'Weight [kg]',
                position: 'outer',
                min: minV - 10,
                max: maxV + 10
            },
            tick: {
                format: function (e, d) {
                    return parseFloat(e).toFixed(2);
                }
            }
        }
    }
});

chart.axis.range({
    min: {
        x: timeStart,
        y: minV - 10
    },
    max: {
        x: timeEnd,
        y: maxV + 10
    }
});

Any clue/fix is more than welcome. Thank you!

Answer

JasTonAChair picture JasTonAChair · Dec 16, 2014

c3js allows you to specify what ticks will appear on x axis.

Under axis/x/tick I added this -

values: [1413936000, 1414195200,1414454400,1414713600,1414972800,1415232000],

I converted your dates in three day intervals with the epoch converter.

Here's the reference for solution.

I can only assume if the gridlines don't match these three day ticks then they were pushing into a new day every nth tick - hence your issue. Alternatively, you can place gridlines manually.

Here's the code for x axis.

        x: {
            label: {
                text: 'Time [days]'
            },
            type: 'timeseries',
            tick: {
                values: [1413936000, 1414195200,1414454400,1414713600,1414972800,1415232000],
                fit: false,
                //count: 29,
                rotate: -75,
                multiline: false,
                format: function (e, d) {
                    return dateToString(e);
                }
            },
            height: 100
        },