问题
I have a dc.js lineChart that is showing the number of events per hour. I would like rather than joining the line between two known values the value should be shown as zero.
So for the data below I would like to have the line drop to zero for 10AM
{datetime: "2018-05-01 09:10:00", event: 1}
{datetime: "2018-05-01 11:30:00", event: 1}
{datetime: "2018-05-01 11:45:00", event: 1}
{datetime: "2018-05-01 12:15:00", event: 1}
var eventsByDay = facts.dimension(function(d) { return d3.time.hour(d.datetime);});
var eventsByDayGroup = eventsByDay.group().reduceCount(function(d) { return d.datetime; });
I've had a look at defined but don't think that is right, I think I need to add the zero value into the data for each hour that has no data? However I'm not sure how to go about it and I can't seem to find an example of what I'm trying within dc.js
This other question does answer this but for d3.js and I'm unsure how to translate that - d3 linechart - Show 0 on the y-axis without passing in all points?
Can anyone point me in the right direction?
Thanks!
回答1:
You are on the right track with ensure_group_bins
but instead of knowing the required set of bins beforehand, in this case we need to calculate them.
Luckily d3 provides interval.range which returns an array of dates for every interval boundary between two dates.
Then we need to merge-sort that set with the bins from the original group. Perhaps I have over-engineered this slightly, but here is a function to do that:
function fill_intervals(group, interval) {
return {
all: function() {
var orig = group.all().map(kv => ({key: new Date(kv.key), value: kv.value}));
var target = interval.range(orig[0].key, orig[orig.length-1].key);
var result = [];
for(var oi = 0, ti = 0; oi < orig.length && ti < target.length;) {
if(orig[oi].key <= target[ti]) {
result.push(orig[oi]);
if(orig[oi++].key.valueOf() === target[ti].valueOf())
++ti;
} else {
result.push({key: target[ti], value: 0});
++ti;
}
}
if(oi<orig.length)
Array.prototype.push.apply(result, orig.slice(oi));
if(ti<target.length)
Array.prototype.push.apply(result, target.slice(ti).map(t => ({key: t, value: 0})));
return result;
}
}
}
Basically we iterate over both the original bins and the target bins, and take whichever is lower. If they are the same, then we increment both counters; otherwise we just increment the lower one.
Finally, when either array has run out, we append all remaining results from the other array.
Here is an example fiddle based on your code.
It's written in D3v4 but you should only have to change d3.timeHour
in two places to d3.time.hour
to use it with D3v3.
I'll add this function to the FAQ!
来源:https://stackoverflow.com/questions/50296863/dc-js-linechart-fill-missing-dates-and-show-zero-where-no-data