Clarinetist
Clarinetist

Reputation: 1187

How to structure .csv file to allow D3.js to associate a line with a specified color?

I don't have a MWE for this, as it mostly deals with the preprocessing of data prior to writing D3 code.

I have a .csv file which is essentially structured as follows:

category,value,date
cat1,200000,2016-08-07
cat2,500000,2016-08-07
cat3,600000,2016-08-07
cat1,200000,2016-09-07
cat2,500000,2016-09-07
cat3,600000,2016-09-07

and so forth. The task is to draw a line graph for each one of cat1, cat2, and cat3 with the x-axis being the date and the y-axis being the value. From every example I've found, the solution appears to be that there must be one date per row:

date,cat1,cat2,cat3
2016-08-07,200000,500000,600000
2016-09-07,200000,500000,600000

which makes sense. However, let's suppose that cat1, cat2, and cat3 have required colors that must be associated with them. For example, suppose that the line for cat1 must have color #4472C4, the line for cat2 must have color #ED7D31, and the line for cat3 must have color #FFC000.

What is the best way to structure the data above to not only easily plot the lines, but to associate each line with a specified color?

If a MWE is preferred, please let me know, and I will delete this question until I have a sufficient MWE prepared.

Upvotes: 1

Views: 111

Answers (2)

Mikhail Shabrikov
Mikhail Shabrikov

Reputation: 8509

You can define your custom color scale this way:

var color = d3.scaleOrdinal()
  .domain(['cat1', 'cat2', 'cat3'])
  .range(["#4472C4", "#ED7D31" , "#FFC000"]);
  
console.log("color('cat1') ==>", color('cat1'));
console.log("color('cat2') ==>", color('cat2'));
console.log("color('cat3') ==>", color('cat3'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>

As you can see it returns the appropriate color for the category name that you pass.

Check the primitive demo how it works in action:

var dataAsCsv = `category,value,date
cat1,200000,2016-08-07
cat2,500000,2016-08-07
cat3,600000,2016-08-07
cat1,400000,2016-09-07
cat2,600000,2016-09-07
cat3,200000,2016-09-07`;

var color = d3.scaleOrdinal()
  .domain(['cat1', 'cat2', 'cat3'])
  .range(["#4472C4", "#ED7D31" , "#FFC000"]);

var data = d3.csvParse(dataAsCsv);

var margin = {top: 20, right: 20, bottom: 30, left: 50},
    width = 300 - margin.left - margin.right,
    height = 100 - margin.top - margin.bottom;
    
var parseTime = d3.timeParse("%Y-%m-%d");

data.forEach(function(d) {
    d.date = parseTime(d.date);
    d.value = +d.value;
});

var dataByCategory = d3.nest()
  .key(function(d) { return d.category; })
  .entries(data);
  
var x = d3.scaleTime().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);

x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.value; })]);
  
var valueline = d3.line()
    .x(function(d) { return x(d.date); })
    .y(function(d) { return y(d.value); });
    
var svg = d3.select("body").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform",
          "translate(" + margin.left + "," + margin.top + ")");
  
svg.selectAll('path')
  .data(dataByCategory)
  .enter()
  .append("path")
  .attr("class", "line")
  .attr("stroke", function(d){
  console.log(color(d.key))
    return color(d.key);
  })
  .attr("d", function(d) {
    return valueline(d.values);
  });
.line {
  fill: none;
  stroke-width: 2px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>

Upvotes: 1

pmkro
pmkro

Reputation: 2550

One thing you could try is to class each line by category, then use css to add colour, something like this:

d3.selectAll("path").data(csv) .enter().append("path") .attr("class", function(d){return d.category}

Alternatively, you could also add a colour scale which can be seen here.

Upvotes: 1

Related Questions