Mark O'Hare Mark O'Hare - 7 months ago 49
Javascript Question

D3.js adding labels to a legend with dynamic colours

I'm currently producing a multi-line graph using d3.js. I'm currently looking to produce a simple legend that describes each lines Client name and its line colour by styling the font in its corresponding colour in the graph.

My test data looks something like this:

var data = [{
"Client": "ABC",
"sale": "202",
"time": "09:00"
}, {
"Client": "ABC",
"sale": "215",
"time": "11:00"
}, {
"Client": "ABC",
"sale": "179",
"time": "12:00"
}, {
"Client": "ABC",
"sale": "199",
"time": "13:00"
}, {
"Client": "ABC",
"sale": "134",
"time": "15:00"
}, {
"Client": "ABC",
"sale": "176",
"time": "16:00"
}, {
"Client": "ABC",
"sale": "197",
"time": "17:00"
}, {
"Client": "XYZ",
"sale": "100",
"time": "09:00"

...etc

}];


By using d3.nest(), I've sorted the json by its Client name which now produces the data shown below:

[{
"key": "ABC",
"values": [{
"Client": "ABC",
"sale": "202",
"year": "2000"
}, {
"Client": "ABC",
"sale": "215",
"year": "2002"
}, {
"Client": "ABC",
"sale": "179",
"year": "2004"
}, {
"Client": "ABC",
"sale": "199",
"year": "2006"
}, {
"Client": "ABC",
"sale": "134",
"year": "2008"
}, {
"Client": "ABC",
"sale": "176",
"year": "2010"
}]
}, {
"key": "XYZ",
"values": [{
"Client": "XYZ",
"sale": "100",
"year": "2000"
}, { ...etc


The new json I've produced above is called 'dataGroup'. I'm trying to use iteration to populate a div on my DOM with client names in their respective colours I've given them using d3.scale.category10();

Here is my current code for the div:

dataGroup.forEach(function(d, i){

d3.select("#value")
.append("text")
.data(dataGroup)
.style("color", function(d, i){
return colours(i);
})
.text(function(d){
return d.key;
});
});


So far, all this does is return the first Client (ABC) and then stops. To my understanding, I thought d3 would've iterated through all the keys in the dataGroup but it hasn't. I've tried putting a for loop in the text function but that hasn't helped either.

Any suggestions?

Answer

There is a problem here. D3 will iterate, if you bind the data properly. This is how you can do:

First, select the div or span you want:

var clientText = d3.select("#value");

Then, create a variable for the texts, and bind the data from dataGroup in this order:

var texts = clientText.selectAll(".clients")
  .data(dataGroup)
  .enter()
  .append("text");

We call this a "select-data-enter-append" sequence.

Then, you can do the rest of your code:

texts.style("color", function(d, i){
            return colors(i);
        })
        .text(function(d){
            return d.key;
        });

This will print all the names in sequence, not the most beatiful result.

Here is the fiddle: https://jsfiddle.net/uwLcrzxk/

Comments