Reputation: 507
I'm new to dc.js so I am probably missing out on something, I have time series data that I am trying to display on 3 time dimensions: by month, by day and by hour - basically to display machine (manufacturing) efficiency across time.
So I made a barchart for the months and hours,and a linechart for the days. code below:
var cfdata = crossfilter(dataArray);
var avgadd = function(p,v) {
p.count++;
p.sum += v.efficiency;
p.avg = p.sum/p.count;
return p;
},
avgremove = function(p,v) {
p.count--;
p.sum -= v.efficiency;
p.avg = p.sum/p.count;
return p;
},
avginit = function(){
return {
count: 0,
sum: 0,
avg: 0
}
};
var parseDate = d3.time.format('%a %b %d %Y %H:%M:%S GMT%Z (UTC)').parse;
dataArray.forEach(function(d) {
d.date = parseDate(d.date);
d.hour = d3.time.hour(d.date).getHours();
d.day = d3.time.day(d.date);
d.month = d3.time.month(d.date);
// d.year = d3.time.year(d.date).getFullYear();
});
// dimensions: efficiency by hour
var hourDim = cfdata.dimension(function(d){return d.hour});
var hourlyEff = hourDim.group().reduce(avgadd, avgremove, avginit);
// dimensions: efficiency by day
var dayDim = cfdata.dimension(function(d){return d.day});
var minDay = dayDim.bottom(1)[0].date;
var maxDay = dayDim.top(1)[0].date;
var dailyEff = dayDim.group().reduce(avgadd, avgremove, avginit);
// dimensions: efficieny by month and year
var monthDim = cfdata.dimension(function(d){return d.month});
var minMonth = monthDim.bottom(1)[0].date;
var maxMonth = monthDim.top(1)[0].date;
var monthlyEff = monthDim.group().reduce(avgadd, avgremove, avginit);
dc.barChart(".month-eff-chart")
.height(180)
.width(900)
.dimension(monthDim)
.group(monthlyEff)
.valueAccessor(function(p){return p.value.avg})
.centerBar(true)
.x(d3.time.scale().domain([minMonth, maxMonth]))
.xUnits(d3.time.months)
.xAxis().ticks(d3.time.month, 1).tickFormat(d3.time.format("%b %y"));
dc.lineChart(".day-eff-chart")
.height(180)
.width(900)
.dimension(dayDim)
.group(dailyEff)
.valueAccessor(function(p){return p.value.avg})
.elasticX(true)
.x(d3.time.scale())
.xUnits(d3.time.days)
.xAxis().ticks(d3.time.week, 1).tickFormat(d3.time.format("%W/%y"));
dc.barChart(".hour-eff-chart")
.height(180)
.width(900)
.dimension(hourDim)
.group(hourlyEff)
.valueAccessor(function(p){return p.value.avg})
.x(d3.scale.linear().domain([0,23]));
dc.renderAll();
so when I open the page and filter across any of the barcharts, the other barchart will filter just fine, but the linechart will just become empty - the lines will completely disappear. when I change the linechart to a barchart, it works - filters just fine.
I must be missing something here.
also, suggestions on how to display time series data in a more meaningful way is also welcome. Thanks!
EDIT: JsFiddle: http://jsfiddle.net/shuzf2vm/2/
Upvotes: 1
Views: 484
Reputation: 20130
The reason that this doesn't work is that your averages will produce NaNs when the count is zero. You need to protect your divisions like this:
var avgadd = function(p,v) {
p.count++;
p.sum += v.efficiency;
p.avg = p.count ? p.sum/p.count : 0;
return p;
},
avgremove = function(p,v) {
p.count--;
p.sum -= v.efficiency;
p.avg = p.count ? p.sum/p.count : 0;
return p;
},
Working fork: http://jsfiddle.net/gordonwoodhull/hsqa43uk/3/
The reason it behaves differently for bar charts versus line charts is interesting. Both protect the output to the drawing functions and detect NaNs. But the bar chart protects each bar individually, while the line chart outputs a single multi-segment line and throws the whole line out if any point is bad.
(It might be more helpful to use d3.svg.line.defined here, if anyone cares to file a PR.)
Upvotes: 2