【问题标题】:Performance issue using dc.js使用 dc.js 的性能问题
【发布时间】:2014-06-24 08:02:57
【问题描述】:

我正在尝试使用 dc.js 和引导程序制作一个简单的仪表板。我展示的图表是一个简单的系列图表,其中包含从大约 9000 行的 csv 中提取的三个不同系列、一个从这些系列中选择的饼图和一个用作日期范围选择器的条形图。

一切正常,但性能很糟糕。我认为这一定是由于我缺乏交叉过滤器的经验,因为示例 (http://nickqizhu.github.io/dc.js/) 使用了 6000 条记录并且执行速度非常快。有任何想法吗?我很抱歉缺乏具体性,但我在这里有点迷失了。

我的代码在这里:

d3.csv(sourceFile, function(error, data) {  
        data = data.splice(min,max);
        var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S").parse;
        data.forEach(function(d) {
            d.Date = parseDate(d.date);
            d.Year=d.Date.getFullYear();
            d.Day = d3.time.day(d.Date);
        });
        var ndx2 = crossfilter(melt(data,["Date","Year","Day","date"],"Resource"));
        var meltedDim  = ndx2.dimension(function(d) {return d.Resource;});
        var dateDim = ndx2.dimension(function(d) {return d.Date;});
        var dateTypeDim = ndx2.dimension (function(d) {return [d.Date,d.Resource];});
        var valueGroup = dateTypeDim.group().reduceSum(function(d){return d.value});
        var dayDim = ndx2.dimension(function(d) {return d.Day;});
        var volumeByDayGroup = dayDim.group().reduceSum(function (d) {
            return d.value/50;
        });
        var yearDim  = ndx2.dimension(function(d) {return +d.Year;}); 
        var year_total = yearDim.group().reduceSum(function(d) {return d.value;});
        var resourceDim  = ndx2.dimension(function(d) {return d.Resource;});
        var value_resource = resourceDim.group().reduceSum(function(d) {return 1;}); 

        var minDate = dateDim.bottom(1)[0].Date;
        var maxDate = dateDim.top(1)[0].Date;

        var xAxisWidth = 1000;

        var dateRangePicker = dc.barChart("#rangeTable");
        dateRangePicker
            .width(xAxisWidth).height(80)
            .margins({top: 0, right: 10, bottom: 20, left: 65})
            .dimension(dayDim)
            .group(volumeByDayGroup)
            .x(d3.time.scale().domain([minDate,maxDate]))
            .gap(1)
            .round(d3.time.day.round)
            .elasticY(true)
            .xUnits(d3.time.days)
            .yAxis().ticks(4);

            var chart = dc.seriesChart(htmlID);
          chart
            .width(xAxisWidth).height(600)
           .dimension(dateDim)
           .group(valueGroup)
           .seriesAccessor(function(d) {return d.key[1]})
           .keyAccessor(function(d) {return d.key[0]})
           .valueAccessor(function (d) {return d.value})               
           .elasticY(false)
          .ordinalColors(["#56B2EA","#E064CD","#F8B700"])
           .x(d3.time.scale().domain([minDate,maxDate]))
           .y(d3.scale.linear().domain([0,100]))
           .elasticX(true)
           .margins({top: 10, right: 10, bottom: 00, left: 10})
           .brushOn(false)
           .transitionDuration(1000)
           .renderHorizontalGridLines(true)
           .renderVerticalGridLines(true)
           .rangeChart(dateRangePicker)
           .mouseZoomable(false)
           .legend(dc.legend().x(xAxisWidth-65).y(10).itemHeight(13).gap(5))
                   .margins({ top: 10, left: 50, right: 10, bottom: 50 }) 
           .yAxisLabel("Resource Percentage");




        var resourceRingChart = dc.pieChart("#chart-ring-resource");
        resourceRingChart
            .width(170).height(170)
            .ordinalColors(["#56B2EA","#E064CD","#F8B700"])
            .dimension(resourceDim)
            .group(value_resource)
            .legend(dc.legend().x(75).y(63).itemHeight(13).gap(5))
            .renderLabel(false)
            .renderTitle(false)
            .innerRadius(50); 



        //dc.renderAll();
        dateRangePicker.render();
        chart.render();
        resourceRingChart.render();



        function getvalues(d){
            var str=d.key.getDate() + "/" + (d.key.getMonth() + 1) + "/" + d.key.getFullYear()+"\n";
            var key_filter = dateDim.filter(d.key).top(Infinity);
            var total=0;
            key_filter.forEach(function(a) {
            str+=a.Resource+": "+a.value+"%\n";
            total+=a.value;
            });
            dateDim.filterAll();
            return str;
        } 

        $("#resetButton").on("click",function(){
           chart.filterAll();
           chart.y(d3.scale.linear().domain([0,100]));
           chart.render();
           dateRangePicker.filterAll();
           resourceRingChart.filterAll();
           dc.redrawAll();
           $("#rangeSlider").slider("destroy");
            $("#rangeSlider").slider({
             range: true,
             min: 0,
             max: 100,
             values: [0,100],
           });
        });

         $("#axisButton").on("click",function(){
            var min = $('#rangeSlider').slider("option", "values")[0];
            var max = $('#rangeSlider').slider("option", "values")[1];
            chart.y(d3.scale.linear().domain([min,max]));
            chart.render();
        });

        $("#rangeSlider").slider({
              range: true,
              min: 0,
              max: 100,
              values: [0,100],
            });
    })

任何帮助将不胜感激。提前致谢。

【问题讨论】:

  • 刚刚找到原因,交叉过滤时:var dateTypeDim = ndx2.dimension (function(d) {return [d.Date,d.Resource];}); 将执行时间增加了 100 倍。通过多个维度进行交叉过滤时似乎存在性能问题。
  • 我认为这通常不是 Crossfilter 的问题(我在更大的数据集中使用数组的维度而没有问题)。不过,这可能是 dc.js 效率低下的事情,可能是访问器函数。我建议您使用分析器来查看减速的确切位置。
  • 我使用了一些 Javascript 代码来告诉我完成上述代码中的每项任务所需的时间。例如,这些是 5000 行 csv 的结果:Time taken for forEach: 29 ms. Time taken for crossfiltering: 14828 ms. Time taken for graph defining: 10 ms. Time taken for rendering: 3186 ms.
  • 除此之外,使用 CPU 分析器,我可以看到:Self:66.60% TOTAL: 67.49% RegExp: //@[ ]sourceMappingURL=[ ]*([^\s'"]*)[ ]*$,因此使用字符串和数字在同一维度中查询似乎不适合 crossfilter。
  • 使用 Date.getTime() 将日期更改为数字并将资源类型分解为整数解决了问题:对于 9000 行,从 30 秒缩短到 700 毫秒。

标签: javascript d3.js dc.js crossfilter


【解决方案1】:

使用维度时,最好避免使用字符串、日期和复杂对象。将所有可以转换为整数,因为它会根据您的变量对数据的内容进行排序。

【讨论】:

    猜你喜欢
    • 2017-05-29
    • 1970-01-01
    • 2017-12-10
    • 2018-03-01
    • 2015-12-13
    • 1970-01-01
    • 1970-01-01
    • 2022-01-04
    • 2021-02-08
    相关资源
    最近更新 更多