【问题标题】:crossfilter: how to use crossfilters for start date and end date columns simultaneously交叉过滤器:如何同时对开始日期和结束日期列使用交叉过滤器
【发布时间】:2016-02-05 10:05:09
【问题描述】:

我的情况与question 类似。考虑到相同的数据集,我如何通过交叉过滤器执行此功能。我是 dc.js 和 crossfilter 的新手。我正在尝试像example 那样实现条形图和面积图。即使此示例使用 1 个日期列。我只能用 startdate 来做到这一点。但是,我的要求是根据 startdate 和 enddate 过滤数据集。我找不到很多讨论同一问题的资源。

我们将不胜感激任何帮助和建议。

【问题讨论】:

  • 您需要为每条记录创建一个包含开始和结束日期的维度,然后实现自定义过滤器功能。请在 jsFiddle 或类似的可编辑平台上仅使用 startdate 或 enddate 组合一个示例,我或这里的其他人将能够向您展示如何做到这一点。
  • @EthanJewett,是groupAll吗? :-)
  • @Gordon LOL :-) 这取决于。通常不会。通常只是一个 filterFunction 来检查开始/结束日期并确定记录在所选期间是否“活动”。但是对于这个特定的问题,groupAll 也是必需的,因为我们希望将这些记录分成几个月,而一条记录可能会分成多个月份。

标签: javascript dc.js crossfilter


【解决方案1】:

您可能认为这很简单,但实际上跟踪间隔是计算机科学中经典的棘手问题之一,它需要一个称为 interval tree 的专门数据结构才能正确完成。

这是一个很常见的请求,所以出于好奇,我寻找了一个用于区间树的 JavaScript 库和found one by Mikola Lysenko

我已将其合并到 new example here 中。 (source)

该示例的重要部分首先是使用groupAll 填充区间树:

      projectsPerMonthTree = ndx.groupAll().reduce(
          function(v, d) {
              v.insert(d.interval);
              return v;
          },
          function(v, d) {
              v.remove(d.interval);
              return v;
          },
          function() {
              return lysenkoIntervalTree(null);
          }
      )

接下来我们使用开始和结束日期填充一个假组,计算与每个月相交的所有间隔:

  function intervalTreeGroup(tree, firstDate, lastDate) {
      return {
          all: function() {
              var begin = d3.time.month(firstDate), end = d3.time.month(lastDate);
              var i = new Date(begin);
              var ret = [], count;
              do {
                  next = new Date(i);
                  next.setMonth(next.getMonth()+1);
                  count = 0;
                  tree.queryInterval(i.getTime(), next.getTime(), function() {
                      ++count;
                  });
                  ret.push({key: i, value: count});
                  i = next;
              }
              while(i.getTime() <= end.getTime());
              return ret;
          }
      };
  }

      projectsPerMonthGroup = intervalTreeGroup(projectsPerMonthTree.value(), firstDate, lastDate),

(如果我们使用对区间树的较低级别访问,或者如果它有更丰富的 API 允许按顺序遍历区间,这可能会更简单、更便宜。但这应该足够快。)

最后,我们设置一个filterFunction,以便我们选择与给定日期范围相交的时间间隔:

  monthChart.filterHandler(function(dim, filters) {
      if(filters && filters.length) {
          if(filters.length !== 1)
              throw new Error('not expecting more than one range filter');
          var range = filters[0];
          dim.filterFunction(function(i) {
              return !(i[1] < range[0].getTime() || i[0] > range[1].getTime());
          })
      }
      else dim.filterAll();
      return filters;
  });

我已经对其进行了设置,以便它过滤月图表以显示与其自己的日期范围相交的所有项目。如果不需要,可以将groupAll 放在intervalDimension 上。

【讨论】:

  • 感谢您的解决方案。很抱歉花了很长时间才回复这个问题。但是,我担心 ret.length >100 的情况会在 intervalTreeGroup() 中引发错误。这有什么意义吗?我的数据集大小约为 1500。因此,它仅在我评论该条件时才有效。再次感谢。
  • 啊,对不起,我把它放进去调试了,会删除它。感谢您的报告。
【解决方案2】:

解决方案真的很简单。创建两个维度:

  1. 按开始时间-startTimeDim
  2. 按结束时间 - endTimeDim

现在,要过滤掉与给定范围相交的区间 - rangeStartrangeEnd,请应用以下内容:

  1. startTimeDim.filter([-Infinity, rangeEnd])
  2. endTimeDim.filter([rangeStart, Infinity])

这基本上会过滤掉范围结束之前开始和范围开始之前结束的间隔。

【讨论】:

    猜你喜欢
    • 2018-06-11
    • 2012-10-05
    • 2015-01-28
    • 1970-01-01
    • 2020-03-13
    • 1970-01-01
    • 2021-12-31
    • 1970-01-01
    • 2017-01-15
    相关资源
    最近更新 更多