交互式图表(由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)});
}

然后,我将这个数据集放入一个交叉过滤器对象中,并创建两个维度和两个组。 每一个显示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>
    

    至少你需要重写系列图上的过滤器处理程序。 现在,假设你从系列图中的i = 20到400选择。 在series.filter([20,400])上,它说的是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 ,您可以强制它在自定义过滤器处理程序中执行此操作。

    以下是使用自定义过滤器处理程序“工作”的版本:

    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排序。

    链接地址: http://www.djcxy.com/p/32719.html

    上一篇: Interactive Charts (by dc.js) not updating each other correctly

    下一篇: Single bar stacked chart in DC