2016-04-21 35 views
0

我正在尝试使用dc.js进行交互式数据可视化。互动图表(由dc.js)没有正确更新对方

我的数据基本上是两个系列值,以每行指定的id属性为特征。这里的例子,我怎么产生的呢:

var data = []; 
var n = 10000.; 
for (var i = 0; i < n; i++) { 
    data.push({id: 0, "i": i, x: Math.random()}); 
    data.push({id: 1, "i": i, x: (Math.random()+i/n)}); 
} 

那我把这个数据集中到一个crossfilter对象,并创建两个维度和两组。一到每id显示分级值的总和沿着系列,和一个为每id显示总选择的值的总和:

var cf = crossfilter(data), 
    series = cf.dimension(function(d) {return [d.id, d.i];}), 
    series_grouped = series 
     .group(function(d){return [d[0], Math.floor(d[1]/100.)*100.];}) 
     .reduceSum(function(d) { return d.x; }), 
    id = cf.dimension(function(d) {return d.id;}), 
    id_grouped = id.group().reduceSum(function(d){return d.x;}); 

我设法建立我想要的图表,用下面的代码。我无法正确处理的是互动行为:

  • 当我在系列图表中选择范围时,左侧的条形图未更新(但应该是)。
  • 当我在系列图表中选择一个范围,然后选择一个条形,条形消失。我无法从该状态恢复(通过重新加载页面以外的方式)。 (我没试过在这里引发cf.filterAll(),因为我不认为这可能解决我的问题根源。)

我怎样才能在左边的柱状图,当我选择在一个范围内进行更新右边的系列图表?难道我做错了什么?

我使用的是Firefox 45.0.2,这些都是我的库版本:

  • dc.js:2.0.0-beta.26
  • crossfilter.js:1.3.12
  • D3 .js文件:3.5.16

这是一个完整的文档:

<!DOCTYPE html> 
<meta charset="utf-8"> 

<head> 
    <script src="crossfilter.js"></script> 
    <script src="d3.js"></script> 
    <script src="dc.js"></script> 
    <link rel="stylesheet" type="text/css" href="dc.css" /> 
    <style> 
     body { width: 960px; } 
     .chart.left { width: 25%; } 
     .chart.right { width: 75%; float: right; } 
    </style> 
</head> 

<body> 
    <div id="charts"> 
     <div id="chart_a" class="chart right"></div> 
     <div id="chart_b" class="chart left"></div> 
    </div> 

    <script> 
    // generate data 
    var data = []; 
    var n = 10000.; 
    for (var i = 0; i < n; i++) { 
     data.push({id: 0, "i": i, x: Math.random()}); 
     data.push({id: 1, "i": i, x: (Math.random()+i/n)}); 
    } 

    // do some crossfilter stuff 
    var cf = crossfilter(data), 
     series = cf.dimension(function(d) {return [d.id, d.i];}), 
     series_grouped = series 
      .group(function(d){return [d[0], Math.floor(d[1]/100.)*100.];}) 
      .reduceSum(function(d) { return d.x; }), 
     id = cf.dimension(function(d) {return d.id;}), 
     id_grouped = id.group().reduceSum(function(d){return d.x;}); 

    // generate charts 
    var chart_width = 960, chart_height = 200; 
    dc.seriesChart("#chart_a").height(chart_height).width(.74*chart_width) 
     .chart(function(c) { return dc.lineChart(c).renderArea(true); }) 
     .x(d3.scale.linear().domain([0,n])) 
     .dimension(series) 
     .group(series_grouped) 
     .seriesAccessor(function(d) {return d.key[0];}) 
     .keyAccessor(function(d) {return d.key[1];}) 
     .valueAccessor(function(d) {return d.value;}) 
     .xAxis(); 
    dc.barChart("#chart_b").height(chart_height).width(.24*chart_width) 
     .dimension(id) 
     .group(id_grouped) 
     .x(d3.scale.ordinal().domain([0,1])) 
     .xUnits(dc.units.ordinal) 
     .xAxis(); 

    dc.renderAll(); 
    </script> 
</body> 

回答

1

至少你需要重写系列图上的过滤器处理程序。现在,假设你从系列图中的i = 20到400选择。在Crossfilter上它说series.filter([20,400])。但是您的系列尺寸值看起来像[0,150],那么评估20 <= [0,150] && [0,150] <= 400意味着什么?很难说,而且几乎肯定不是你的意思。通过Crossfilter的自动化类型转换,它可能会评估"20" < "0,150" && "0,150" < "400"。相反,您可能希望它评估20 <= [0,150][1] && [0,150][1] <= 400,您可以强制它在自定义过滤器处理程序中执行。

Here“SA版本的‘作品’使用自定义过滤处理器:

dc.seriesChart("#chart_a").height(chart_height).width(.74 * chart_width) 
    .chart(function(c) { 
    return dc.lineChart(c).renderArea(true) 
     .filterHandler(function(dimension, filter) { 
     if (filter[0]) { 
      dimension.filterFunction(function(d) { 
      return d[1] > filter[0][0] && d[1] < filter[0][1]; 
      }); 
     } else { 
      dimension.filterAll(); 
     } 
     setTimeout(dc.redrawAll, 0); 
     return filter; 
     }); 
    }) 
    .x(d3.scale.linear().domain([0, n])) 
    .dimension(series) 
    .group(series_grouped) 
    .seriesAccessor(function(d) { 
    return d.key[0]; 
    }) 
    .keyAccessor(function(d) { 
    return d.key[1]; 
    }) 
    .valueAccessor(function(d) { 
    return d.value; 
    }); 

然而,你可能也看到,使用数组作为Crossfilter维度键是一个非常糟糕的主意(除非你在Crossfilter2中使用数组类型,这不是你想要的)。尺寸必须是自然排列的,并且当我希望上面的解释说明时,数组在排序时的行为令人惊讶。

那么你会怎么做?我建议将您的数据作为最佳的选择:

var data = []; 
var n = 10000.; 
for (var i = 0; i < n; i++) { 
    data.push({"i": i, x0: Math.random(), x1:(Math.random()+i/n)}); 
} 

有了这些数据,生成合计二者X0和X1组,然后使用堆栈混入物(包含在标准dc.lineChart)显示每个系列的线。

另一种更痛苦的方法是自己处理字符串的序列化和反序列化。只需要非常小心地考虑排序,这意味着您可能需要将值填零,并且在序列化之前显式舍入浮点值可能是个好主意。从订购的角度来看,如果这是您想要过滤的尺寸,您应该使您的尺寸值按i而不是id排序。

+0

感谢您的输入。我已经将我的实现基于给定的[这里](http://dc-js.github.io/dc.js/examples/series.html)中的多行图示的示例。如果我按照您的建议重组我的数据,我想我会遇到问题,生成每个ID的条形图。我想我没有完全理解我将如何实现和应用自定义过滤器处理程序。 [dc.js文档](http://dc-js.github.io/dc.js/docs/html/dc.baseMixin.html)在这件事上并没有真正的帮助(也许这是因为我没有完全了解过滤器如何工作)。你可以扩展这个,或者提供一个例子吗? – moooeeeep

+0

嗯。我对这个例子有效,但有点惊讶,但如果这就是你所追求的,这很公平。这里可能会有不同的事情发生。你能把你的代码的一个工作例子放在一起吗?我很乐意仔细看看。这里有一个模板,你可以使用已经有DC.js和Crossfilter加载:https://jsfiddle.net/esjewett/jusjkm8j/2/ –

+0

这是一个使用filterHandler“工作”的版本。看看该系列图表dc.js的例子,我很确定它有与您正在运行的过滤相同的问题。我个人会远离它,但也许@gordonwoodhull会有更多的见解。 https://jsfiddle.net/jusjkm8j/7/ –