c3js › Timeseries x values not evenly spaced

爱⌒轻易说出口 提交于 2019-12-01 15:23:39

问题


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!


回答1:


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
        },



回答2:


Set tick.fit to false can make the ticks be positioned according to x value of the data points.

http://c3js.org/reference.html#axis-x-tick-fit

axis: {
  x: {
    tick: {
      fit: true
    }
  }
}

Here's the sample from official site http://c3js.org/samples/axes_x_tick_fit.html




回答3:


I tried all of the answers suggested, but none gave me what I wanted. The closest was Partha's answer, however, selecting category as your chart type creates an unsightly padding on the left and right of the graph.

The solution that worked best for me was to exclude labels from my graph and instead work with an indexed graph. From there, I manually format each index to the proper date using the format function.

Here's a simplified version of the original poster's code:

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

var array_times = [1414540800, 1414627200, 1414627200 + d, 1414627200 + 2 * d, 1414627200 + 3 * d, 1456528117];
var array_values = [67, 66.22, 68, 68, 68, 77];

var labelWeight = 'weight in kg';

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


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


var chart = c3.generate({
    bindto: '#chart',
    data: {
        columns: [
          // Notice that I removed the datetimes from here
          [labelWeight].concat(array_values)
        ],
        type: 'area'
    },
    point: {
        r: 6
    },
    legend: {
        show: false
    },
    grid: {
        x: {
            show: true
        },
        y: {
            show: true
        }
    },
    axis: {
        x: {
            label: {
                text: 'Time [days]'
            },
            type: 'indexed',
            tick: {
                rotate: 90,
                // I reference array_times manually here to 
                // convert the index to a user-friendly label 
                format: function (index) {
                    return dateToString(array_times[index]);
                }
            }
        }
    }
});

Working fiddle: http://jsfiddle.net/uop61zLc/1/




回答4:


I also faced the problem.Here is how I have resolved. Use the x-axis as category and not timeseries, and manipulate the corresponding tick format to look as if it is timeseris.

I have simplified the prob to make it generic.

Problem (irregular spacing):

var chart = c3.generate({
            data: {
                x: 'xtime',
                xFormat: '%Y-%m-%d-%H-%M-%S',
                columns: [
                    ['xtime', '2015-05-20-05-10-13', '2015-05-20-05-11-13', '2015-05-21-06-10-13'],
                    ['value', 30, 50, 20]
                ]
            },
            size: {
                height: 300,
                width: 600
            },
            axis: {
                x: {
                    type: 'timeseries',
                    // type: 'category',
                    tick: {
                        // format: function(x) {
                        //     var dateSubs = this.api.categories()[x].split('-'),
                        //         newDate = new Date(dateSubs[0], dateSubs[1], dateSubs[2], dateSubs[3], dateSubs[4], dateSubs[5], 0);
                        //
                        //     return newDate.toLocaleString();
                        // }

                         format: '%e-%b-%Y %H:%M'
                    }
                }
            }
        });
    <link href="https://rawgit.com/masayuki0812/c3/master/c3.css" rel="stylesheet"/>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.js"></script>
    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>

<div id="chart"></div>

Solution :

var chart = c3.generate({
            data: {
                x: 'xtime',
                xFormat: '%Y-%m-%d-%H-%M-%S',
                columns: [
                    ['xtime', '2015-05-20-05-10-13', '2015-05-20-05-11-13', '2015-05-21-06-10-13'],
                    ['value', 30, 50, 20]
                ]
            },
            size: {
                height: 300,
                width: 600
            },
            axis: {
                x: {
                    // type: 'timeseries',
                    type: 'category',
                    tick: {
                        format: function(x) {
                            var dateSubs = this.api.categories()[x].split('-'),
                                newDate = new Date(dateSubs[0], dateSubs[1], dateSubs[2], dateSubs[3], dateSubs[4], dateSubs[5], 0);
                        
                            return newDate.toLocaleString();
                        }

                         // format: '%e-%b-%Y %H:%M'
                    }
                }
            }
        });
<link href="https://rawgit.com/masayuki0812/c3/master/c3.css" rel="stylesheet"/>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.4.10/c3.js"></script>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>

<div id="chart"></div>


来源:https://stackoverflow.com/questions/27469937/c3js-timeseries-x-values-not-evenly-spaced

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!