4

I have a line chart. Its purpose is to show the amount of transactions per user over a given time period.

To do this I'm getting the dates of all users transactions. I'm working off this example : http://bl.ocks.org/mbostock/3884955 and have the line chart renedering fine.

My x-axis is time and the y-axis is number of transactions. The problem I have is to do with displaying dates when there is no activity.

Say I have 4 transactions on Tuesday and 5 transactions on Thursday..I need to show that there has been 0 transactions on Wednesday. As no data exists in my database explicitly stating that a user has made no transactions on Wedensday do I need to pass in the Wednesday time (and all other times, depending on the timeframe) with a 0 value? or can I do it with d3? I can't seem to find any examples that fit my problem.

Travis
  • 705
  • 6
  • 30

1 Answers1

5

This seems like a pretty common issue, so I worked up an example implementation here: http://jsfiddle.net/nrabinowitz/dhW2F/2/

Relevant code:

  // get the min/max dates
  var extent = d3.extent(data, function(d) { return d.date; }),
      // hash the existing days for easy lookup
      dateHash = data.reduce(function(agg, d) {
          agg[d.date] = true;
          return agg;
      }, {}),
      // note that this leverages some "get all headers but date" processing
      // already present in the example
      headers = color.domain();

    // make even intervals
    d3.time.days(extent[0], extent[1])
        // drop the existing ones
        .filter(function(date) {
            return !dateHash[date];
        })
        // and push them into the array
        .forEach(function(date) {
            var emptyRow = { date: date };
            headers.forEach(function(header) {
                emptyRow[header] = null;
            });
            data.push(emptyRow);
        });
    // re-sort the data
    data.sort(function(a, b) { return d3.ascending(a.date, b.date); });

As you can see, it's a bit convoluted, but seems to work well - you make an array of evenly spaced dates using the handy d3.interval.range method, filter out those dates already present in your data, and use the remaining ones to push empty rows. One downside is that performance could be slow for a big dataset - and this assumes full rows are empty, rather than different empty dates in different series.

An alternate representation, with gaps (using line.defined) instead of zero points, is here: http://jsfiddle.net/nrabinowitz/dhW2F/3/

nrabinowitz
  • 55,314
  • 10
  • 149
  • 165