The winning times for the Women's Eights Head of the River Race (1993 to 2017).
Last active
January 13, 2020 03:46
-
-
Save johnwalley/8cf264cb5eb7f2277a4b5103d2ede851 to your computer and use it in GitHub Desktop.
WEHoRR Winning Times
This file contains hidden or 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
license: mit |
We can make this file beautiful and searchable if this error is corrected: It looks like row 3 should actually have 4 columns, instead of 6 in line 2.
This file contains hidden or 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
year,time,flow,crew | |
2017,18:31.1,,Leander Club | |
2016,19:17.7,74.8,Leander RC, Reading RC, Tees RC | |
2015,18:58.6,62.47,Army BC, Imperial College BC, London RC, Marlow RC, Minerva-Bath RC, Oxford Brookes University | |
2014,17:42.21,137.9,Army RC/Gloucester RC/Imperial College BC/London RC/ Minerva-Bath RC/Oxford Brookes University BC/Tees RC | |
2013,18:16.57,177.7,Imperial College BC A | |
2012,20:10.92,16.8,Thames RC A | |
2011,18:06.57,47,Leander Club | |
2010,18:10.67,87.4,Gloucester / Imperial College / Marlow / Reading University / Thames / UL | |
2009,18:28.27,104,London / Hollandia / Thames / Marlow / UL | |
2008,19:32.81,54,Osiris BC A | |
2007,18:14.9,122,Marlow / Rebecca / Tideway Scullers / Thames | |
2006,19:13.61,72.3,Birmhm U/Mlw/Read U/Rebc/Thames/TSS | |
2005,19:20.83,41.1,Leander Club | |
2004,18:18.79,44.3,IC/MARLO/READING UNI/ROB ROY/THA/TSS | |
2003,19:36.58,87.7,IC/KINGST/MARLW/OXF BR/THAMES | |
2001,19:22.28,132,THAMES RC A | |
2000,18:06.4,180,MARLOW/NCRA/QT/SHEFF/THAMES | |
1999,18:33.88,75.8,MARLOW RC A | |
1998,18:28.31,123,MARLOW A | |
1997,18:52.90,35.9,THAMES RC A | |
1996,18:24.52,51,KINGSTON/THAMES/TIDEWAY SCULLERS | |
1995,18:14.6,120,KINGSTON/THAMES/TSS | |
1993,19:03.7,,TIDEWAY SCULLERS SCHOOL 'A' |
This file contains hidden or 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"> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<title>WEHoRR winning times</title> | |
<style> | |
html { | |
height: 100%; | |
} | |
body { | |
height: 100vh; | |
margin: 0px; | |
display: flex; | |
font-family: sans-serif; | |
background-color: #f0ece9; | |
flex-direction: column; | |
overflow: hidden; | |
} | |
#header { | |
background-color: #f5f3f2; | |
padding-left: 22px; | |
padding-top: 12px; | |
border-bottom: 1px solid white; | |
} | |
#header #headline { | |
display: flex; | |
flex-direction: row; | |
justify-content: space-between; | |
} | |
#header h1 { | |
font-family: Helvetica, sans-serif; | |
font-size: 20px; | |
color: #635f5d; | |
margin-top: 0px; | |
margin-bottom: 5px; | |
} | |
#header p { | |
font-family: Georgia, serif; | |
font-size: 14px; | |
font-style: italic; | |
color: #8e8883; | |
margin-top: 5px; | |
margin-bottom: 5px; | |
} | |
#footer { | |
height: 22px; | |
line-height: 22px; | |
font-family: Georgia, serif; | |
font-size: 12px; | |
color: #625e5b; | |
background-color: #e6e2df; | |
padding-left: 22px; | |
border-top: 1px dashed #cdcdc9; | |
} | |
#footer span { | |
display: inline-block; | |
vertical-align: middle; | |
} | |
div#chart { | |
flex: 1; | |
} | |
.title { | |
font-family: Helvetica, sans-serif; | |
font-size: 30px; | |
fill: #625e5b; | |
} | |
svg text { | |
fill: #635f5d; | |
} | |
.axis--x { | |
font-size: 2vw; | |
} | |
.axis--x .domain { | |
display: none; | |
} | |
.axis--x .tick line { | |
stroke: white; | |
} | |
.label { | |
font-size: 2vw; | |
} | |
.axis--yLeft { | |
font-size: 2vw; | |
} | |
.axis--yLeft .domain { | |
display: none; | |
} | |
.axis--yLeft .tick line { | |
stroke: white; | |
} | |
.axis--yRight { | |
font-size: 2vw; | |
} | |
.axis--yRight .domain { | |
display: none; | |
} | |
.axis--yRight.tick line { | |
stroke: white; | |
} | |
#tooltip { | |
position: absolute; | |
pointer-events: none; | |
padding: 6px; | |
background-color: white; | |
border: 1px solid black; | |
border-radius: 4px; | |
box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.4); | |
} | |
#tooltip.hidden { | |
display: none; | |
} | |
@media screen and (max-width: 500px) { | |
.axis--x { | |
font-size: 10px; | |
} | |
.axis--yLeft { | |
font-size: 10px; | |
} | |
.axis--yRight { | |
font-size: 10px; | |
} | |
.label { | |
font-size: 10px; | |
} | |
} | |
@media screen and (min-width: 800px) { | |
.axis--x { | |
font-size: 16px; | |
} | |
.axis--yLeft { | |
font-size: 16px; | |
} | |
.axis--yRight { | |
font-size: 16px; | |
} | |
.label { | |
font-size: 16px; | |
} | |
} | |
</style> | |
<div id="header"> | |
<div id="headline"> | |
<h1>WEHoRR winning times</h1> | |
</div> | |
<p>The winning times for the Women's Eights Head of the River Race (1993 to 2017)</p> | |
</div> | |
<div id="chart"></div> | |
<div id="footer"> | |
<span> | |
<strong>Sources</strong>: | |
<i>http://wehorr.org/results/ http://nrfa.ceh.ac.uk/</i> | |
</span> | |
</div> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<script src="https://unpkg.com/[email protected]/dist/regression.js"></script> | |
<script src="https://unpkg.com/[email protected]/dist/tippy.all.min.js"></script> | |
<script> | |
d3.csv("data.csv", function (d) { | |
d.year = +d.year; | |
d.timeStr = d.time; | |
var time = d3.timeParse("%M:%S.%L")(d.time); | |
d.time = 60 * time.getMinutes() + time.getSeconds(); | |
d.flow = +d.flow; | |
return d; | |
}, function (error, data) { | |
if (error) throw error; | |
var barChart = chart(); | |
var change = function (isResize) { | |
var selection = d3.select("#chart"); | |
selection.datum(data).call(barChart, isResize); | |
} | |
window.onresize = function () { | |
change(true); | |
} | |
change(false); | |
tippy('.point'); | |
tippy('.bar', { placement: 'bottom' }); | |
}); | |
var chart = function () { | |
var svg = null; | |
var width; | |
var height; | |
var chartWidth; | |
var chartHeight; | |
var x; | |
var xBar; | |
var yLeft; | |
var yRight; | |
function chart(selection, isResize) { | |
selection.each(function (data) { | |
var result = regression.linear(data.map(function (d) { return [d.year, d.time]; })); | |
var gradient = result.equation[0]; | |
var yIntercept = result.equation[1]; | |
var duration = isResize ? 0 : 1000; | |
width = selection.node().getBoundingClientRect().width; | |
height = selection.node().getBoundingClientRect().height; | |
var ratio = (width - 500) / (800 - 500); | |
var clampedRatio = Math.max(0, Math.min(1, ratio)); | |
var marginBottom = 48 + 48 * clampedRatio; | |
var marginLeft = 64 + 24 * clampedRatio; | |
var marginRight = 64 + 24 * clampedRatio; | |
var margin = { | |
top: 22, | |
right: marginRight, | |
bottom: marginBottom, | |
left: marginLeft | |
}; | |
chartWidth = width - margin.left - margin.right; | |
chartHeight = height - margin.top - margin.bottom; | |
if (!svg) { | |
svg = selection.append("svg") | |
.style("vertical-align", "bottom"); // <-- Makes all the difference | |
var g = svg.append("g"); | |
g.append("g") | |
.attr("class", "axis axis--x"); | |
g.append("g") | |
.attr("class", "axis axis--yLeft"); | |
g.append("g") | |
.attr("class", "axis axis--yRight"); | |
svg.append("text") | |
.attr("class", "label left") | |
.attr("transform", "rotate(-90)") | |
.attr("dy", "1.1em") | |
.attr("text-anchor", "middle") | |
.text("Winning time (minutes)"); | |
svg.append("text") | |
.attr("class", "label right") | |
.attr("transform", "rotate(-90)") | |
.attr("dy", "1.1em") | |
.attr("text-anchor", "middle") | |
.text("Mean daily flow (m³/s)"); | |
} | |
svg.attr("height", "100%") | |
.attr("width", width); | |
var g = svg.select("g") | |
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
g.append("g") | |
.attr("class", "bars"); | |
g.append("g") | |
.attr("class", "points"); | |
svg.select(".title") | |
.attr("x", width - margin.right); | |
svg.select(".label.left") | |
.attr("x", -chartHeight / 2) | |
.attr("y", 8); | |
svg.select(".label.right") | |
.attr("x", -chartHeight / 2) | |
.attr("y", chartWidth + marginLeft + 48); | |
x = d3.scaleLinear().range([0, chartWidth]).nice(); | |
xBar = d3.scaleBand().padding(0.5).range([chartWidth, 0.0]); | |
yLeft | |
= d3.scaleLinear().rangeRound([chartHeight, 0]); | |
yRight | |
= d3.scaleLinear().rangeRound([0, chartHeight]); | |
x.domain(d3.extent(data.map(function (d) { return d.year; }))).nice(); | |
xBar.domain(data.map(function (d) { return d.year; })); | |
yLeft | |
.domain([d3.min(data, function (d) { return d.time - 10; }), d3.max(data, function (d) { return d.time; })]).nice(); | |
yRight | |
.domain([0, d3.max(data, function (d) { return d.flow; })]).nice(); | |
var t = d3.transition() | |
.duration(duration); | |
var xAxis = svg.select(".axis--x") | |
.attr("transform", "translate(0," + chartHeight + ")"); | |
xAxis.call(d3.axisBottom(x).tickSize(-chartHeight).tickFormat(d3.format("d"))) | |
.selectAll("text") | |
.attr("y", 0); | |
xAxis.selectAll("text") | |
.attr("y", 0) | |
.attr("x", -20) | |
.attr("dy", ".35em") | |
.attr("transform", "rotate(-90)") | |
.style("text-anchor", "end"); | |
svg.select(".axis--yLeft") | |
.call(d3.axisLeft(yLeft | |
).tickValues([18 * 60, 19 * 60, 20 * 60]).tickSize(-chartWidth).tickFormat(function (d) { | |
return d3.format("2d")(Math.floor(d / 60)) + ":" + d3.format("02d")(d % 60); | |
})); | |
svg.select(".axis--yRight") | |
.attr("transform", "translate(" + chartWidth + ",0)") | |
.call(d3.axisRight(yRight).tickSize(0)); | |
var bars = svg.select(".bars") | |
.selectAll(".bar") | |
.data(data, function (d) { return d.year; }) | |
.attr("x", function (d) { return x(d.year) - xBar.bandwidth() / 2; }) | |
.attr("y", function (d) { return yRight(0); }) | |
.attr("width", xBar.bandwidth()) | |
.attr("height", function (d) { return yRight(d.flow); }); | |
bars.enter() | |
.append("rect") | |
.attr("class", "bar") | |
.attr("x", function (d) { return x(d.year) - xBar.bandwidth() / 2; }) | |
.attr("y", function (d) { return yRight(0); }) | |
.attr("width", xBar.bandwidth()) | |
.attr("height", function (d) { return 0; }) | |
.attr("opacity", 0) | |
.attr("fill", "#E6842A") | |
.style("cursor", "pointer") | |
.on("mouseover", function (d) { | |
d3.select(this).attr("fill", "#F6B656"); | |
}) | |
.on("mouseout", function (d) { | |
d3.select(this).attr("fill", "#E6842A"); | |
}) | |
.attr("title", function (d) { return `<strong>${d.year}</strong><br />Time: ${d.timeStr}<br />Flow: ${d.flow} m<sup>3</sup>/s<br />${d.crew}`; }) | |
.merge(bars) | |
.transition(t) | |
.attr("opacity", 1) | |
.transition(t) | |
.attr("height", function (d) { return yRight(d.flow); }); | |
bars.exit() | |
.transition(t) | |
.attr("opacity", 0) | |
.remove(); | |
var points = svg.select(".points") | |
.selectAll(".point") | |
.data(data, function (d) { return d.year; }) | |
.attr("r", chartWidth / 100) | |
.attr("cx", function (d) { return x(d.year); }) | |
.attr("cy", function (d) { | |
return yLeft | |
(d.time); | |
}); | |
points.enter() | |
.append("circle") | |
.attr("class", "point") | |
.attr("opacity", 0) | |
.attr("cx", function (d) { return x(d.year); }) | |
.attr("cy", function (d) { | |
return yLeft | |
(gradient * d.year + yIntercept); | |
}) | |
.attr("r", chartWidth / 100) | |
.attr("fill", function (d) { return "#137B80"; }) | |
.attr("title", function (d) { return `<strong>${d.year}</strong><br />Time: ${d.timeStr}<br />Flow: ${d.flow} m<sup>3</sup>/s<br />${d.crew}`; }) | |
.style("cursor", "pointer") | |
.on("mouseover", function (d) { | |
d3.select(this).attr("fill", "#42A5B3"); | |
}) | |
.on("mouseout", function (d) { | |
d3.select(this).attr("fill", "#137B80"); | |
}) | |
.merge(points) | |
.transition(t) | |
.attr("opacity", 1) | |
.transition(t) | |
.attr("cx", function (d) { return x(d.year); }) | |
.attr("cy", function (d) { | |
return yLeft | |
(d.time); | |
}); | |
points.exit() | |
.transition(t) | |
.attr("cy", function (d) { | |
return yLeft | |
(0); | |
}) | |
.attr("opacity", 0) | |
.remove(); | |
var line = svg.select("g") | |
.selectAll(".line") | |
.data([{ | |
x1: x.invert(x.range()[0]), | |
y1: gradient * x.invert(x.range()[0]) + yIntercept, | |
x2: x.invert(x.range()[1]), | |
y2: gradient * x.invert(x.range()[1]) + yIntercept, | |
}]); | |
line | |
.attr("x1", function (d) { return x(d.x1); }) | |
.attr("y1", function (d) { | |
return yLeft | |
(d.y1); | |
}) | |
.attr("x2", function (d) { return x(d.x2); }) | |
.attr("y2", function (d) { | |
return yLeft | |
(d.y2); | |
}); | |
line.enter() | |
.append("line") | |
.attr("class", "line") | |
.attr("x1", function (d) { return x(d.x1); }) | |
.attr("y1", function (d) { | |
return yLeft | |
(d.y1); | |
}) | |
.attr("x2", function (d) { return x(d.x2); }) | |
.attr("y2", function (d) { | |
return yLeft | |
(d.y2); | |
}) | |
.attr("stroke", "#8E8883") | |
.attr("stroke-width", 2) | |
.attr("stroke-dasharray", "20, 20") | |
.attr("stroke-linecap", "round") | |
.attr("opacity", 0) | |
.transition(t) | |
.delay(2 * duration) | |
.attr("opacity", 1); | |
}); | |
} | |
return chart; | |
} | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment