Reputation: 41
Using d3.js v3.55, crossfilter.js v1.311 and dc.js v1.73 and trying to build an reduce function that returns an average as opposed to a sum or count. The reduceSum which is builtin working fine, but when I try to add my own reduce function, based on many examples on the internet. I receive the messages: d3.js:5942 Error: Invalid value for attribute transform="translate(NaN,0)" d3.js:8718 Error: Invalid value for attribute width="NaN"
Here is the code reduced as much as I can without eliminating any important information:
<script type="text/javascript">
//
// Create the Chart Objects
//
var GeoZoneChart = dc.rowChart("#chart-geo-zone");
var pdcData = [
{GeoZone: 'New York Metro', PDCLast365: 0.43},
{GeoZone: 'New York Metro', PDCLast365: 0.427},
{GeoZone: 'New York Metro', PDCLast365: 0.418},
{GeoZone: 'Los Angeles Metro', PDCLast365: 0.4085},
{GeoZone: 'Los Angeles Metro', PDCLast365: 0.40565},
{GeoZone: 'Chicago Metro', PDCLast365: 0.46789457},
{GeoZone: 'Chicago Metro', PDCLast365: 0.46366023},
{GeoZone: 'Chicago Metro', PDCLast365: 0.447781455}
];
//
// normalize/parse data
// in this case, turn the decimel into a percentage
pdcData.forEach(function(d) {
d.PDCLast365 = d.PDCLast365 * 100;
d.PDCLast365 = d.PDCLast365.toFixed(2);
});
function isNumeric(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
function reduceAddAvg(attr) {
return function(p,v) {
if (isNumeric(v[attr]) ){
++p.count;
p.sum += v[attr];
p.avg = p.sum/p.count;
}
return p;
};
}
function reduceRemoveAvg(attr) {
return function(p,v) {
if (isNumeric(v[attr]) ){
--p.count;
p.sum -= v[attr];
p.avg = p.sum/p.count;
}
return p;
};
}
function reduceInitAvg() {
return {count:0, sum:0, avg:0};
}
//
// set crossfilter
//
var ndx = crossfilter(pdcData),
GeoZoneDim = ndx.dimension(function(d) {return d.GeoZone;}),
PDCLast365PerGeoZone =
GeoZoneDim.group().reduce(
reduceAddAvg('PDCLast365'),
reduceRemoveAvg('PDCLast365'),
reduceInitAvg);
GeoZoneChart
.width(400).height(200)
.dimension(GeoZoneDim)
.group(PDCLast365PerGeoZone)
.elasticX(true);
dc.renderAll();
</script>
Upvotes: 4
Views: 8035
Reputation: 102
I usually get that Error when the range is not an Array.
Check if the variable that .range
receives is an actual Array
Upvotes: 0
Reputation: 20150
You need a guard for when p.count
falls to zero. So:
function reduceRemoveAvg(attr) {
return function(p,v) {
if (isNumeric(v[attr]) ){
--p.count;
p.sum -= v[attr];
p.avg = p.count ? p.sum/p.count : 0;
}
return p;
};
}
Obliged if you can point to any such bad examples here on SO or on the dc.js site or user group.
EDIT: I'm not sure what effect it will have here, but toFixed() actually returns a string, not a number. And your isNumeric
tests whether the value can be converted to a number, not whether it is a number. So you might end up with string concatenation not addition.
Like I say below, the right way to figure this or is by putting breakpoints in the reduce functions and seeing what's actually being calculated.
Upvotes: 1