【发布时间】: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