d3.csv('training-mileage.csv', function(mileage) { var group = fc.group() .orient('horizontal') .key('week'); var groupedMileage = group(mileage); var colourDomain = groupedMileage[0].map(function(d) { return d[0]; }); var color = d3.scaleOrdinal(d3.schemeCategory10) .domain(colourDomain); var point = fc.seriesSvgPoint() .size(20) .crossValue(function(d, i) { return i + 1; }) .mainValue(function(d, i) { return d[1]; }); var line = fc.seriesSvgLine() .crossValue(function(d, i) { return i + 1; }) .mainValue(function(d, i) { return d[1]; }); var pointLineSeries = fc.seriesSvgMulti() .series([point, line]); var multiLine = fc.seriesSvgRepeat() .series(pointLineSeries) .decorate(function(sel) { sel.attr('stroke', function(_, i) { return color(colourDomain[i]); }) .attr('fill', function(_, i) { return color(colourDomain[i]); }) }); var gridline = fc.annotationSvgGridline() .yTicks(5); var multi = fc.seriesSvgMulti() .series([multiLine, gridline]); var yExtent = fc.extentLinear() .include([0]) .pad([0, 0.1]) .accessors([function(d) { return d.map(function(j) { return j[1]; }); }]); var legend = d3.legendColor() .shapeWidth(30) .orient('vertical') .scale(color); var extent = yExtent(groupedMileage); var chart = fc.chartSvgCartesian( d3.scaleLinear(), d3.scaleLinear() ) .xDomain([0.5, mileage.length + 0.5]) .yDomain(yExtent(groupedMileage)) .yOrient('left') .yTicks(5) .yLabel('miles') .xLabel('week') .yNice() .chartLabel('Weekly marathon training mileage') .plotArea(multi) .decorate(function(selection, data, index) { // append an svg for the d3-legend selection.enter() .append('svg') .attr('class', 'legend'); // render the legend selection.select('svg.legend') .call(legend); }); d3.select('#chart') .datum(groupedMileage) .call(chart); });