Question

I am currently trying to create a simple Sankey diagram using D3.js. I have gotten most of the way, but setting the height and y-axis is proving to be a challenge. Specifically, the error returned is the following:

Error: Problem parsing d="M15, NaNC479, NaN 479, NaN 943, NaN" Error: Invalid value for attribute height = "NaN"

I have tried to follow the example (which works): http://bost.ocks.org/mike/sankey/ My example is here: http://zenbot.ca/elections.html

Note, the text underneath ("Brockville", "Central Toronto" etc) is just a test to make sure I am connecting to the JSON file correctly, so you can ignore that. The blob up at the top of the page should look like the Sankey diagram, but it currently does not.

A sample of my JSON (which is available at http://zenbot.ca/js/electionJSON.json) seems to be formed in the same manner as Mr. Bostock's example (http://bost.ocks.org/mike/sankey/energy.json) and is the following:

{
  "nodes": [
    {"name": "Brockville"},
    {"name": "Central Toronto"},
    ...
  ],
  "links": [
    {"source": 0, "type": "Individual", "target": 26, "amount": 500},
    {"source": 5, "type": "Individual", "target": 16, "amount": 200},
    ...
  ]
}

What I've tried to do to correct the problem myself is I've played around with the "d.dy" value (trying to replace it with "d.amount"). Hard coding it at "100" instead of the function at about line 79 makes one node appear but the rest is still a tangled mess.

So...it seems to be down to the height and placement of the nodes. It looks a lot like Bostock's example, but clearly it is not. Any ideas?

The code to get the sankey working is as follows:

d3.json("js/electionJSON.json", function(election) {

  sankey
      .nodes(election.nodes)
      .links(election.links)
      .layout(32);

  var link = svg.append("g").selectAll(".link")
      .data(election.links)
    .enter().append("path")
      .attr("class", "link")
      .attr("d", path)
      .style("stroke-width", function(d) { return Math.max(1, d.dy); })
      .sort(function(a, b) { return b.dy - a.dy; });

  link.append("title")
      .text(function(d) { return d.source.name + " → " + d.target.name + "\n" + format(d.amount); });

  var node = svg.append("g").selectAll(".node")
      .data(election.nodes)
    .enter().append("g")
      .attr("class", "node")
      .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
    .call(d3.behavior.drag()
      .origin(function(d) { return d; })
      .on("dragstart", function() { this.parentNode.appendChild(this); })
      .on("drag", dragmove));

  node.append("rect")
      .attr("height", function(d) { return d.dy; })
      .attr("width", sankey.nodeWidth())
      .style("fill", function(d) { return d.color = color(d.name.replace(/ .*/, "")); })
      .style("stroke", function(d) { return d3.rgb(d.color).darker(2); })
    .append("title")
      .text(function(d) { return d.name + "\n" + format(d.amount); });

  node.append("text")
      .attr("x", -6)
      .attr("y", function(d) { return d.dy / 2; })
      .attr("dy", ".35em")
      .attr("text-anchor", "end")
      .attr("transform", null)
      .text(function(d) { return d.name; })
    .filter(function(d) { return d.x < width / 2; })
      .attr("x", 6 + sankey.nodeWidth())
      .attr("text-anchor", "start");

  function dragmove(d) {
    d3.select(this).attr("transform", "translate(" + d.x + "," + (d.y = Math.max(0, Math.min(height - d.dy, d3.event.y))) + ")");
    sankey.relayout();
    link.attr("d", path);
  }
});
Was it helpful?

Solution

You may kick yourself for this one, but it was good fun for me to play with the sankey implementation. Your biggest issue right now is that the data in electionJSON.json uses amount as the value. Yet sankey expects the value to be called value:

function value (link) {
  return link.value;
}

This will always return undefined in your dataset. It seems like sankey makes this assumption in multiple places, so I ended up using sed to replace the word "amount" with "value". That seemed to do the trick.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top