This charts shows the weekly training mileage of strava athletes who ran the 2016 London Marathon. The data is rendered using a combination of d3 and d3fc components.
Last active
February 3, 2023 22:26
-
-
Save ColinEberhardt/2c098c4f9e93f6de827aaf827282a7e1 to your computer and use it in GitHub Desktop.
Weekly marathon training mileage
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<meta charset='utf-8'> | |
<script src="https://unpkg.com/d3@4.6.0"></script> | |
<script src="https://unpkg.com/d3fc@12.1.0"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/2.18.0/d3-legend.js"></script> | |
<style> | |
body { | |
font-family: sans-serif; | |
font-size: 1.2em; | |
} | |
.tick { | |
font-size: 1.2em; | |
} | |
.gridline-y { | |
display: none; | |
} | |
.gridline-x { | |
opacity: 0.5; | |
} | |
.legend { | |
position: absolute; | |
bottom: auto; | |
top: 50px; | |
right: 10px; | |
width: 150px; | |
height: 120px; | |
font-size: 0.8em; | |
} | |
.y-axis-label { | |
transform: rotate(-90deg) translateY(20px) !important; | |
} | |
.point { | |
fill: inherit; | |
stroke: transparent; | |
} | |
.line { | |
stroke: inherit; | |
} | |
</style> | |
<div id='chart' style='height: 400px'></div> | |
<script src="training-mileage.js"></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
week | 2 - 3 hours | 3 - 4 hours | 4 - 5 hours | 5 - 6 hours | |
---|---|---|---|---|---|
1 | 37.58857143 | 22.63053279 | 15.86790831 | 13.05769231 | |
2 | 41.21048951 | 23.61279528 | 18.4127027 | 15.47256637 | |
3 | 41.92 | 25.39609375 | 17.9571831 | 16.14122807 | |
4 | 41.42191781 | 25.33238095 | 18.49645777 | 14.77107438 | |
5 | 42.0489011 | 26.05599315 | 17.66459459 | 16.772 | |
6 | 46.67231638 | 27.82239583 | 20.04053333 | 16.58130081 | |
7 | 48.19044944 | 28.88290598 | 20.33341772 | 17.77096774 | |
8 | 49.64444444 | 29.67728814 | 21.46188119 | 18.08333333 | |
9 | 44.40748663 | 28.55257903 | 22.06059113 | 18.4728 | |
10 | 47.75654762 | 28.23784247 | 20.40025 | 14.61755725 | |
11 | 47.72601156 | 29.42739496 | 21.7739759 | 18.40378788 | |
12 | 50.48 | 30.72166667 | 24.93062201 | 19.68814815 | |
13 | 42.76358974 | 26.38578352 | 20.98762376 | 16.75952381 | |
14 | 47.30483871 | 30.17133443 | 22.27336562 | 17.66614173 | |
15 | 39.3483871 | 22.85170732 | 17.33044554 | 13.63257576 | |
16 | 24.93055556 | 15.11318865 | 10.62351421 | 8.540186916 | |
17 | 8.889005236 | 5.637198795 | 3.562150538 | 2.846060606 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment