Как отобразить временную серию / категорически составленную столбчатую диаграмму в d c. js, фильтруя стек и столбец - PullRequest
1 голос
/ 10 марта 2020

Большинство примеров, которые я нашел, используют данные, которые имеют время и номер

var data =      [
  {
    "Time": "19-Jan-2018 11:24:49.000 UTC",
    "Speed": 1.885
  },
  {
    "Time": "19-Jan-2018 11:24:59.000 UTC",
    "Speed": 1.875
  },
  {
    "Time": "19-Jan-2018 11:25:00.000 UTC",
    "Speed": 1.878
  },
  {
    "Time": "19-Jan-2018 11:25:01.000 UTC",
    "Speed": 1.876
  }
]

Я ищу тип стека

    var data =      [
  {
    "Time": "19-Jan-2018 11:24:49.000 UTC",
    "type": "CAT"
  },
  {
    "Time": "19-Jan-2018 11:24:59.000 UTC",
    "type": "DOG"
  },
  {
    "Time": "19-Jan-2018 11:25:00.000 UTC",
    "type": "CAT"
  },
  {
    "Time": "19-Jan-2018 11:25:01.000 UTC",
    "Type": "BAT"
  }
]

Как я могу складывать категориальные данные, позволяя пользователь может выбрать пары время / категория, как показано ниже: Пример ?

1 Ответ

0 голосов
/ 11 марта 2020

Я адаптировал пример к данным времени / категории в этой скрипке .

Эти даты будут анализироваться только в Chrome, поэтому

const parseDate = d3.utcParse("%d-%b-%Y %H:%M:%S.%L UTC");
data.forEach(d => {
  d.Time = parseDate(d.Time);
})

Я изменил ключевые функции для использования ,

function multikey(x,y) {
  return x + ',' + y;
}
function splitkey(k) {
  return k.split(',');
}

Я также изменил поддельную группу stack_second, чтобы преобразовать строковые даты из мультиключей обратно в Dates и инициализировать категории в 0 (так как каждый стек должен быть присутствует для каждого X).

function stack_second(group, categories) {
  return {
    all: function() {
      var all = group.all(),
          m = {};
      // build matrix from multikey/value pairs
      all.forEach(function(kv) {
        var ks = splitkey(kv.key);
        m[ks[0]] = m[ks[0]] || Object.fromEntries(categories.map(c=>[c,0]));
        m[ks[0]][ks[1]] = kv.value;
      });
      // then produce multivalue key/value pairs
      return Object.keys(m).map(function(k) {
        return {key: new Date(k), value: m[k]};
      });
    }
  };
}

Получить массив категорий из исходных данных:

const categories = Array.from(new Set(data.map(d => d.Type)).values());

При работе с датой / временем вы должны выбрать d3 интервал времени соответствующий вашим данным. Здесь минуты выглядели правильно. Повсеместно используйте UT C d3-time, потому что ваши исходные данные - UT C.

const interval = d3.utcMinute;

Рассчитайте домен xscale и примените:

let extent = d3.extent(data, d=>d.Time);
extent[1] = interval.offset(extent[1], 1)
chart
  .x(d3.scaleTime().domain(extent))
  .xUnits(interval.range)

Правильное число тиков, также отформатированный в UT C:

chart.xAxis().ticks(d3.utcMinute).tickFormat(d3.utcFormat('%H:%M'))

Сопоставить цвета между стопками и клинами с

.colors(d3.scaleOrdinal().domain(categories).range(d3.schemeCategory10))

Инициализация перекрестного фильтра, используя интервал и категории:

const interval = d3.utcMinute; // choose appropriate to your data
var cf = crossfilter(data),
    timeTypeDim = cf.dimension(function(d) { return multikey(interval(d.Time), d.Type); }),
    timeTypeGroup = timeTypeDim.group(), // reduceCount by default
    stackedGroup = stack_second(timeTypeGroup, categories);

А вот код диаграммы для полноты, хотя мы уже обсуждали соответствующие части:

function sel_stack(i) {
  return function(d) {
    return d.value[i];
  };
}
chart
  .width(600)
  .height(400)
  .colors(d3.scaleOrdinal().domain(categories).range(d3.schemeCategory10))

  .controlsUseVisibility(true)
  .x(d3.scaleTime().domain(extent))
  .xUnits(interval.range)
  .margins({left: 80, top: 20, right: 10, bottom: 20})
  .brushOn(false)
  .clipPadding(10)
  .title(function(d) {
  return d.key + '[' + this.layer + ']: ' + d.value[this.layer];
})
  .legend(dc.legend().x(540).y(50))
  .dimension(timeTypeDim)
  .group(stackedGroup, categories[0], sel_stack(categories[0]))
  .renderLabel(true);

time/category stacked bars

...