1
votes

I am trying to create a date stacked area chart using dc.js. This chart should:

  1. Show different areas by each field "event"
  2. Count the number of events per day

This is my code:

var data = [{
  "event": "Panic",
  "date": "2018-01-02"
}, {
  "event": "Speed limit exceeded",
  "date": "2018-01-01"
}, {
  "event": "Door opened",
  "date": "2018-01-03"
}];

var chart = dc.lineChart("#areaChart");
var dtgFormat = d3.time.format("%Y-%m-%d");

data.forEach(function(d) {
  d.dtg = dtgFormat.parse(d.date);
});

var ndx = crossfilter(data);
var areaDim = ndx.dimension(function(d) {
  return d.dtg;
});
var areaGroup = areaDim.group().reduce(
  function(p, v) {
    p[v.event] = (p[v.event] || 0) + 1;
    return p;
  },
  function(p, v) {
    p[v.event] = (p[v.event] || 0) - 1;
    return p;
  },
  function() {
    return {};
  });

// Get distinct
var eventsArray = data.map(a => a.event).filter(function onlyUnique(value, index, self) {
  return self.indexOf(value) === index;
});

function sel_stack(i) {
  return function(d) {
    return d.value[i];
  };
}

chart.width(960)
  .height(150)
  .transitionDuration(500)
  .dimension(areaDim)
  .group(areaGroup, eventsArray[0], sel_stack(eventsArray[0]))
  .renderArea(true)
  .elasticY(true)
  .x(d3.time.scale().domain(d3.extent(data, function(d) {
    return d.dtg;
  })))
  .xAxis().ticks(4);

for (var i = 1; i < eventsArray.length; i++)
  chart.stack(areaGroup, eventsArray[i], sel_stack(eventsArray[i]));

dc.renderAll();

But the chart is only drawing both axis. What am I missing ?

Here is my jsfiddle: http://jsfiddle.net/n08e32n6/12/

1

1 Answers

0
votes

The stack feature of dc.js requires every stack to have a value for every X value. Since some are currently undefined you end up with NaNs and then dc.js sanitizes the areas out entirely.

All you need to do is initialize your reduce objects with all of the available keys instead of starting with a blank object. So you can compute your distinct event types first, and then use use Array.reduce to create an object with zeroes for each event type:

var eventsArray = data.map(a => a.event).filter(function onlyUnique(value, index, self) {
  return self.indexOf(value) === index;
});

var areaGroup = areaDim.group().reduce(
  function(p, v) {
    p[v.event] = (p[v.event] || 0) + 1;
    return p;
  },
  function(p, v) {
    p[v.event] = (p[v.event] || 0) - 1;
    return p;
  },
  function() {
    return eventsArray.reduce(function(p, v) {
      p[v] = 0;
      return p;
    }, {});
  });

working stacks

Fork of your fiddle.