Skip to content

Commit e69a7ee

Browse files
committed
New dataset of water level monitoring stations covering Trafford and environs. The CSV dataset is in a tidy and technical format whereas the data in the GeoJSON dataset is in a more presentational style suitable for viewing within mapping applications such as our Explore app.
1 parent 4e975da commit e69a7ee

4 files changed

Lines changed: 235 additions & 0 deletions

File tree

water_level_monitoring/README.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<table>
2+
<tr>
3+
<td>Dataset name</td>
4+
<td>Water level monitoring stations</td>
5+
</tr>
6+
<tr>
7+
<td>Dataset description</td>
8+
<td>Location and related information of river/water level monitoring stations in Trafford and the surrounding areas, including typical water level range, and historic low/high levels where available. Obtained via API <a href="https://environment.data.gov.uk/flood-monitoring/doc/reference">https://environment.data.gov.uk/flood-monitoring/doc/reference</a></td>
9+
</tr>
10+
<tr>
11+
<td>Source</td>
12+
<td>Environment Agency</td>
13+
</tr>
14+
<tr>
15+
<td>Publisher</td>
16+
<td>Environment Agency</td>
17+
</tr>
18+
<tr>
19+
<td>Publisher URL</td>
20+
<td><a href="https://environment.data.gov.uk/dataset/ae80cf81-f3aa-4703-88e7-41fbe80c67b2">https://environment.data.gov.uk/dataset/ae80cf81-f3aa-4703-88e7-41fbe80c67b2</a></td>
21+
</tr>
22+
<tr>
23+
<td>Geography</td>
24+
<td>Local Authority</td>
25+
</tr>
26+
<tr>
27+
<td>Geographic coverage</td>
28+
<td>Trafford and environs</td>
29+
</tr>
30+
<tr>
31+
<td>Temporal coverage</td>
32+
<td>2025-01-31</td>
33+
</tr>
34+
<tr>
35+
<td>Update frequency</td>
36+
<td>Real-time/near-real-time</td>
37+
</tr>
38+
<tr>
39+
<td>Licence</td>
40+
<td><a href="http://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/">Open Government Licence</a></td>
41+
</tr>
42+
<tr>
43+
<td>Attribution</td>
44+
<td>© Environment Agency copyright and/or database right 2025. All rights reserved.</td>
45+
</tr>
46+
<tr>
47+
<td>Format</td>
48+
<td>CSV, GeoJSON</td>
49+
</tr>
50+
<tr>
51+
<td>Openness rating</td>
52+
<td>&#9733&#9733&#9733&#9734&#9734&nbsp; Structured data in open format (e.g. CSV)</td>
53+
</tr>
54+
<tr>
55+
<td>Last updated</td>
56+
<td>2025-01-31</td>
57+
</tr>
58+
<tr>
59+
<td>Notes</td>
60+
<td>Typical water level, historic low/high information is not available for all monitoring stations. However, a URL is provided within the GeoJSON dataset to view the latest available water level readings for each station.</td>
61+
</tr>
62+
<tr>
63+
<td>Lab visualisation</td>
64+
<td>View data within the Lab's <a href="https://www.trafforddatalab.io/maps/explore/index.html?dataset=water_level_monitoring">Explore application</a>.</td>
65+
</tr>
66+
</table>
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
# River/water level data from monitoring stations
2+
# Source: DEFRA, published by Environment Agency
3+
# URL: https://environment.data.gov.uk/dataset/ae80cf81-f3aa-4703-88e7-41fbe80c67b2
4+
# API: https://environment.data.gov.uk/flood-monitoring/doc/reference
5+
6+
# Example API calls:
7+
# - All stations recording water levels within 9km of the centre of Trafford: https://environment.data.gov.uk/flood-monitoring/id/stations?lat=53.41671&long=-2.36572&dist=9&parameter=level
8+
# - Get the data from a specific station (which includes historic highs, lows etc.: https://environment.data.gov.uk/flood-monitoring/id/stations/692727 (.json)
9+
# - Get the latest reading from a specific station: https://environment.data.gov.uk/flood-monitoring/id/measures/692727-level-stage-i-15_min-m/readings?latest
10+
# - Get the latest 7 days worth of data from a specific station: https://environment.data.gov.uk/flood-monitoring/id/stations/692727/readings?_sorted&_limit=672
11+
# NOTE: 692727 is Flixton Bridge. Readings are taken every 15 minutes, so 4 readings per hour for 7 days = 672 stated as the _limit parameter
12+
13+
14+
# Load libraries ---------------------------
15+
library(tidyverse) ; library(sf) ; library(httr) ; library(jsonlite) ; library(lubridate)
16+
17+
18+
# Monitoring stations covering the Trafford area and environs ---------------------------
19+
# Call the API and attempt to get all stations recording water levels within 9km of the centre of Trafford
20+
api_response <- GET(
21+
url = 'https://environment.data.gov.uk/flood-monitoring/id/stations?lat=53.41671&long=-2.36572&dist=9&parameter=level',
22+
timeout(50)
23+
)
24+
25+
# After examining the API response, pull out the data we're interested in ("items") into a tibble
26+
monitoring_stations_raw <- fromJSON(content(api_response, as = "text"), flatten = TRUE) %>%
27+
pluck("items") %>%
28+
as_tibble()
29+
30+
# Tidy up the variables
31+
monitoring_stations <- monitoring_stations_raw %>%
32+
rename(lon = long,
33+
station_name = label,
34+
station_reference = stationReference,
35+
river_name = riverName,
36+
catchment_name = catchmentName) %>%
37+
mutate(station_reference = as.numeric(station_reference)) %>%
38+
select(station_name, station_reference, river_name, catchment_name, town, lon, lat)
39+
40+
41+
# Historic data from the chosen monitoring stations ---------------------------
42+
# Call the API again based on all the monitoring station IDs we've obtained and retrieve the record highs, lows and typical range
43+
44+
# Function to use within purrr:map_df() to iterate through the monitoring station IDs
45+
getHistoricData <- function(.station_ref) {
46+
api_response <- GET(
47+
url = paste0("https://environment.data.gov.uk/flood-monitoring/id/stations/", .station_ref, "/stageScale"),
48+
timeout(50)
49+
)
50+
51+
if (api_response$status_code == 200) {
52+
# Get the node containing the data of interest from the API response - we will then successively pull what we need from this
53+
historic_levels_raw <- fromJSON(content(api_response, as = "text"), flatten = TRUE) %>%
54+
pluck("items")
55+
56+
# Typical range low and high values
57+
df_tmp <- historic_levels_raw %>%
58+
as_tibble() %>% # turn list into a tibble so we can work with the data like a dataframe
59+
rename(typical_range_low = typicalRangeLow,
60+
typical_range_high = typicalRangeHigh) %>%
61+
mutate(station_reference = .station_ref) %>%
62+
select(station_reference, typical_range_low, typical_range_high) %>%
63+
head(1) # due to the "items" list containing 3 sub lists (recentHigh, highOnRecord, minOnRecord), the dataframe/tibble contains 3 identical rows, so here we just pick the first row
64+
65+
# Lowest level on record
66+
df_tmp <- df_tmp %>%
67+
left_join(
68+
historic_levels_raw %>%
69+
pluck("minOnRecord") %>%
70+
as_tibble() %>% # turn list into a tibble so we can work with the data like a dataframe
71+
rename(record_low_date = dateTime,
72+
record_low = value) %>%
73+
mutate(station_reference = .station_ref,
74+
record_low_date = as.character(date(record_low_date))) %>%
75+
select(station_reference, record_low, record_low_date)
76+
)
77+
78+
# Highest level on record
79+
df_tmp <- df_tmp %>%
80+
left_join(
81+
historic_levels_raw %>%
82+
pluck("maxOnRecord") %>%
83+
as_tibble() %>% # turn list into a tibble so we can work with the data like a dataframe
84+
rename(record_high_date = dateTime,
85+
record_high = value) %>%
86+
mutate(station_reference = .station_ref,
87+
record_high_date = as.character(date(record_high_date))) %>%
88+
select(station_reference, record_high, record_high_date)
89+
)
90+
}
91+
else {
92+
df_tmp <- tibble(station_reference = .station_ref)
93+
}
94+
95+
return(df_tmp)
96+
}
97+
98+
# Call the GetHistoricData function passing in every `station_reference` from the dataframe monitoring_stations and then join the returned data to it
99+
monitoring_stations <- monitoring_stations %>%
100+
left_join(map_df(monitoring_stations$station_reference, getHistoricData)) %>%
101+
mutate(measure = "Water level",
102+
unit = "Metres",
103+
across(ends_with(c("_low", "_high")), round, 2)) %>% # Convert all water levels to 2 decimal places
104+
select(station_name, station_reference, lon, lat, river_name, catchment_name, town, measure, unit, typical_range_low, typical_range_high, record_low, record_high, record_low_date, record_high_date)
105+
106+
107+
# write data ---------------------------
108+
file.remove("water_level_monitoring_stations_trafford_and_environs.geojson") # first remove the previous file
109+
110+
monitoring_stations %>%
111+
write_csv("water_level_monitoring_stations_trafford_and_environs.csv") %>% # write out the CSV as-is from above, then make changes for the GeoJSON output below to make it more presentable
112+
mutate(measure = "Water level in metres (m)",
113+
typical_range = if_else(is.na(typical_range_low), "Not available", paste0(typical_range_low, "m - ", typical_range_high, "m")),
114+
record_low = if_else(is.na(record_low), "Not available", paste0(record_low, "m (", record_low_date, ")")),
115+
record_high = if_else(is.na(record_high), "Not available", paste0(record_high, "m (", record_high_date, ")")),
116+
latest_levels_url = paste0("https://environment.data.gov.uk/flood-monitoring/id/measures/", station_reference, "-level-stage-i-15_min-m/readings.html?__htmlView=table&_sorted")) %>%
117+
mutate(across(c(river_name, catchment_name, town), ~replace_na(., "Not available"))) %>%
118+
st_as_sf(coords = c("lon", "lat")) %>%
119+
st_set_crs(4326) %>%
120+
select(station_name, station_reference, river_name, catchment_name, town, measure, typical_range, record_low, record_high, latest_levels_url) %>%
121+
st_write("water_level_monitoring_stations_trafford_and_environs.geojson", driver = "GeoJSON")
122+
123+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
station_name,station_reference,lon,lat,river_name,catchment_name,town,measure,unit,typical_range_low,typical_range_high,record_low,record_high,record_low_date,record_high_date
2+
Northern Moor,693115,-2.294665,53.407591,Baguley Brook,Upper Mersey,Northern Moor,Water level,Metres,0.1,1.22,0.06,1.45,2010-07-10,2019-07-31
3+
Bollington Mill,693515,-2.406589,53.380045,River Bollin,Upper Mersey,Little Bollington,Water level,Metres,0.26,1,0.2,1.49,2010-07-05,2019-08-01
4+
Ashton Weir,692726,-2.344072,53.438308,River Mersey,Upper Mersey,Urmston,Water level,Metres,0.29,4.15,0.2,3.91,1984-08-26,2021-01-21
5+
Flixton Bridge,692727,-2.388645,53.439969,River Mersey,Upper Mersey,Flixton,Water level,Metres,0.23,4.3,0.17,4.92,2010-07-12,2002-02-20
6+
Chestnut Road,690350,-2.375559,53.494067,Worsley Brook,Northern Manchester,Alder Forest,Water level,Metres,0.07,1.79,0.06,1.96,2011-01-27,2019-07-31
7+
Stanneylands,693333,-2.232417,53.343712,Dean,Upper Mersey,Styal,Water level,Metres,0.07,0.51,0.02,1.72,1996-07-21,2019-07-31
8+
Northenden,692710,-2.252674,53.408784,River Mersey,Upper Mersey,Northenden,Water level,Metres,0.27,1.8,0.15,3.32,2005-09-05,2022-02-21
9+
Little Woolden Hall,693032,-2.475817,53.440813,Glaze Brook,Lower Mersey,Glazebrook,Water level,Metres,0.38,1.9,0.24,3.58,1996-05-12,2021-01-21
10+
Adelphi Weir,690511,-2.26639,53.485246,River Irwell,Northern Manchester,Salford,Water level,Metres,0.18,2,0.12,3.86,1976-09-08,2015-12-26
11+
Partington,693132,-2.413046,53.410314,Sinderland Brook,Upper Mersey,Partington,Water level,Metres,0.12,0.8,0.06,1.42,1982-06-17,1981-08-06
12+
Athol Road,692810,-2.246761,53.439852,NA,NA,NA,Water level,Metres,NA,NA,NA,NA,NA,NA
13+
Sale Ees,692717,-2.288164,53.429377,NA,NA,NA,Water level,Metres,NA,NA,NA,NA,NA,NA
14+
Mauldeth Road,692800,-2.255783,53.438035,NA,NA,NA,Water level,Metres,NA,NA,NA,NA,NA,NA
15+
Bedford FW,693023,-2.501157,53.496087,NA,NA,NA,Water level,Metres,NA,NA,NA,NA,NA,NA
16+
Didsbury River,692706,-2.235618,53.40126,River Mersey,Upper Mersey,Didsbury,Water level,Metres,3.2,6.2,2.52,7.23,2020-05-20,2022-02-20
17+
Sale Waterpark,692722,-2.297206,53.431153,NA,NA,NA,Water level,Metres,NA,NA,NA,NA,NA,NA
18+
Didsbury Basin Stenner Lane,692707,-2.233923,53.410225,NA,NA,NA,Water level,Metres,NA,NA,NA,NA,NA,NA
19+
Jennets Lane PS,693015,-2.49657,53.478947,NA,NA,NA,Water level,Metres,NA,NA,NA,NA,NA,NA
20+
Didsbury,692705,-2.23534,53.402528,NA,NA,NA,Water level,Metres,NA,NA,NA,NA,NA,NA

0 commit comments

Comments
 (0)