如何在动态增长的数据集上应用笔刷?

时间:2019-07-29 15:48:36

标签: dc.js crossfilter

我有一个动态增长的时间序列,需要显示在可缩放/可缩放的图表中。

在这里尝试一下(实际上:我的第一个jsFiddle :)):

https://jsfiddle.net/Herkules001/L12k5zwx/29/

我尝试按照此处所述的相同方式进行操作:https://dc-js.github.io/dc.js/examples/replacing-data.html

但是,每次图表更新时,焦点图表上的缩放和滤镜都会丢失。 (但是画笔保留在范围图上。)

如何在不重置视图和不丢失缩放的情况下添加数据?

var chart = dc.lineChart("#test");
var zoom = dc.lineChart("#zoom");

//d3.csv("morley.csv", function(error, experiments) {
var experiments = d3.csvParse(d3.select('pre#data').text());
  experiments.forEach(function(x) {
    x.Speed = +x.Speed;
  });

  var ndx                 = crossfilter(experiments),
      runDimension        = ndx.dimension(function(d) {return +d.Run;}),
      speedSumGroup       = runDimension.group().reduceSum(function(d) {return d.Speed * d.Run / 1000;});

  chart
    .width(768)
    .height(400)
    .x(d3.scaleLinear().domain([6,20]))
    .brushOn(false)
    .yAxisLabel("This is the Y Axis!")
    .dimension(runDimension)
    .group(speedSumGroup)
    .rangeChart(zoom);

  zoom
    .width(768)
    .height(80)
    .x(d3.scaleLinear().domain([6,20]))
    .brushOn(true)
    .yAxisLabel("")
    .dimension(runDimension)
    .group(speedSumGroup);

    zoom.render();
    chart.render();

  var run = 21;
  setInterval(
    () => {

      var chartfilter = chart.filters();
      var zoomfilter = zoom.filters();

      chart.filter(null);
      zoom.filter(null);

      ndx.add([{Expt: 6, Run: run++, Speed: 100 + 5 * run}]);
      chart.x(d3.scaleLinear().domain([6,run]));
      zoom.x(d3.scaleLinear().domain([6,run]));

      chart.filter([chartfilter]);
      zoom.filter([zoomfilter]);

      chart.render();
      zoom.render();
    },
    1000);  

//});

1 个答案:

答案 0 :(得分:0)

在这种情况下,如果您只是添加数据,则无需执行引用的示例中演示的过滤器的复杂清除和还原操作。

该部分仅是必需的,因为crossfilter.remove()最初将删除与当前过滤器匹配的数据。尴尬的界面,几乎从来没有想要的。

如果仅添加数据,则不必担心其中的任何一个:

setInterval(
() => {
  ndx.add([{Expt: 6, Run: run++, Speed: 5000 + 5 * run}]);
  chart.redraw();
  zoom.redraw();
},
5000);  

请注意,使用redraw而非render可以减少闪烁,并获得不错的动画过渡。我还添加了evadeDomainFilter以避免线在图表边缘之前被剪掉。

Fork of your fiddle

删除数据

如果使用谓词形式crossfilter.remove(),则不必担心保存和还原过滤器:

  ndx.remove(d => d.Run < run-20);

但是,这确实暴露了dc.js中的其他错误。似乎elasticY无效,类似于所描述的in this issue。还有you get some weird animations

Here's a demo with remove enabled.

最后,dc.js具有一些非常简洁的功能,通常可以通过一种方法使它执行您想要的操作,但是它确实很古怪。这是一个非常复杂的领域,以我的经验,您将在所有功能齐全的图表库中找到其中一些怪癖。

更新:我修复了replacing data example,现在只是ndx.remove(() => true)

缩放问题

如Joerg在评论中指出的

  • 当图表未缩放时,最好也将其增长以在到达时显示新数据
  • 如果焦点移到图表的原始域之外,则X域将被剪切甚至反转

我们可以通过添加preRedraw event handler来解决这些问题。那是调整域的理想场所。例如,您可以根据需要手动实施elasticX。 (正如您稍后看到的,我们做到了!)

首先,一个很容易理解的天真尝试:

chart.on('preRedraw', () => {
  chart.elasticX(!zoom.filters().length);
});

我们可以根据范围图表是否具有活动过滤器来打开和关闭elasticX

这行得通,而且很好,也很简单,但是当您尝试关注原始图表中未包含的域时,为什么图表会如此混乱?

欢迎,它将记录原始域(source)。这样,如果清除焦点,它就可以还原到该域,并且还可以阻止您缩放或平移超过图形的边缘。

但是从上面的源链接中注意到,我们有一个逃生舱口。设置X标度后,它会记录原始域 。因此,除了设置elasticX之外,我们还可以计算数据的范围,设置刻度的域,并告诉图表刻度是新的:

chart.on('preRedraw', () => {
  if(!zoom.filters().length) {
    var xExtent = d3.extent(speedSumGroup.all(), kv => kv.key);
    chart.x(chart.x().domain(xExtent));
  }
});

New fiddle with zooming issues fixed.

Joerg仍然指出一个小故障:如果在数据输入时移动画笔,则画笔柄有时会偶尔从画笔的末端偏离。以我的经验,这类故障在D3(通常是动态图表)中很常见,因为很难考虑用户交互过程中的数据更改。它可能可以在库中修复(也许是过渡中断吗?),但我在这里不打算讨论。