使用dc.js的可编辑散点图

时间:2016-11-12 17:51:38

标签: dc.js

有一个散点图有什么好方法,可以通过点击操作在绘图本身中编辑数据?

这个想法是在图中的数据中发现异常值并过滤图中的值,而不是必须更改源数据。

更好的方法是从交叉过滤器中删除数据,但只有过滤器才能接受。

1 个答案:

答案 0 :(得分:1)

我使用当前的dc.js(beta 32)提出了一个解决方案。

它不支持画笔(需要.brushOn(false)) - 我将在增强请求中解释为什么这需要对dc.js进行一些更改。

但它确实支持点击点来切换它们,以及重置链接。 (点击背景重置也是可能的,但这里没有实现。)

我们要做的是使用标准的dc.js过滤器签名定义我们自己的ExcludePointsFilter

function compare_point(p1, p2) {
  return p1[0] === p2[0] && p1[1] === p2[1];
}
function has_point(points, point) {
  return points.some(function(p) {
    return compare_point(point, p);
  });
}
function ExcludePointsFilter(points) {
  var points2 = points.slice(0);
  points2.filterType = 'ExcludePointsFilter';
  points2.isFiltered = function(k) {
    return !has_point(points2, k);
  };
  return points2;
}

我们将在每次点击一个点时计算一组新点,并替换过滤器:

scatterPlot.on('pretransition.exclude-dots', function() { #1
  // toggle exclusion on click
  scatterPlot.selectAll('path.symbol') #2
      .style('cursor', 'pointer') // #3
      .on('click.exclude-dots', function(d) { // #4
    var p = [d.key[0],d.key[1]];
    // rebuild the filter #5
    var points = scatterPlot.filter() || [];
    if(has_point(points, p))
      points = points.filter(function(p2) {
        return !compare_point(p2, p);
      });
    else
      points.push(p);
    // bypass scatterPlot.filter, which will try to change
    // it into a RangedTwoDimensionalFilter #6
    scatterPlot.__filter(null)
      .__filter(ExcludePointsFilter(points));
    scatterPlot.redrawGroup();
  });
});

说明:

  1. 每次渲染或重绘图表时,我们都会在任何转换开始之前对其进行注释
  2. 选择所有点,即path
  3. symbol元素
  4. 设置合适的光标(指针可能不理想,但有aren't too many to choose from
  5. 为每个点设置一个点击处理程序 - 使用exclude-dots事件命名空间来确保我们不会干扰其他任何人。
  6. 获取当前过滤器或开始新过滤器。查看当前点被点击(作为d传递)是否在该数组中,然后添加或删除它。
  7. 替换散点图的当前过滤器。由于散点图与RangedTwoDimensionalFilter深深吻合,我们需要绕过filter覆盖(以及coordinateGridMixin覆盖!)并一直到baseMixin.filter()。是的,这很奇怪。
  8. 为了更好的衡量,我们还将更换过滤器,通常不知道如何处理一系列点:

    scatterPlot.filterPrinter(function(filters) {
      // filters will contain 1 or 0 elements (top map/join is just for safety)
      return filters.map(function(filter) {
        // filter is itself an array of points
        return filter.map(function(p) {
          return '[' + p.map(dc.utils.printSingleValue).join(',') + ']';
        }).join(',');
      }).join(',');
    });
    

    这是一个小提琴中的工作示例:http://jsfiddle.net/gordonwoodhull/3y72o0g8/16/

    注意,如果您想要对排除的点执行某些操作,则可以从scatterPlot.filter()读取它们 - 过滤器是带有一些注释的点数组。您甚至可以撤消过滤器,然后拨打crossfilter.remove(),但我会将其作为练习。