0

My question is similar to that asked here : D3.js - Donut charts with multiple rings

In that question, there was the use of nested arrays to draw the inner rings in the posted jsFiddle: http://jsfiddle.net/Qh9X5/154/ referenced as a solution to the problem.

I am trying to implement the donut chart with inner rings but this time using a csv file. This is my current code:

var margin = {top: 20, right: 30, bottom: 30, left: 30},
 width = 500 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom,
    donutWidth = 50;
    //radius = Math.min(width, height) / 2;

var color = d3.scale.category10(); 

var pie = d3.layout.pie()
    //.value(function(d){ return d.count;})
    .sort(null);

var arc = d3.svg.arc();
    //.innerRadius(radius - donutWidth)
    //.outerRadius(radius - 50);

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

d3.csv("data/svm-prediction.csv", function(error, data) {
  if (error) throw error;

  var classNames = d3.keys(data[0]).filter(function(key) { return key !== "Class"; });

  data.forEach(function(d) {
      d.predValues = classNames.map(function(name) { return {name: name, value: +d[name]}; });
  });

  var gs = chart1.selectAll("g").data(d3.values(function(d){ return d.predValues; })).enter().append("g");

  var path = gs.selectAll('path')
        .data(function(d){ return pie(d); })
      .enter().append('path')
        .attr('d', function(d, i , j) { return
          arc.innerRadius(10+donutWidth*j).outerRadius(donutWidth*(j+1))(d);
        })
        .attr('fill', function(d, i) { return color(d.data.Class); });

});

I keep running the code, but it doesn't display on the webpage. I am trying to show the counts for the predicted and actual classes, grouped by the class names. Please assist.

This is the format of the csv file:

Class,Actual_Class,Predicted_Class,Accuracy
Class A,495,495,100
Class B,495,492,99
Class C,495,495,100
Class D,495,495,100
Class E,495,495,100
Community
  • 1
  • 1
moodygeek
  • 127
  • 13

1 Answers1

1

Similar to the fiddle you have posted let's try to convert the data we get from our csv into arrays of data for actual values and predicted values. I am sure that there might be better ways to do this but a simple, straight forward approach will be as follows:

var donutData = new Array,
    actualValues = new Array,
    predValues = new Array;

data.forEach(function(d) {
  actualValues.push(d.Actual_Class);
  predValues.push(d.Predicted_Class);
});

donutData.push(actualValues);
donutData.push(predValues);

You won't have to do a filter on class name and all. The donutData object that we created (2D array) can directly be used for creating the donut charts. Next, while creating gs you are trying to use bound data without actually binding any before doing so. So replace that line with:

var gs = chart1.selectAll("g").data(donutData).enter().append("g");

Now that we have data nicely bound to g tags, one for each class, we can proceed with donut chart creation:

var path = gs.selectAll('path')
    .data(function(d){ return pie(d); })
  .enter().append('path')
    .attr('d', function(d, i , j) { 
      return arc.innerRadius(10+donutWidth*j).outerRadius(donutWidth*(j+1))(d);
    })
    .attr('fill', function(d, i) { return color(i); });

Notice that I have used pie(d) to select the corresponding arrays we constructed. Also, I have simply passed i to the color() for generating different colors. the d3.csv() part will look something like this:

d3.csv("data.csv", function(error, data) {
  if (error) console.log("error reading csv");

  var donutData = new Array,
      actualValues = new Array,
      predValues = new Array;    

  data.forEach(function(d) {
      actualValues.push(d.Actual_Class);
      predValues.push(d.Predicted_Class);
  });

  donutData.push(actualValues);
  donutData.push(predValues);

  var gs = chart1.selectAll("g").data(donutData).enter().append("g");

  var path = gs.selectAll('path')
        .data(function(d){ return pie(d); })
      .enter().append('path')
        .attr('d', function(d, i , j) { 
          return arc.innerRadius(10+donutWidth*j).outerRadius(donutWidth*(j+1))(d);
        })
        .attr('fill', function(d, i) { return color(i); });

});

Hope this was what you were actually looking for.

Rajeev Atmakuri
  • 888
  • 1
  • 10
  • 22
  • I made the changes to the code but that also didn't work. – moodygeek Nov 13 '15 at 03:30
  • can you check the console and find out any specific errors? – Rajeev Atmakuri Nov 13 '15 at 06:19
  • surprisingly its working now only this is almost what i'm looking for. I want to achieve two rings, with the inner ring for the distribution of the "actual class" values for each class so a partition of 5, and then the outer ring for the "predicted class" values for each class. – moodygeek Nov 13 '15 at 08:34
  • Oh ok. So instead of making arrays of the form `{pred value, actual value}` for each class we can make two arrays corresponding to actual and predicted values of the classes. I have made the necessary code changes to accommodate the same. Have a look now. – Rajeev Atmakuri Nov 13 '15 at 10:22
  • Glad to help. You can accept this as the answer if you found it helpful. – Rajeev Atmakuri Nov 13 '15 at 11:30