Adding labels to chord diagram





This post directly follows the previous basic chord diagram. It describes how to add axis and labels around the outer circle. See the chord section for more examples. This example works with d3.js v4 and v6


chord diagram section

Steps:

  • See the previous post for the basics of chord diagram.

  • Ticks position is first computed using the groupTicks() function that is defined at the end of the script. This function returns info allowing to place ticks thanks to a translation.

  • Adding labels follows almost the same process. Note the formula d.angle * 180 / Math.PI - 90 to go from radian to degree

  • Next step: control color.
|
<!DOCTYPE html>
<meta charset="utf-8">

<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>

<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>

<!DOCTYPE html>
<meta charset="utf-8">

<!-- Load d3.js -->
<script src="https://d3js.org/d3.v6.js"></script>

<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>

<script>


// create the svg area
var svg = d3.select("#my_dataviz")
  .append("svg")
    .attr("width", 440)
    .attr("height", 440)
  .append("g")
    .attr("transform", "translate(220,220)")

// create a matrix
var matrix = [
  [11,  58, 89, 28],
  [ 51, 18, 20, 61],
  [ 80, 145, 80, 85],
  [ 103,   99,  40, 71]
];

// give this matrix to d3.chord(): it will calculates all the info we need to draw arc and ribbon
var res = d3.chord()
    .padAngle(0.05)
    .sortSubgroups(d3.descending)
    (matrix)

// Add the links between groups
svg
  .datum(res)
  .append("g")
  .selectAll("path")
  .data(function(d) { return d; })
  .enter()
  .append("path")
    .attr("d", d3.ribbon()
      .radius(190)
    )
    .style("fill", "#69b3a2")
    .style("stroke", "black");

// this group object use each group of the data.groups object
var group = svg
  .datum(res)
  .append("g")
  .selectAll("g")
  .data(function(d) { return d.groups; })
  .enter()

// add the group arcs on the outer part of the circle
group.append("g")
    .append("path")
    .style("fill", "grey")
    .style("stroke", "black")
    .attr("d", d3.arc()
      .innerRadius(190)
      .outerRadius(200)
    )

// Add the ticks
group
  .selectAll(".group-tick")
  .data(function(d) { return groupTicks(d, 25); })    // Controls the number of ticks: one tick each 25 here.
  .enter()
  .append("g")
    .attr("transform", function(d) { return "rotate(" + (d.angle * 180 / Math.PI - 90) + ") translate(" + 200 + ",0)"; })
  .append("line")               // By default, x1 = y1 = y2 = 0, so no need to specify it.
    .attr("x2", 6)
    .attr("stroke", "black")

// Add the labels of a few ticks:
group
  .selectAll(".group-tick-label")
  .data(function(d) { return groupTicks(d, 25); })
  .enter()
  .filter(function(d) { return d.value % 25 === 0; })
  .append("g")
    .attr("transform", function(d) { return "rotate(" + (d.angle * 180 / Math.PI - 90) + ") translate(" + 200 + ",0)"; })
  .append("text")
    .attr("x", 8)
    .attr("dy", ".35em")
    .attr("transform", function(d) { return d.angle > Math.PI ? "rotate(180) translate(-16)" : null; })
    .style("text-anchor", function(d) { return d.angle > Math.PI ? "end" : null; })
    .text(function(d) { return d.value })
    .style("font-size", 9)


// Returns an array of tick angles and values for a given group and step.
function groupTicks(d, step) {
  var k = (d.endAngle - d.startAngle) / d.value;
  return d3.range(0, d.value, step).map(function(value) {
    return {value: value, angle: value * k + d.startAngle};
  });
}

</script>
<script>

// create the svg area
const svg = d3.select("#my_dataviz")
  .append("svg")
    .attr("width", 440)
    .attr("height", 440)
  .append("g")
    .attr("transform", "translate(220,220)")

// create a matrix
const matrix = [
  [11,  58, 89, 28],
  [ 51, 18, 20, 61],
  [ 80, 145, 80, 85],
  [ 103,   99,  40, 71]
];

// give this matrix to d3.chord(): it will calculates all the info we need to draw arc and ribbon
const res = d3.chord()
    .padAngle(0.05)
    .sortSubgroups(d3.descending)
    (matrix)

// Add the links between groups
svg
  .datum(res)
  .append("g")
  .selectAll("path")
  .data(d => d)
  .join("path")
    .attr("d", d3.ribbon()
      .radius(190)
    )
    .style("fill", "#69b3a2")
    .style("stroke", "black");

// this group object use each group of the data.groups object
const group = svg
  .datum(res)
  .append("g")
  .selectAll("g")
  .data(d => d.groups)
  .enter()

// add the group arcs on the outer part of the circle
group.append("g")
    .append("path")
    .style("fill", "grey")
    .style("stroke", "black")
    .attr("d", d3.arc()
      .innerRadius(190)
      .outerRadius(200)
    )

// Add the ticks
group
  .selectAll(".group-tick")
  .data(d => groupTicks(d, 25))    // Controls the number of ticks: one tick each 25 here.
  .join("g")
  .attr("transform", d => `rotate(${d.angle * 180 / Math.PI - 90}) translate(200,0)`)
  .append("line")               // By default, x1 = y1 = y2 = 0, so no need to specify it.
    .attr("x2", 6)
    .attr("stroke", "black")

// Add the labels of a few ticks:
group
  .selectAll(".group-tick-label")
  .data(d => groupTicks(d, 25))
  .enter()
  .filter(d => d.value % 25 === 0)
  .append("g")
    .attr("transform", d => `rotate(${d.angle * 180 / Math.PI - 90}) translate(200,0)`)
  .append("text")
    .attr("x", 8)
    .attr("dy", ".35em")
    .attr("transform", function(d) { return d.angle > Math.PI ? "rotate(180) translate(-16)" : null; })
    .style("text-anchor", function(d) { return d.angle > Math.PI ? "end" : null; })
    .text(d => d.value)
    .style("font-size", 9)


// Returns an array of tick angles and values for a given group and step.
function groupTicks(d, step) {
  const k = (d.endAngle - d.startAngle) / d.value;
  return d3.range(0, d.value, step).map(function(value) {
    return {value: value, angle: value * k + d.startAngle};
  });
}

</script>

Related blocks →