Перекрестный фильтр: как использовать перекрестные фильтры для столбцов даты начала и окончания даты одновременно

У меня похожая ситуация как в этом вопросе. Учитывая тот же набор данных, как я могу выполнить эту функцию через перекрестные фильтры. Я новичок в dc.js и crossfilter. Я пытаюсь реализовать бар и площадь участка, как в этом примере. Даже этот пример использует 1 столбец даты. Я могу сделать это только с начальной даты. Тем не менее, мое требование состоит в том, чтобы фильтровать наборы данных на основе начальной и конечной даты. Я не смог найти много ресурсов, рассказывающих об одной и той же проблеме.

Любая помощь и предложения будут высоко оценены.

2 ответа

Решение

Вы можете ожидать, что это будет просто, но на самом деле отслеживание интервалов является одной из классических хитрых проблем компьютерной науки, и для этого требуется специальная структура данных, называемая деревом интервалов, чтобы сделать это правильно.

Это довольно распространенный запрос, поэтому из любопытства я искал библиотеку JavaScript для интервальных деревьев и нашел Миколу Лысенко.

Я включил это в новый пример здесь. ( источник)

Важными частями примера являются, во-первых, использование 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 вместо.

Решение действительно очень простое. Создайте два измерения:

  1. по времени начала -startTimeDim
  2. к концу времени - endTimeDim

Теперь, чтобы отфильтровать интервалы, которые пересекают данный диапазон - rangeStart а также rangeEnd, примените следующее:

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

Это в основном отфильтровывает интервалы, которые начинаются до того, как диапазон заканчивается и заканчивается до того, как диапазон начинается.

Другие вопросы по тегам