多层比较直方图

时间:2013-11-14 16:20:39

标签: d3.js

我需要使用d3.js库构建直方图。直方图应如下所示。该直方图的主要目的是比较两组结果。下图中显示的结果表示在该月的同一天收集的数据,但是在两个不同的月份(例如1月1日至6日(绿色)和2月(蓝色))。

我目前拥有的直方图基本上显示了正确的数据,只是它没有覆盖它们(甚至并排显示它们)。相反,它显示按日期排序,结果表示1月1日(左侧),代表2月2日(右侧)的结果。为了让它们并排显示,我该怎么办?

编辑:我在Angular环境中工作,我使用预建指令来显示图形。该指令的代码是https://github.com/fullscale/dangle/blob/master/dist/dangle.datehisto.js

期望的结果:

desired chart

目前的结果:

current chart

1 个答案:

答案 0 :(得分:2)

这里的问题是你正在使用一个时间尺度,它应该是你想要做的线性。您不希望x偏移量根据实际日期/时间增加,而是仅在日期的date.getDate()部分增加。假设d.time与new Date().getTime()表示相同,那么您可以将比例更改为线性,并仅使用日期加上月份的偏移来确定您的x值。这将要求您构建某种形式的图例来表示这几个月。

首先更改我们使用的比例:

// create x,y scales (x is inferred as time)
// var x = d3.time.scale()
//    .range([0, width]);
//
// Use linear scale since we really care about the day portion of the date/time
var x = d3.scale.linear()
      .range([0, width]);

然后计算我们的月和日范围:

// Get the range of months so we can use the month
// to offset the x value for overlay
var monthExtent = d3.extent(data,function(d) { 
            var date = new Date(); 
            date.setTime(d.time.getTime()); 
            return date.getMonth(); 
        });

// Get the range of days for the graph
// If you always want to display the whole month
// var dateExtent = [0,31]
//
// Otherwise calculate the range
var dateExtent = d3.extent(data,function(d) {  
            var date = new Date(); 
            date.setTime(d.time.getTime()); 
            return date.getDate(); 
        });

然后将x域设置为我们的日期范围:

// recalculate the x and y domains based on the new data.
 // we have to add our "interval" to the max otherwise 
 // we don't have enough room to draw the last bar.
 //
 //x.domain([
 //    d3.min(data, function(d) { 
 //        return d.time;
 //    }), 
 //    d3.max(data, function(d) { 
 //        return d.time;
 //    })
 //]);


 // Our x domain is just the range of days 
 x.domain(dateExtent);

添加色标以区分月份:

// Set up a color scale to separate months
 var color = d3.scale.category10();

现在,更改x属性以使用日期值加上月份的偏移量来创建叠加层。我在这里使用了20个像素,但您可以轻松地将其更改为teh条宽度的百分比。然后使用月份和颜色比例添加填充属性,以便每个月获得它自己的颜色。

bars.enter()
    .append('rect')
        .attr('class', 'histo rect ')
        .attr('cursor', 'pointer')
        .attr('x', function(d) {
            // Extract the day portion of the date/time
            // and then offset the rect by it's month value
            var date = new Date();
            date.setTime(d.time.getTime());
            return x(date.getDate()) + (date.getMonth() - monthExtent[0]) * 20; 
        })
        .attr("fill",function(d) { 
            var date = new Date();
            date.setTime(d.time);
            return color(date.getMonth()); 
        })
        .attr("y", function(d) { return height })
        .attr('width', barWidth)
        .transition()
            .delay(function (d,i){ return i * 0; })
            .duration(500)
                .attr('height', function(d) { return height - y(d.count); })
                .attr('y', function(d) { return y(d.count); });

最后,您可能需要更改barWidth的计算方式,以确保每天之间有足够的空间。希望这有帮助!