Crossfilter 在 dc.js 上显示负数且数据集中没有负数

Crossfilter showing negative numbers on dc.js with no negative numbers in the dataset

我正在使用 CrossFilter 和 dc.js 创建 4 个不同的条形图并允许用户使用图表上的画笔功能更改数据,因此当用户更改一个图表上的画笔时其他动态变化。

除了一个有趣的问题,这一切对我来说都很有用,看起来 CrossFilter 或 dc.js 正在将负值放在图表上,但只有当图表的某些部分是 select编辑。

因此,正如您从图像中看到的那样,当我 select 图表的某个区域似乎没有值时,这在其他图表中显示为负值。

我的数据中有四个项目,日期、类型(字符串)、值(数字)和分组值(这是分组为 50 个较小值块的值)

然后我在每条数据上有 4 个维度和 4 个组,这些被提供给图表。

我的数据中从来没有任何负值,那么我的图表怎么会显示负值呢?

我是 CrossFilter 和 dc.js 的新手,所以我不确定这里显示的最佳方法或最佳代码片段,如果还有其他我应该分享的内容,请告诉我,我真的需要帮助来理解为什么我的图表中有负数。

编辑:添加代码

这是我的数据示例:

[{"Id":"1","InDate":"31/10/2015","Type":"New","Category":"cat1","Value":"1.400874145"}, {"Id":"2","InDate":"21/10/2014","Type":"Old","Category":"cat2","Value":"0"}]

我使用 CSV 文件中的 d3.csv 函数读取了它。我对 CSV 文件中的负值进行了三重检查。

以下是我设置维度的方法:

var ndx = crossfilter(data);

var parseDate = d3.time.format("%d/%m/%Y").parse;

data.forEach(function(d) {
    d.date = parseDate(d.InDate);
    d.valueGrouped = createValueGrouping(parseFloat(d.Value));
});

var dateDim = ndx.dimension(function(d) {return d.date;});
var typeDim = ndx.dimension(function(d) {return d.Type;});
var valueGroupDim = ndx.dimension(function(d) {return d.valueGrouped;});
var categoryDim = ndx.dimension(function(d) {return d.Category;});

这是创建 valueGrouped 属性的函数:

function createValueGrouping(value){
    return 50 * Math.round(value/50);
}

最后是我设置群组的方法:

var timelineGroup = dateDim.group().reduceSum(function(d) {return parseFloat(d.Value);});
var typeGroup = typeDim.group().reduceSum(function(d) {return parseFloat(d.Value);});
var valueGrouped = valueGroupDim.group().reduceSum(function(d) {return parseFloat(d.Value);});
var categoryGroup = categoryDim.group().reduceSum(function(d) {return parseFloat(d.Value);});

编辑 2:添加 JSFiddle

Fiddle - JSFiddle

看起来这些是无穷小的负数,这可能表示由于浮点数没有完全抵消而引起的故障。

当您对数量级差异较大的浮点数进行相加时,运算不一定是关联或分配的,这意味着如果您以不同的顺序相加,您将得到不同的结果。

https://en.m.wikipedia.org/wiki/Floating_point#Accuracy_problems

另外,crossfilter减法的顺序和加法的顺序不同,所以经常出现这种问题。

我建议创建一个假组来包装您的数据,并在它们非常接近时将值设置为零:

function snap_to_zero(source_group) {
    return {
        all:function () {
            return source_group.all().map(function(d) {
                return {key: d.key, 
                        value: (Math.abs(d.value)<1e-6) ? 0 : d.value};
            });
        }
    };
}

在您发现问题的任何地方用这个函数包装您的原始组:

chart.group(snap_to_zero(valueGrouped))