score:1

Accepted answer

To create a multi-line chart with d3, you need to

  1. Create a top-level data array, with one entry for each data series (i.e., for each line on the chart); and
  2. For each data series, create an array of (x,y) points containing that series' data in a standard format.

When your data is in a table format, with each series in separate column, this gets much easier if you can hard-code an array of column names representing the columns that you want to use as data series.

var seriesNames = ["GDP", "Population", "GDP per Capita", "Exports", "Industry"];

If you don't want to hard-code in all the series names, you will at least need to know the names of the column that will be used for the x values and any other columns not to include. Then you can get the names of all columns from d3.keys(data[0]), and use an array filter to get rid of the "Year" and "Country Name" values. The Mike Bostock example you linked to does this when setting the domain of the colour scale, and then grabs the array for future use from color.domain():

color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; }));

I find that confusing, and would save the array of names in a variable first, then use it to set the domain of the colour scale:

var seriesNames = d3.keys(data[0]).filter(function(key) { 
                                    return key !== "date"; 
                                     //you would have to change the name(s) to exclude
                                 });
color.domain( seriesNames );

Whether you hard-code it or create it dynamically, you can then use your array of series names to create your array of arrays:

var series = seriesNames.map(function(name) {
    return {
      name: name,
      values: data.map(function(d) {
        return {x: d.year, 
                y: +d[name] };
      })
    };
});

The array map function creates a new array where each entry is the result of passing the corresponding entry from the starting array to the mapping function. This code uses two levels of mapping: the outer function takes your series name and returns a data object, the inner function takes the original data array and extracts only the values that are relevant to this series, with a standardized name that you can then use in the rest of your code.

That should get you started, but there's one complication in your data that isn't in the example you're working from: your data series all represent completely different types of numbers, with completely different scales. I'm not sure how you were planning to handle that for graphing all these values on the same chart, but one option would be to graph percent change from the starting year. You could do that calculation in your data-mapping function:

var series = seriesNames.map(function(name) {
    var initialValue = +data[0][name];
    return {
      name: name,
      values: data.map(function(d) {
        return {year: d.year, 
                percentChange: (+d[name] / initialValue) };
      })
    };
});

Related Query

More Query from same tag