简体   繁体   中英

D3.js Grouped Bar chart using nested file

I have a problem with my JavaScript code for D3.js. I am trying to use the d3.nest() function to summarize my large CSV file and then create visualizations from it. I am trying to make a grouped bar chart as shown here : mbostock's example .

But nothing is displayed on the page when I load it up. The grouped chart is meant to show the number of actual and predicted repairs values based on the modules ( module_category , as shown in the sample data below):

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

This is the code I've written so far:

 (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; }); }); } 

I am also trying to add interactivity to the chart to allow the user to view the components related to a module when they click on it. The picture below is the ideal chart I am looking to make:

groupedBarChart示例图片

Some issues in your code:

Issue1 : CSV is incorrect actual and predicted data have dates in them:

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

should have been:

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

Issue2 : domain for x1 is wrong. Your code:

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

here d3.keys(data) is undefined

should have been

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

Issue3 : domain for y is wrong. Your code:

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

should have been

//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 : data set is incorrect.

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

should have been

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;
  })

Working code here

Hope this helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM