D3.js part 7 of 9 - Adding a legend to explain the data

Part 6 – Add labels to the map

With the labels in place let’s start working on integrating a legend to explain the colors on the map. You can visit my Github page for all the blogs and demo’s in this series.

To be able to display the legend we first need to make the data available. We need to have access to the range of colors used and the corresponding value domain of the arrest dataset. With .d3.scale.ordinal() we can create a scale with the arrestdata connected to the specific colors for each domain. The domain groups are based on the quantify function we created in the fourth blog in this series.

var color = d3.scale.ordinal()
    .domain(["1450"])
    .range(["#1a9850", "#66bd63", "#a6d96a","#d9ef8b","#ffffbf","#fee08b","#fdae61","#f46d43","#d73027"]);

The legend should be a static element in the top left of the map. To achieve this we need to add a new g element to the SVG outside of the zoomgroup element. Inside this we will create a g element for each legend item. Like before we select all g elements, load the data: the color variable domain, connect the element and the data before appending it to the SVG.g. To place each item directly below the previous one, we add a transform attribute. With an iteration through the elements the offset to the top of the SVG will be increased by the required height of each, specified in the legendRectSize variable.

var legend = d3.select('svg')
    .append("g")
    .selectAll("g")
    .data(color.domain())
    .enter()
    .append('g')
      .attr('class', 'legend')
      .attr('transform', function(d, i) {
        var height = legendRectSize;
        var x = 0;
        var y = i * height;
        return 'translate(' + x + ',' + y + ')';
    });

Inside each legend element we need to have a box to display the color and an explanatory text element. For the colored box we append a rect element with a height and width we specify in the legendRectSize variable. The fill and the stroke will be defined through the range in the color variable, that was already connected to each legend item. In the text element I would like to display each domain value. The initial place of the text element is the top left corner of the legend item element. To align the text we should move them down and to the right with the use of the legendRectSize and legendSpacing variables.

legend.append('rect')
    .attr('width', legendRectSize)
    .attr('height', legendRectSize)
    .style('fill', color)
    .style('stroke', color);

legend.append('text')
    .attr('x', legendRectSize + legendSpacing)
    .attr('y', legendRectSize - legendSpacing)
    .text(function(d) { return d; });

possible improvements
It would be nice if the function coloring the map and generating the legend would share the color variable, setting the range and the domain of the colors on the map. At this moment the functions are completely separated which means you need to change the colors at two places in the code when needed.

We now have a good indication of the amount of arrests in a province through the integration of the legend. It would be nice if we could show the exact amount in a tooltip when you hover over one of the provinces. Let’s integrate that functionality in the next post.

Part 8 – Interactive tooltips for detailed information

Share your thoughts

Leave a Reply