Building legends in d3.js





It is a common and necessary practice in datavisualization to build legends. D3.js does not provide any helper function for that, meaning you have to build it from scratch. This document provides a few templates for categorical and continuous legend. Hopefully you will find one that suits your needs.

Categorical legend: 100% handmade



Notes:

  • Each element of the legend is added with a specific line of code.

  • Very tedious, but allows fine grain customization.

  • Not suitable if many groups since it would create too much code.
<!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>
  <svg id="my_dataviz" height=300 width=450></svg>
</div>
<script>

// select the svg area
var svg = d3.select("#my_dataviz")

// Handmade legend
svg.append("circle").attr("cx",200).attr("cy",130).attr("r", 6).style("fill", "#69b3a2")
svg.append("circle").attr("cx",200).attr("cy",160).attr("r", 6).style("fill", "#404080")
svg.append("text").attr("x", 220).attr("y", 130).text("variable A").style("font-size", "15px").attr("alignment-baseline","middle")
svg.append("text").attr("x", 220).attr("y", 160).text("variable B").style("font-size", "15px").attr("alignment-baseline","middle")

</script>

Categorical legend: use a loop



Notes:

  • If you have legends with many entry, it is more convenient to use a loop.

  • This is done using a classic enter() approach: adding one element per entry of the key.
<!DOCTYPE html>
<meta charset="utf-8">

<!-- Load d3.js & color palette -->
<script src="https://d3js.org/d3.v4.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>

<!-- Create a div where the graph will take place -->
<div>
  <svg id="my_dataviz2" height=300 width=450></svg>
</div>
<script>

// select the svg area
var Svg = d3.select("#my_dataviz2")

// create a list of keys
var keys = ["Mister A", "Brigitte", "Eleonore", "Another friend", "Batman"]

// Usually you have a color scale in your chart already
var color = d3.scaleOrdinal()
  .domain(keys)
  .range(d3.schemeSet2);

// Add one dot in the legend for each name.
Svg.selectAll("mydots")
  .data(keys)
  .enter()
  .append("circle")
    .attr("cx", 100)
    .attr("cy", function(d,i){ return 100 + i*25}) // 100 is where the first dot appears. 25 is the distance between dots
    .attr("r", 7)
    .style("fill", function(d){ return color(d)})

// Add one dot in the legend for each name.
Svg.selectAll("mylabels")
  .data(keys)
  .enter()
  .append("text")
    .attr("x", 120)
    .attr("y", function(d,i){ return 100 + i*25}) // 100 is where the first dot appears. 25 is the distance between dots
    .style("fill", function(d){ return color(d)})
    .text(function(d){ return d})
    .attr("text-anchor", "left")
    .style("alignment-baseline", "middle")
</script>

Categorical legend: square



Notes:

  • Small modification to add squares instead of circles.

  • Play with the size variable to change the whole size.
<!DOCTYPE html>
<meta charset="utf-8">

<!-- Load d3.js & color palette -->
<script src="https://d3js.org/d3.v4.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>

<!-- Create a div where the graph will take place -->
<div>
  <svg id="my_dataviz3" height=300 width=450></svg>
</div>
<script>

// select the svg area
var SVG = d3.select("#my_dataviz3")

// create a list of keys
var keys = ["Mister A", "Brigitte", "Eleonore", "Another friend", "Batman"]

// Usually you have a color scale in your chart already
var color = d3.scaleOrdinal()
  .domain(keys)
  .range(d3.schemeSet1);

// Add one dot in the legend for each name.
var size = 20
SVG.selectAll("mydots")
  .data(keys)
  .enter()
  .append("rect")
    .attr("x", 100)
    .attr("y", function(d,i){ return 100 + i*(size+5)}) // 100 is where the first dot appears. 25 is the distance between dots
    .attr("width", size)
    .attr("height", size)
    .style("fill", function(d){ return color(d)})

// Add one dot in the legend for each name.
SVG.selectAll("mylabels")
  .data(keys)
  .enter()
  .append("text")
    .attr("x", 100 + size*1.2)
    .attr("y", function(d,i){ return 100 + i*(size+5) + (size/2)}) // 100 is where the first dot appears. 25 is the distance between dots
    .style("fill", function(d){ return color(d)})
    .text(function(d){ return d})
    .attr("text-anchor", "left")
    .style("alignment-baseline", "middle")
</script>