当给定在C3js图表中呈现的非连续日数组时,直接在点之间绘制线条。是否有一个设置允许C3js将未提供的天数解释为具有值0,这样非连续天数之间的线将在中间日期首先降至值0,然后再回升到下一个提供的日期值?
我可以想象,临时替代方案是使用条形图,但我更喜欢折线图。
以上是不良结果的图像,其中分散的数据点直接连接,而在中间期间不会降至0值。
我创建的一个方法,作为一个临时解决方案,是编写一个函数,它只生成一个日期数组,该数组从日值数组的第一个日期到最后一个日期。它为原始日期数组中索引为-1的天提供0值。
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);
});
答案 0 :(得分:2)
问题是c3不会将缺少的日期解释为空值或0,只是您未声明感兴趣的日期,因此您的解决方案看起来就像是要走的路。
我假设您已将connectNull
设置为true,因为您的屏幕截图有两个系列,其中一些数据点存在于一个系列中而不存在于另一个系列中,但它们会像connectNull
那样被跳过
您可以通过仅在现有日期之前和之后放置“零天”来提高您的代码效率,而不是填写所有中间日期。示例改编自http://c3js.org/samples/timeseries.html。它可能会渲染得更快,并且不会产生额外的刻度。
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'
}
}
}
});
答案 1 :(得分:0)
我喜欢 mgraham 在现有日期前后放置“零天”的想法,但 d3.set 位对我不起作用,所以我想我会用自己的方式来做。没有设置插入,所以我想它可能会运行得稍微快一点(都是非常顺序的),但是我的代码显然没有那么优雅!
var dates = ['2013-01-01', '2013-01-02', '2013-01-08', '2013-01-09', '2013-05-02']; //I'm assuming this is ordered!
var values = [30, 200, 400, 150, 250];
var chosen_start_date = new Date("2012-01-01"); //chosen start of date range
var chosen_end_date = new Date("2014-01-01"); //chosen end of date range
var new_dates = [];
var new_values = [];
var prev_real_date = new Date("0001-01-01");
var following = chosen_start_date;
for (var i=0; i<dates.length; i++) {
date = dates[i];
date_obj = new Date(date);
if (!moment(date_obj).isSame(following,'day')) {
// Following on from an earlier real date value we need to add a zero
new_dates.push(moment(following).format('YYYY-MM-DD'));
new_values.push(0);
}
earlier = new Date(date_obj);
earlier.setDate(date_obj.getDate() - 1);
if (!moment(prev_real_date).isSame(earlier,'day') && !moment(following).isSame(earlier,'day')) {
// Before this real date value we need to add a zero
new_dates.push(moment(earlier).format('YYYY-MM-DD'));
new_values.push(0);
}
following = new Date(date_obj);
following.setDate(date_obj.getDate() + 1);
//Push this real date value
new_dates.push(moment(date).format('YYYY-MM-DD'));
new_values.push(values[i]);
prev_real_date = date_obj;
}
if (moment(chosen_end_date).isAfter(date_obj)) {
// Add final zeros to take us to the end date
new_dates.push(moment(following).format('YYYY-MM-DD'));
new_values.push(0);
if (moment(chosen_end_date).isAfter(following)) {
new_dates.push(moment(chosen_end_date).format('YYYY-MM-DD'));
new_values.push(0);
}
}
//new_dates & new_values ready to use in c3js
console.log(new_dates);
console.log(new_values);