var secondsPerMinute = 60; var minutesPerHour = 60; var timeFormat = function(d) { return d3.timeFormat('%H:%M')(new Date(0, 0, 0, d, (d*60)%60, 0)); } d3.text('finish.txt').then(text => { var times = d3.csvParseRows(text, d => d.map(Number)); var grouped = d3.nest() .key(d => Math.floor(d[0] / secondsPerMinute)) .entries(times) .sort((a, b) => d3.ascending(+a.key, +b.key)); var bar = fc.autoBandwidth(fc.seriesSvgBar()) .crossValue(d => (+d.key + 0.5) / minutesPerHour) .mainValue(d => d.values.length) .widthFraction(1.1); var gridlines = fc.annotationSvgGridline(); var multi = fc.seriesSvgMulti() .series([bar, gridlines]); var yExtent = fc.extentLinear() .accessors([d => d.values.length]) .pad([0, 0.1]); var chart = fc.chartCartesian( d3.scaleLinear(), d3.scaleLinear() ) .xDomain([2, 7]) .yDomain(yExtent(grouped)) .yOrient('left') .yTicks(5) .yLabel('Frequency') .xLabel('Finish time (hours)') .chartLabel('London Marathon 2016 Finish Time Distribution') .xTickFormat(timeFormat) .svgPlotArea(multi); d3.select('#chart') .datum(grouped) .call(chart); });