How to add in zero values into a time series in d3.js / JavaScript

前端 未结 3 2002
花落未央
花落未央 2020-12-31 03:26

This is a problem that I have previously solved using php or (what I thought was) needlessly complex MySQL queries, but which I suddenly thought there must be a more elegant

3条回答
  •  Happy的楠姐
    2020-12-31 03:50

    I've not greatly improved on your overall approach, but if you use some more built-in methods and add underscore/lodash you can make the data transformation a lot shorter:

    x.domain(d3.extent(data, function(d) { return d.date; })).ticks(d3.time.month);
    y.domain([0, d3.max(data, function(d) { return d.value; })]);
    
    var newData = x.ticks().map(function(monthBucket) {
        return _.find(data, {date: monthBucket}) || {date: monthBucket, value: 0};
    });
    

    If we tell it that it should use monthly ticks, then we can just get the ticks array back out again rather than constructing a separate buckets array.

    And then from that point we just use .map rather than for loop and lodash (or underscore) _.find method to match up to our original data. Updated fiddle here: http://jsfiddle.net/a5jUz/3/


    Original answer below... in case you want to use D3 scales to spread out the values on bar graph:

    1 - You have to use a time scale rather than an ordinal scale:

    var x = d3.time.scale().range([0, width]);
    

    2 - You need to set the domain of that scale based on the min/max of the date range:

    x.domain(d3.extent(data, function(d) { return d.date; })).nice();
    

    3 - [the ugly part] now that you're not using ordinal scale, you don't have the rangeBand function for the bar positioning:

      // TODO: calculate based on overall width & number of data points  
      .attr("x", function(d) { return x(d.date); })
      .attr("width", 16)
    

    Updated fiddle here: http://jsfiddle.net/LWyjf/

提交回复
热议问题