【问题标题】:Drawing gaps for missing dates in dc.js time series line graph在 dc.js 时间序列折线图中绘制缺失日期的间隙
【发布时间】:2023-07-25 10:24:02
【问题描述】:

好的,我已经看到了this 票和this 问题,并且已经尝试了几个示例。也许我只是密密麻麻,但我真的无法破解这个。

我有一个时间序列的事件,其中有差距。默认情况下,dc.js 在间隙上连接一条直线(使它看起来像实际上不应该出现的东西在那里表示)。例如,在this 图中,我们有如下数据:

    {"time":"2014-06-09T18:45:00.000Z","input":17755156,"output":250613233.333333},
    {"time":"2014-06-09T18:46:00.000Z","input":18780286.6666667,"output":134619822.666667},
    {"time":"2014-06-09T18:47:00.000Z","input":20074614.6666667,"output":203239834.666667},
    {"time":"2014-06-09T18:48:00.000Z","input":22955373.3333333,"output":348996205.333333},
    {"time":"2014-06-09T18:49:00.000Z","input":19119089.3333333,"output":562631022.666667},
    {"time":"2014-06-09T18:50:00.000Z","input":15404272,"output":389916332},
    {"time":"2014-06-09T18:51:00.000Z","input":null,"output":null},
    {"time":"2014-06-09T21:25:20.000Z","input":5266038.66666667,"output":62598396},
    {"time":"2014-06-09T21:26:20.000Z","input":6367678.66666667,"output":84494096},
    {"time":"2014-06-09T21:27:20.000Z","input":5051610.66666667,"output":88812540},
    {"time":"2014-06-09T21:28:20.000Z","input":5761069.33333333,"output":79098036},
    {"time":"2014-06-09T21:29:20.000Z", "input":5110277.33333333,"output":45816729.3333333}

即使只有两组实际的数据,该图上仍有一条线将它们连接起来。如何让 dc.js 折线图在没有数据的地方绘制 0。我试过使用.defined(function(d) { return !isNaN(d.x);}).defined(function(d) { return d.y != null; }) 等,但这只是遍历不存在的数据。

【问题讨论】:

    标签: dc.js crossfilter


    【解决方案1】:

    在使用交叉过滤器时尝试保留空值是很棘手的,因为交叉过滤器是关于聚合的。

    请记住,reduceSum 将添加它找到的任何值,从零开始,0 + null === 0

    在你的情况下,看起来你实际上并没有聚合,因为你的时间戳是唯一的,所以你可以这样做:

    var input  = time.group().reduce(
        function(p, d) {
           if(d.input !== null)
               p += d.input;
           else p = null;
           return p;
        },
        function(p, d) {
           if(d.input !== null)
               p -= d.input;
           else p = null;
           return p;
        },
        function(){ return 0; }
    );
    

    是的,这比reduceSum 复杂得多,如果多个数据落入桶中,它可能会变得更加复杂。 (不确定您想在那里做什么 - 是否可以部分定义数据点?)

    通过这种方式定义的归约,null 归约为 null 并且 dc.js 能够找到差距:

    你的小提琴叉(谢谢!):http://jsfiddle.net/gordonwoodhull/omLko77k/3/

    编辑:计算空值

    如果您要在 bin 中有多个值的情况下进行“真正的”减少,我认为您需要计算非空值的数量并保持运行总和。

    当没有非空值时,总和应该是null

    这次更好地重用我们的代码:

    function null_counter(field) {
        return {
            add: function(p, d) {
                if(d[field] !== null) {
                    p.nvalues++;
                    p.sum += d[field];
                }
                return p;
            },
            remove: function(p, d) {
                if(d[field] !== null) {
                    p.nvalues--;
                    p.sum -= d[field];
                    if(!p.nvalues)
                        p.sum = null;
                }
                return p;
            },
            init: function() {
                return {nvalues: 0, sum: null};
            }
        }
    }
    

    像这样应用(并且这次正确填写字段):

    var input_reducer = null_counter('input');
    var input = time.group().reduce(
        input_reducer.add,
        input_reducer.remove,
        input_reducer.init
    );
    var output_reducer = null_counter('output');
    var output = time.group().reduce(
        output_reducer.add,
        output_reducer.remove,
        output_reducer.init
    );
    

    由于我们要简化为具有两个值 {nvalues, sum} 的对象,因此我们需要使所有访问器更复杂一些:

        .valueAccessor(function(kv) { return kv.value.sum; })
        .defined(function(d){
            return (d.data.value.sum !== null);
        })
    chart.stack(output, "Output bits",
                function(kv) { return kv.value.sum; });
    

    更新分叉:http://jsfiddle.net/gordonwoodhull/omLko77k/9/

    【讨论】:

    • Gordon,在倾注了您回答的所有其他 * 问题之后,我真的希望您能出现在这里!
    • 如果我的时间戳不是唯一的,我将如何聚合的任何建议(例如小提琴:jsfiddle.net/ta3khggy/2)?我在多个方面都遇到了这个问题。感谢您的所有帮助以及你们在框架上所做的工作!
    • 我会考虑一下,明天再修改我的答案。我想最好的办法是任意数量的空值 -> null; 任何数字 -> 忽略空值并添加数字。我认为这意味着你必须计算空值。 :-(
    • 开始使用空计数器或更确切地说是非空计数器进行更新。希望现在还不算晚,如果有效,请告诉我。
    • 绝对不晚;我一直坚持下去,无法拼凑出更好的解决方案。我将在本周晚些时候/结束时尝试一下,然后告诉你进展如何!