Inspiration
Since starting university in Oxford and living here through the rain, we've seen a lot of water pooling in streets and low-lying areas, as you saw yesterday. That made us wonder how vulnerable the city is to flooding, and whether people could get a clearer idea of where river levels were heading.
The Environment Agency (EA) publishes river gauge readings, but they're hard to read if you just want to know how likely flooding is near you, and when. FloodClock tries to answer that. It's a decision-support tool, not an official warning, and it doesn't replace the EA.
What it does
FloodClock forecasts river levels 6 to 72 hours ahead using EA river and rain gauge data. The model looks at recent levels at the target gauge, upstream levels (shifted by travel time), rain that has already fallen, and the season. It then gives the chance of passing a local flood threshold. Each gauge has its own reference point, so readings are judged against that gauge's own history rather than compared between gauges.
The app shows a map of the river network and the risk at five Oxford trouble spots, with a timeline for live readings or replays of past floods. The animations show how gauges relate, not water moving through streets. Four of the spots have forecasts, and some use a nearby stand-in gauge, which the app points out.
How we built it
- Data: EA historical river and rainfall data, live flood-monitoring readings and historic flood warnings, cleaned into hourly data with gaps tracked.
- Gauge checks: Some lock gauges only had history for the upstream side, which stays fairly flat in floods, so we switched target gauges.
- Travel times: A rise at Enslow reaches Kings Mill in about 18.6 hours on average across six past floods, though it varies.
- Model: LightGBM quantile models predict a range of levels, which we turn into a chance of crossing the threshold, tested against a "river stays where it is" baseline.
- App: React and TypeScript, runs offline from saved data, with a sandbag suggestion model using terrain data.
Challenges we ran into
The gauges we planned to use didn't have the right historical data, so we had to retarget the model. With several people and AI coding sessions working at once, shared task tracking and clear data contracts kept things from breaking. Keeping the pipeline, model, API and interface in sync took effort, and so did making uncertainty easy to read on a map. Oxford has only had a few major floods, so we had to avoid data leakage and be honest about false alarms and the times the EA warned first.
Accomplishments that we're proud of
- A working prototype for a real Oxford problem, built on public data
- Replays of past floods showing our forecasts next to observed levels and EA warnings
- In replay testing, FloodClock caught 29 of 30 threshold crossings with 6 false alarms, compared with 24 and 1 false alarm for EA Flood Warnings scored the same way. We decided a false alarm is a much better outcome than a missed flood.
- At Osney and Cherwell, our signals came on average about 24 hours before the EA's
- A sandbag suggestion model for Osney and Botley, showing where sandbags could be prioritised
- A demo that works offline
What we learned
We had to collect a lot of rain and river gauge data from different sources, then clean and combine it. That taught us to check the data before modelling, because a gauge can look useful and still measure the wrong thing. We also learned how to split work between people and AI agents. Most of all, a forecast has to show its uncertainty and beat a simple baseline, not just look good on a map.
What's next for FloodClock
We'd like to try it in other towns with connected gauges, good historical records and locally checked thresholds. We also want to bring down false alarms, test forecast rainfall as an input, and get better data for spots using stand-in gauges, checking accuracy and false alarms before relying on anything new.
Built With
- claude
- duckdb
- environment-agency-api
- fastapi
- github
- leaflet.js
- lightgbm
- numpy
- open-data
- openstreetmap
- pandas
- parquet
- postgresql
- python
- react
- scipy
- tiger-data
- timescaledb
- typescript
- uvicorn
- vite
Log in or sign up for Devpost to join the conversation.