d3js Create legend for bar chart

bar-chart, d3.js, javascript, legend

Solution

You need to use `colors` rather than `dataset` as parameter for the `.data()` of your legend. In order for that to work, `colors` has to be an array rather than an object:

var colors = [ ["Local", "#377EB8"],
               ["Global", "#4DAF4A"] ];

The code for creating the legend then becomes:

var legendRect = legend.selectAll('rect').data(colors);

legendRect.enter()
    .append("rect")
    .attr("x", w - 65)
    .attr("width", 10)
    .attr("height", 10);

legendRect
    .attr("y", function(d, i) {
        return i * 20;
    })
    .style("fill", function(d) {
        return d[1];
    });

var legendText = legend.selectAll('text').data(colors);

legendText.enter()
    .append("text")
    .attr("x", w - 52);

legendText
    .attr("y", function(d, i) {
        return i * 20 + 9;
    })
    .text(function(d) {
        return d[0];
    });

Cf the updated fiddle.

Problem

I'm having a couple of issues with my bar chart. The current issue is trying to create a legend. The legend should read Global and Local (blue & green). Currently the legend generates 5 boxes - 2 of them are colored. I assume it's going through my dataset and generating boxes for each set of columns. I do not want this. After I get the legend formatted, I want to be able to have it interactive. So if they only want to see global, then they unselect local, and the chart updates dynamically. I know I'll need to adjust it and create a function to update data, domain, etc. But before beginning down that road, I want to get the legend populating properly. But I would appreciate if the legend solution would lead down this road. I have a working Fiddle you can play around with. Data Sources ``` var colors = {0: ["Local", "#377EB8"], 1: ["Global", "#4DAF4A"]}; var dataset = [ {"keyword": "payday loans", "global": 1400000, "local": 673000, "cpc": "14.11"}, {"keyword": "title loans", "global": 165000, "local": 160000, "cpc": "12.53" }, {"keyword": "personal loans", "global": 550000, "local": 301000, "cpc": "6.14"}, {"keyword": "online personal loans", "global": 15400, "local": 12900, "cpc": "5.84"}, {"keyword": "online title loans", "global": 111600, "local": 11500, "cpc": "11.74"} ]; ``` Label Code ``` var legend = svg.append("g") .attr("class", "legend") //.attr("x", w - 65) //.attr("y", 50) .attr("height", 100) .attr("width", 100) .attr('transform', 'translate(-20,50)'); legend.selectAll('rect') .data(dataset) .enter() .append("rect") .attr("x", w - 65) .attr("y", function(d, i) { return i * 20; }) .attr("width", 10) .attr("height", 10) .style("fill", function(d) { var color = colors[dataset.indexOf(d)][1]; return color; }); legend.selectAll('text') .data(dataset) .enter() .append("text") .attr("x", w - 52) .attr("y", function(d, i) { return i * 20 + 9; }) .text(function(d) { var text = colors[dataset.indexOf(d)][0]; return text; }); ``` I know my Colors array/object probably isn't the most efficient way. So I'm open to adjusting that if it helps with the solution. Also, I would prefer that it is a Horizontal list instead of vertical.

Original source