D3.js使用嵌套文件的分组条形图

时间:2015-11-13 11:32:22

标签: javascript d3.js charts

我的D3.js的JavaScript代码有问题。我正在尝试使用d3.nest()函数来汇总我的大型CSV文件,然后从中创建可视化。我正在尝试制作一个如图所示的分组条形图:mbostock's example

但我加载时页面上没有显示任何内容。分组图表用于显示基于模块的实际和预测修复值的数量(module_category,如下面的示例数据所示):

module_category,component_category,date_repair,actual,predicted,
M1,P06,1/1/2009,39,63,
M1,P06,2009/10,3,4,2009/10/1
M1,P06,2009/11,4,3,2009/11/1
M1,P06,2009/12,4,2,2009/12/1
M1,P06,2009/02,29,45,2009/02/1
M1,P06,2009/03,29,32,2009/03/1
M1,P06,2009/04,10,22,2009/04/1
M1,P06,2009/05,13,15,2009/05/1
M1,P06,2009/06,9,16,2009/06/1
M1,P06,2009/07,7,12,2009/07/1

这是我到目前为止编写的代码:

(function() { 
  
  var margin = {top: 20, right: 90, bottom: 30, left: 60},
      width = 980 - margin.left - margin.right,
      height = 500 - margin.top - margin.bottom;
  var x0 = d3.scale.ordinal()
          .rangeRoundBands([0, width], .1);

  var x1 = d3.scale.ordinal();

  var y = d3.scale.linear()
      .range([height, 0]);

  var color = d3.scale.category10();

  var xAxis = d3.svg.axis()
      .scale(x0)
      .orient("bottom");

  var yAxis = d3.svg.axis()
      .scale(y)
      .orient("left")
      .tickFormat(d3.format(".2s"));

  var svg = d3.select("#maincontent").append("svg")
      .attr('width', width + margin.right + margin.left)
      .attr('height', height + margin.top + margin.bottom)
    .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

  var tip=d3.tip()
              .attr("class","d3-tip")
              .offset([-10, 0])
              .html(function(d) { return "No. of repairs: " + d.value; });

  d3.csv("data/Consolidated_result.csv", function(error, data) {
    if (error) throw error;

    data = d3.nest()
      .key(function(d) { return d.module_category;})
      .rollup(function(values){
          var counts = {}, keys = ['actual', 'predicted']
          keys.forEach(function(key){
              counts[key] = d3.sum(values, function(d){ return d[key]})
          })
          return counts
      })
      .entries(data);

      console.log(data);

    x0.domain(data.map(function(d) { return d.key; }));
    x1.domain(d3.keys(data)).rangeRoundBands([0, x0.rangeBand()]);
    y.domain([0, d3.max(data, function(d) { return d3.max(d.values, function(d) { return d.values.length; }); })]);

    svg.call(tip);

    svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis);

    svg.append("g")
        .attr("class", "y axis")
        .call(yAxis)
      .append("text")
        .attr("transform", "rotate(-90)")
        .attr("y", 0 - margin.left)
        .attr("x", 0 - (height / 2))
        .attr("dy", "1em")
        .style("text-anchor", "middle")
        .text("Number of Repairs");

    var module = svg.selectAll(".module")
        .data(data, function(d){ return d.values; })
      .enter().append("g")
        .attr("class", "g")
        .attr("transform", function(d) { return "translate(" + x0(d.key) + ",0)"; });

    module.selectAll("rect")
        .data(data)
      .enter().append("rect")
        .attr("width", x1.rangeBand())
        .attr("x", function(d) { return x1(d.key); })
        .attr("y", function(d) { return y(d.values); })
        .attr("height", function(d) { return height - y(d.values); })
        .style("fill", function(d) { return color(d.key); });

    var legend = svg.selectAll(".legend")
        .data(d3.keys(data).slice().reverse())
      .enter().append("g")
        .attr("class", "legend")
        .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });

    legend.append("rect")
        .attr("x", width - 18)
        .attr("width", 18)
        .attr("height", 18)
        .style("fill", color);

    legend.append("text")
        .attr("x", width - 24)
        .attr("y", 9)
        .attr("dy", ".35em")
        .style("text-anchor", "end")
        .text(function(d) { return d; });


  });
}

我还尝试在图表中添加交互性,以允许用户在单击模块时查看与模块相关的组件。下面的图片是我想要制作的理想图表:

groupedBarChart sample picture

1 个答案:

答案 0 :(得分:1)

代码中的一些问题:

问题1 :CSV实际不正确,预测数据中包含日期:

module_category,component_category,date_repair,actual,predicted,
M1,P06,1/1/2009,39,63,
M1,P06,2009/10,3,4,2009/10/1
M1,P06,2009/11,4,3,2009/11/1
M1,P06,2009/12,4,2,2009/12/1

应该是:

module_category,component_category,date_repair,actual,predicted
M1,P06,1/1/2009,39,63
M2,P06,2009/10/1,3,4
M3,P06,2009/10/1,30,40

问题2 :x1的域名错误。 你的代码:

x1.domain(d3.keys(data)).rangeRoundBands([0, x0.rangeBand()]);

此处d3.keys(data)未定义

应该是

x1.domain(['actual', 'predicted']).rangeRoundBands([0, x0.rangeBand()]);

问题3 :y的域名错误。 你的代码:

 y.domain([0, d3.max(data, function(d) { return d3.max(d.values, function(d) { return d.values.length; }); })]);

应该是

//store all the values in array
var yval = [];
    data.forEach(function(d) {
      yval.push(d.values.actual);
      yval.push(d.values.predicted);
    });
 //then do max on that
y.domain([0, d3.max(yval)]);

Issue4 :数据集不正确。

 module.selectAll("rect")
        .data(data) //you are passing an object but it should be an array
      .enter().append("rect")

应该是

module.selectAll("rect")
  .data(function(d) {
    var ary = [];
    ary.push({name:"actual", value:d.values.actual});
    ary.push({name:"predicted", value:d.values.predicted});
    return ary;
  })

工作代码here

希望这有帮助!