d3.csv('miles-vs-finish.csv', row => ({ miles: Number(row.miles), finish: Number(row.finish) / 3600 })) .then(data => { var histogram = d3.histogram() .value(d => d.finish) .domain([2.5, 6.5]) .thresholds(d3.range(2.5, 7, 0.5)); var average = histogram(data) .map(d => ({ miles: d3.median(d.map(j => j.miles)), finish: (d.x0 + d.x1) / 2 })); var point = fc.seriesSvgPoint() .size(30) .crossValue(d => d.miles) .mainValue(d => d.finish); var line = fc.seriesSvgLine() .crossValue(d => d.miles) .mainValue(d => d.finish); var pointLineSeries = fc.seriesSvgMulti() .series([line, point]); var scatter = fc.seriesSvgPoint() .size(10) .crossValue(d => d.miles) .mainValue(d => d.finish); var multi = fc.seriesSvgMulti() .series([scatter, pointLineSeries]) .mapping((_, index, series) => { switch(series[index]) { case scatter: return data; case pointLineSeries: return average; } }); var chart = fc.chartCartesian( d3.scaleLinear(), d3.scaleLinear() ) .xDomain([0, 70]) .yDomain([2, 7]) .yOrient('left') .yLabel('finish time (hours)') .xLabel('average weekly miles') .yNice() .chartLabel('Average weekly training mileage - vs - Finish time') .svgPlotArea(multi); d3.select('#chart') .datum(average) .call(chart); });