Migrating d3 v2 to d3 v4 for Chord Diagram

Viewed 970

I am using this example to guide my foray into chord diagrams with d3. I have it working with my data in v2 (the version the example is in), and now I am attempting to upgrade to v4.

Here is the code that works with v2:

<script src="http://d3js.org/d3.v2.min.js?2.8.1"></script>
<script>

var width = 900,
    height = 900,
    outerRadius = Math.min(width, height) / 2 - 10,
    innerRadius = outerRadius - 24;

var formatPercent = d3.format(",.0f");

var arc = d3.svg.arc()
            .innerRadius(innerRadius)
                        .outerRadius(outerRadius);

var layout = d3.layout.chord()
                             .padding(.02)
                             .sortSubgroups(d3.descending)
                             .sortChords(d3.ascending);

var path = d3.svg.chord()
                         .radius(innerRadius);

var svg = d3.select("body").append("svg")
                      .attr("width", width)
                        .attr("height", height)
                        .append("g")
                        .attr("id", "circle")
                        .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

svg.append("circle")
     .attr("r", outerRadius);

d3.csv("teams.csv", function(cities) {
d3.json("matrix.json", function(matrix) {

// Compute the chord layout.
layout.matrix(matrix);

// Add a group per neighborhood.
var group = svg.selectAll(".group")
                           .data(layout.groups)
                             .enter().append("g")
                             .attr("class", "group")
                             .on("mouseover", mouseover);

// Add a mouseover title.
group.append("title").text(function(d, i) {
return cities[i].name + ": " + formatPercent(d.value) + " as business unit";
});

// Add the group arc.
var groupPath = group.append("path")
                                         .attr("id", function(d, i) { return "group" + i; })
                                         .attr("d", arc)
                     .style("fill", function(d, i) { return cities[i].color; });

// Add the chords.
var chord = svg.selectAll(".chord")
                             .data(layout.chords)
               .enter().append("path")
               .attr("class", "chord")
               .style("fill", function(d) { return cities[d.source.index].color; })
               .attr("d", path);

// Add an elaborate mouseover title for each chord.
 chord.append("title").text(function(d) {
 return cities[d.source.index].name
 + " → " + cities[d.target.index].name
 + ": " + formatPercent(d.source.value)
 + "\n" + cities[d.target.index].name
 + " → " + cities[d.source.index].name
 + ": " + formatPercent(d.target.value);
 });

function mouseover(d, i) {
chord.classed("fade", function(p) {
return p.source.index != i
&& p.target.index != i;
});
}
});
});

</script>

Here is the same code midway through my attempt to migrate to v4:

<script src="http://d3js.org/d3.v4.min.js"></script>
<script>

var width = 900,
height = 900,
outerRadius = Math.min(width, height) / 2 - 10,
innerRadius = outerRadius - 24;

var formatPercent = d3.format(",.0f");

var arc = d3.arc()
            .innerRadius(innerRadius)
            .outerRadius(outerRadius);

var layout = d3.chord()
                             .padAngle(.02)
                             .sortSubgroups(d3.descending)
                             .sortChords(d3.ascending);

var path = d3.ribbon()
             .radius(innerRadius);

var svg = d3.select("body").append("svg")
            .attr("width", width)
            .attr("height", height)
            .append("g")
            .attr("id", "circle")
            .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

svg.append("circle")
   .attr("r", outerRadius);

d3.csv("teams.csv", function(cities) {
d3.json("matrix.json", function(matrix) {

// Compute the chord layout.
layout.matrix(matrix);

// Add a group per neighborhood.
var group = svg.selectAll(".group")
               .data(layout.groups)
               .enter().append("g")
               .attr("class", "group")
               .on("mouseover", mouseover);

// Add a mouseover title.
group.append("title").text(function(d, i) {
return cities[i].name + ": " + formatPercent(d.value) + " as business unit";
});

// Add the group arc.
var groupPath = group.append("path")
                     .attr("id", function(d, i) { return "group" + i; })
                     .attr("d", arc)
                     .style("fill", function(d, i) { return cities[i].color; });

// Add the chords.
var chord = svg.selectAll(".chord")
               .data(layout.chords)
               .enter().append("path")
               .attr("class", "chord")
               .style("fill", function(d) { return cities[d.source.index].color; })
               .attr("d", path);

// Add an elaborate mouseover title for each chord.
 chord.append("title").text(function(d) {
 return cities[d.source.index].name
 + " → " + cities[d.target.index].name
 + ": " + formatPercent(d.source.value)
 + "\n" + cities[d.target.index].name
 + " → " + cities[d.source.index].name
 + ": " + formatPercent(d.target.value);
 });

function mouseover(d, i) {
chord.classed("fade", function(p) {
return p.source.index != i
&& p.target.index != i;
});
}
});
});

</script>

So far, I've flattened the namespaces (up to d3.csv), changed padding to padAngle, and changed var path = d3.chord() to var path = d3.ribbon(). As I make each change, I am checking the error messages in Chrome Developer. After making those changes, the current error is layout.matrix is not a function. This makes sense, based on v4 standards. To combat this, I tried adding .data(layout.matrix) to the var svg creation. I tried a few other routes gleaned from other chord diagram examples, to no avail.

How should I access and bind the data in v4?

Edit: I added .data(layout(matrix)) instead, and now the g elements with class=group are being created. However, this error is occurring: attribute d: Expected number, "MNaN,NaNLNaN,NaNZ". So I'm thinking this means the location is not being populated correctly.

Edit #2: Now I've gotten everything to show up except for the bars around the outside. Here is my current code. I believe the d attribute of the path elements within the g groups are wrong. They are set to be the same as the path elements outside the g groups. When I attempt to set them to arc instead (.attr("d", arc), the error attribute d: Expected number, "MNaN,NaNLNaN,NaNZ". occurs.

<script>

var width = 900,
    height = 900,
    outerRadius = Math.min(width, height) / 2 - 10,
    innerRadius = outerRadius - 24;

var formatPercent = d3.format(",.0f");

var arc = d3.arc()
            .innerRadius(innerRadius)
            .outerRadius(outerRadius);

var layout = d3.chord()
                             .padAngle(.02)
                             .sortSubgroups(d3.descending)
                             .sortChords(d3.ascending);

var ribbon = d3.ribbon()
             .radius(innerRadius);

var svg = d3.select("body")
            .append("svg")
              .attr("width", width)
              .attr("height", height)
            .append("g")
              .attr("id", "circle")
              .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")

svg.append("circle")
     .attr("r", outerRadius);

d3.csv("teams.csv", function(cities) {
d3.json("matrix.json", function(matrix) {

// Add a group per neighborhood.
var group = svg.selectAll(".group")
               .data(layout(matrix))
               .enter()
               .append("g")
                 .attr("class", "group");

// Add the group arc.
var groupRibbon = group.append("path")
                     .attr("id", function(d, i) { return "group" + i; })
                     .attr("d", ribbon)
                     //.style("fill", function(d, i) { return cities[i].color; })
                     ;

// Add the chords.
var chord = svg.selectAll(".chord")
               .data(layout(matrix))
               .enter().append("path")
               .attr("class", "chord")
               .style("fill", function(d) { return cities[d.source.index].color; })
               .attr("d", ribbon);
});
});

</script>
0 Answers
Related