whytheq
whytheq

Reputation: 35577

Creating sunburst to accept csv data

I've maybe tried to run before I can walk but I've used the following two references:

http://codepen.io/anon/pen/fcBEe

https://bl.ocks.org/mbostock/4063423

From the first I've tried to take the idea of being able to feed a csv file into the sunburst with the function buildHierarchy(csv). The rest of the code is from Mike Bostock's example.

I've narrowed the data down to something very simple as follows:

var text = 
    "N-CB,50\n\
     N-TrP-F,800\n";

So I thought this would produce three concentric rings - which is does - but I was hoping that the inner ring would be split in the ratio of 800:50 as in the data. Why am I getting the rings that I'm getting?

<!DOCTYPE html>
<meta charset="utf-8">
<style>
  #sunBurst {
    position: absolute;
    top: 60px;
    left: 20px;
    width: 250px;
    height: 300px;
  }
  
  body {
    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
    margin: auto;
    position: relative;
    width: 250px;
  }
  
  form {
    position: absolute;
    right: 20px;
    top: 30px;
  }
</style>
<form>
  <label>
    <input type="radio" name="mode" value="size" checked> Size</label>
  <label>
    <input type="radio" name="mode" value="count"> Count</label>
</form>
<script src="//d3js.org/d3.v3.min.js"></script>
<div id="sunBurst"></div>
<script>

  var text = 
    "N-CB,50\n\
     N-TrP-F,800\n";


  var csv = d3.csv.parseRows(text);
  var json = buildHierarchy(csv);


  var width = 300,
    height = 250,
    radius = Math.min(width, height) / 2,
    color = d3.scale.category20c();

  //this bit is easy to understand:
  var svg = d3.select("#sunBurst").append("svg")

  .attr("width", width)
    .attr("height", height)
    .append("g")
    .attr({
      'transform': "translate(" + width / 2 + "," + height * .52 + ")",
      id: "sunGroup"
    });

  // it seems d3.layout.partition() can be either squares or arcs
  var partition = d3.layout.partition()
    .sort(null)
    .size([2 * Math.PI, radius * radius])
    .value(function(d) {
      return 1;
    });

  var arc = d3.svg.arc()
    .startAngle(function(d) {
      return d.x;
    })
    .endAngle(function(d) {
      return d.x + d.dx;
    })
    .innerRadius(function(d) {
      return Math.sqrt(d.y);
    })
    .outerRadius(function(d) {
      return Math.sqrt(d.y + d.dy);
    });



  var path = svg.data([json]).selectAll("path")
    .data(partition.nodes)
    .enter()
    .append("path")
    .attr("display", function(d) {
      return d.depth ? null : "none";
    })
    .attr("d", arc)
    .style("stroke", "#fff")
    .style("fill", function(d) {
      return color((d.children ? d : d.parent).name);
    })
    .attr("fill-rule", "evenodd")
    .style("opacity", 1)
    .each(stash);



  d3.selectAll("input").on("change", function change() {
    var value = this.value === "size" ? function() {
      return 1;
    } : function(d) {
      return d.size;
    };

    path
      .data(partition.value(value).nodes)
      .transition()
      .duration(2500)
      .attrTween("d", arcTween);
  });
  //});

  // Stash the old values for transition.
  function stash(d) {
    d.x0 = d.x;
    d.dx0 = d.dx;
  }

  // Interpolate the arcs in data space.
  function arcTween(a) {
    var i = d3.interpolate({
      x: a.x0,
      dx: a.dx0
    }, a);
    return function(t) {
      var b = i(t);
      a.x0 = b.x;
      a.dx0 = b.dx;
      return arc(b);
    };
  }

  d3.select(self.frameElement).style("height", height + "px");


  // Take a 2-column CSV and transform it into a hierarchical structure suitable
  // for a partition layout. The first column is a sequence of step names, from
  // root to leaf, separated by hyphens. The second column is a count of how 
  // often that sequence occurred.
  function buildHierarchy(csv) {
    var root = {
      "name": "root",
      "children": []
    };
    for (var i = 0; i < csv.length; i++) {
      var sequence = csv[i][0];
      var size = +csv[i][1];
      if (isNaN(size)) { // e.g. if this is a header row
        continue;
      }
      var parts = sequence.split("-");
      var currentNode = root;
      for (var j = 0; j < parts.length; j++) {
        var children = currentNode["children"];
        var nodeName = parts[j];
        var childNode;
        if (j + 1 < parts.length) {
          // Not yet at the end of the sequence; move down the tree.
          var foundChild = false;
          for (var k = 0; k < children.length; k++) {
            if (children[k]["name"] == nodeName) {
              childNode = children[k];
              foundChild = true;
              break;
            }
          }
          // If we don't already have a child node for this branch, create it.
          if (!foundChild) {
            childNode = {
              "name": nodeName,
              "children": []
            };
            children.push(childNode);
          }
          currentNode = childNode;
        } else {
          // Reached the end of the sequence; create a leaf node.
          childNode = {
            "name": nodeName,
            "size": size
          };
          children.push(childNode);
        }
      }
    }
    return root;
  };
</script>

There is a further live example of here on plunker : https://plnkr.co/edit/vqUqDtPCRiSDUIwfCbnY?p=preview

Upvotes: 0

Views: 633

Answers (1)

Nixie
Nixie

Reputation: 637

Your buildHierarchy function takes whitespace into account. So, when you write

  var text = 
    "N-CB,50\n\
     N-TrP-F,800\n";

it is actually two root nodes:

'N' and '     N'

You have two options:

  1. Use non-whitespace text like

     var text = 
        "N-CB,50\n" +
        "N-TrP-F,800\n";
    
  2. Fix buildHierarchy function to trim whitespace.

Upvotes: 1

Related Questions