d3 SVG Legend (v4)

Tired of making legends for your data visualizations? Me too, enjoy.

A library to make legends in svg-land easy as pie.

By Susie Lu

Usage

Client-side

Version

This is the version compatible with d3v4, please go here for the version compatible with d3v3

Changes when moving to d3v4 of this component

  • Flattened naming for accessing functions
    • d3.legend.color => d3.legendColor
    • d3.legend.size => d3.legendSize
    • d3.legend.symbol => d3.legendSymbol
  • NPM package no longer binds to global d3, is now just an object with the three legend functions

CDN

You can add the latest version of d3-legend hosted on cdnjs.

https://cdnjs.com/libraries/d3-legend

Include the file directly

You must include the d3 library before including the legend file. Then you can simply add the compiled js file to your website:

npm

Already using d3? Great! You can add the d3 legend as a node module by running:

npm i d3-svg-legend -S

Github + feedback

The full source code is available on github. I would love to hear from you about any additional features that would be useful, please say hi on twitter @DataToViz.

Contents

Color

Documentation

Examples

Quantile Scale Legend

          

var quantize = d3.scaleQuantize()
  .domain([ 0, 0.15 ])
  .range(d3.range(9).map(function(i) { return "q" + i + "-9"; }));

var svg = d3.select("svg");

svg.append("g")
  .attr("class", "legendQuant")
  .attr("transform", "translate(20,20)");

var legend = d3.legendColor()
  .labelFormat(d3.format(".2f"))
  .useClass(true)
  .title("A really really really really 
    really long title")
  .titleWidth(100)
  .scale(quantize);

svg.select(".legendQuant")
  .call(legend);
          
        

Treshold Scale Legend

          

var thresholdScale = d3.scaleThreshold()
  .domain([ 0, 1000, 2500, 5000, 10000 ])
  .range(d3.range(6)
  .map(function(i) { return "q" + i + "-9"}));

var svg = d3.select("svg");

svg.append("g")
  .attr("class", "legendQuant")
  .attr("transform", "translate(20,20)");

var legend = d3.legendColor()
    .labelFormat(d3.format(".2f"))
    .labels(d3.legendHelpers.thresholdLabels)
    .useClass(true)
    .scale(thresholdScale)

/*
----legendHelpers.thresholdLabels----
function({
  i,
  genLength,
  generatedLabels,
  labelDelimiter
}) {
  if (i === 0) {
    const values = generatedLabels[i].split(` ${labelDelimiter} `)
    return `Less than ${values[1]}`
  } else if (i === genLength - 1) {
    const values = generatedLabels[i].split(` ${labelDelimiter} `)
    return `${values[0]} or more`
  }
  return generatedLabels[i]
}

*/

svg.select(".legendQuant")
  .call(legend);
          
        

Log Scale Legend

          

var log = d3.scaleLog()
    .domain([ 0.1, 100, 1000 ])
    .range(["rgb(46, 73, 123)", "rgb(71, 187, 94)"]);

var svg = d3.select("svg");

svg.append("g")
  .attr("class", "legendLog")
  .attr("transform", "translate(20,20)");

var logLegend = d3.legendColor()
    .cells([0.1, 5, 10, 50, 100, 500, 1000])
    .scale(log);

svg.select(".legendLog")
  .call(logLegend);

          
        

Linear Scale Legend - Horizontal

          

var linear = d3.scaleLinear()
  .domain([0,10])
  .range(["rgb(46, 73, 123)", "rgb(71, 187, 94)"]);

var svg = d3.select("svg");

svg.append("g")
  .attr("class", "legendLinear")
  .attr("transform", "translate(20,20)");

var legendLinear = d3.legendColor()
  .shapeWidth(30)
  .orient('horizontal')
  .scale(linear);

svg.select(".legendLinear")
  .call(legendLinear);
          
        

Linear Scale Legend - 10 cells

          

var linear = d3.scaleLinear()
  .domain([0,10])
  .range(["rgb(46, 73, 123)", "rgb(71, 187, 94)"]);

var svg = d3.select("svg");

svg.append("g")
  .attr("class", "legendLinear")
  .attr("transform", "translate(20,20)");

var legendLinear = d3.legendColor()
  .shapeWidth(30)
  .cells(10)
  .orient('horizontal')
  .scale(linear);

svg.select(".legendLinear")
  .call(legendLinear);
          
        

Linear Scale Legend - Custom cells

          

var linear = d3.scaleLinear()
  .domain([0,10])
  .range(["rgb(46, 73, 123)", "rgb(71, 187, 94)"]);

var svg = d3.select("svg");

svg.append("g")
  .attr("class", "legendLinear")
  .attr("transform", "translate(20,20)");

var legendLinear = d3.legendColor()
  .shapeWidth(30)
  .cells([1, 2, 3, 6, 8])
  .orient('horizontal')
  .scale(linear);

svg.select(".legendLinear")
  .call(legendLinear);
          
        

Sequential Scale Legend

          

var sequentialScale = d3.scaleSequential(d3.interpolateRainbow)
  .domain([0,10]);

var svg = d3.select("svg");

svg.append("g")
  .attr("class", "legendSequential")
  .attr("transform", "translate(20,20)");

var legendSequential = d3.legendColor()
    .shapeWidth(30)
    .cells(10)
    .orient("horizontal")
    .scale(sequentialScale) 

svg.select(".legendSequential")
  .call(legendSequential);
          
        

Ordinal Scale Legend - Custom shape

          

var ordinal = d3.scaleOrdinal()
  .domain(["a", "b", "c", "d", "e"])
  .range([ "rgb(153, 107, 195)", "rgb(56, 106, 197)", "rgb(93, 199, 76)", "rgb(223, 199, 31)", "rgb(234, 118, 47)"]);

var svg = d3.select("svg");

svg.append("g")
  .attr("class", "legendOrdinal")
  .attr("transform", "translate(20,20)");

var legendOrdinal = d3.legendColor()
  //d3 symbol creates a path-string, for example
  //"M0,-8.059274488676564L9.306048591020996,
  //8.059274488676564 -9.306048591020996,8.059274488676564Z"
  .shape("path", d3.symbol().type(d3.symbolTriangle).size(150)())
  .shapePadding(10)
  //use cellFilter to hide the "e" cell
  .cellFilter(function(d){ return d.label !== "e" })
  .scale(ordinal);

svg.select(".legendOrdinal")
  .call(legendOrdinal);
          
        

Size

Documentation

Examples

Linear Scale Legend - Circles

         

var linearSize = d3.scaleLinear().domain([0,10]).range([10, 30]);

var svg = d3.select("svg");

svg.append("g")
  .attr("class", "legendSize")
  .attr("transform", "translate(20, 40)");

var legendSize = d3.legendSize()
  .scale(linearSize)
  .shape('circle')
  .shapePadding(15)
  .labelOffset(20)
  .orient('horizontal');

svg.select(".legendSize")
  .call(legendSize);
         
       

Linear Scale Legend - Lines

         

var lineSize = d3.scaleLinear().domain([0,10]).range([2, 10]);

var svg = d3.select("svg");

svg.append("g")
  .attr("class", "legendSizeLine")
  .attr("transform", "translate(0, 20)");

var legendSizeLine = d3.legendSize()
      .scale(lineSize)
      .shape("line")
      .orient("horizontal")
      //otherwise labels would have displayed:
      // 0, 2.5, 5, 10
      .labels(["tiny testing at the beginning",
        "small", "medium", "large", "grand, 
        all the way long label"])
      .labelWrap(30)
      .shapeWidth(40)
      .labelAlign("start")
      .shapePadding(10);

svg.select(".legendSizeLine")
  .call(legendSizeLine);
         
       

Symbol

Documentation

Examples

Ordinal Scale Legend - Custom symbols

         

var triangleU = d3.symbol().type(d3.symbolTriangle)(),
  circle = d3.symbol().type(d3.symbolCircle)(),
  cross = d3.symbol().type(d3.symbolCross)(),
  diamond = d3.symbol().type(d3.symbolDiamond)(),
  star = d3.symbol().type(d3.symbolStar)();

//example output of d3.svg.symbol().type('circle')();
//"M0,4.51351666838205A4.51351666838205,4.51351666838205 0 1,1 0,
//-4.51351666838205A4.51351666838205,4.51351666838205 0 1,1 0,4.51351666838205Z"

var symbolScale =  d3.scaleOrdinal()
  .domain(['a longer label','b','c', 'd', 'e'])
  .range([ triangleU, circle, cross, diamond, start] );

var svg = d3.select("svg");

svg.append("g")
  .attr("class", "legendSymbol")
  .attr("transform", "translate(20, 20)");

var legendPath = d3.legendSymbol()
  .scale(symbolScale)
  .orient("horizontal")
  .labelWrap(30)
  .title("Symbol Legend Title")
  .on("cellclick", function(d){alert("clicked " + d);});

svg.select(".legendSymbol")
  .call(legendPath);
         
       

Helpers

Documentation

Summary of Functions

Function Color Size Symbol
scale
cells
cellFilter
orient
ascending
shape
shapeWidth
shapeHeight
shapeRadius
shapePadding
useClass
classPrefix
title
titleWidth
labels
labelAlign
labelFormat
locale
labelOffset
labelDelimiter
labelWrap
on

NOTES

Huge thanks to Elijah Meeks for discussing ideas and encouraging me to complete this project.

The styling and layout of this page is made with another project of mine, minimal-ui.

The fonts on this page are provided by Google Fonts, and created by Julieta Ulanovsky and David Perry.

Using Prism for syntax highlighting.

And of course, thanks d3.js for creating such a lovely project and Mike Bostock for providing examples on how to make your own components.