Static Data API
Overview
The irishbuoys package provides a static JSON API served via GitHub Pages. All endpoints are pre-computed by the targets pipeline and updated on a regular schedule (see Update Schedule).
Base URL: https://johngavin.github.io/irishbuoys/api/v1/
No authentication required. All responses are JSON. Data is updated regularly from the Marine Institute’s ERDDAP server.
Available Endpoints
Stations
The stations.json endpoint provides metadata for each buoy in the Irish Weather Buoy Network, including station ID, name, latitude, and longitude.
Latest Observations
The latest.json endpoint returns the most recent observation per station. A sample response (one station):
{ “_meta”: { “generated”: “2026-03-16T09:00:58Z”, “package_version”: “0.2.0”, “endpoint”: “latest”, “description”: “Most recent observation per station” }, “data”: { “n_stations”: 5, “observations”: [ { “time”: “2026-03-16T08:00:00”, “station_id”: “M5”, “call_sign”: “62094”, “longitude”: -6.7043, “latitude”: 51.6904, “atmospheric_pressure”: 1013.391, “air_temperature”: 9.824, “dew_point”: null, “wind_direction”: 246, “wind_speed”: 17.077, “gust”: 24.933, “relative_humidity”: 79.199, “sea_temperature”: 9.694, “salinity”: 25, “wave_height”: 2.813, “wave_period”: 6.328, “mean_wave_direction”: 246, “hmax”: 3.75, “tp”: 19.336, “thtp”: 261.563, “sprtp”: 50.977, “qc_flag”: 0 } ] } }
Summary Statistics
The stats.json endpoint provides per-station summary statistics including record counts, mean/max wave height, and mean/max wind speed.
Overall summary:
- Total records: 299,753
- Date range: 2018-10-16 to 2026-03-16 08:00:00
- Stations: M2
- Stations: M3
- Stations: M4
- Stations: M5
- Stations: M6
- Wind-wave correlation: 0.6092
- Wave-Hmax correlation: 0.9767
Seasonal Patterns
The seasonal.json endpoint provides monthly and seasonal (DJF/MAM/JJA/SON) mean statistics for wave height and wind speed, plus annual trend analysis with linear trend per decade and significance (p-value).
Fields: wave.monthly, wave.seasonal, wind.monthly, wind.seasonal, annual_trends.wave, annual_trends.wind
Wave data (sample)
{
"wave": {
"monthly": [
{
"month": 1,
"mean": 3.3127,
"sd": 1.8862,
"median": 3.047,
"n": 24802,
"month_name": "Jan"
},
{
"month": 2,
"mean": 3.6297,
"sd": 1.8691,
"median": 3.438,
"n": 21284,
"month_name": "Feb"
},
{
"month": 3,
"mean": 2.8243,
"sd": 1.6811,
"median": 2.578,
"n": 21918,
"month_name": "Mar"
}
]
}
}Wind data (sample)
{
"wind": {
"monthly": [
{
"month": 1,
"mean": 17.5198,
"sd": 6.9971,
"median": 17.533,
"n": 24352,
"month_name": "Jan"
},
{
"month": 2,
"mean": 19.0089,
"sd": 6.5457,
"median": 19.013,
"n": 21237,
"month_name": "Feb"
},
{
"month": 3,
"mean": 16.3551,
"sd": 6.8438,
"median": 16.166,
"n": 21877,
"month_name": "Mar"
}
]
}
}Annual trends
{
"annual_trends": {
"wave": {
"annual_stats": [
{
"year": 2018,
"mean": 3.5427,
"median": 3.281,
"sd": 1.6517,
"max": 10.781,
"p90": 5.781,
"p99": 8.594,
"n": 5229
},
{
"year": 2019,
"mean": 2.6478,
"median": 2.344,
"sd": 1.6309,
"max": 15.703,
"p90": 4.844,
"p99": 7.736,
"n": 23498
},
{
"year": 2020,
"mean": 2.6805,
"median": 2.227,
"sd": 1.8318,
"max": 15.117,
"p90": 5.156,
"p99": 8.984,
"n": 26774
},
{
"year": 2021,
"mean": 2.2887,
"median": 1.875,
"sd": 1.5643,
"max": 12.578,
"p90": 4.453,
"p99": 7.109,
"n": 43323
},
{
"year": 2022,
"mean": 2.4772,
"median": 2.031,
"sd": 1.7631,
"max": 15.781,
"p90": 4.805,
"p99": 8.438,
"n": 39957
},
{
"year": 2023,
"mean": 2.5258,
"median": 2.227,
"sd": 1.5755,
"max": 11.953,
"p90": 4.688,
"p99": 7.5,
"n": 42741
},
{
"year": 2024,
"mean": 2.4866,
"median": 2.188,
"sd": 1.5774,
"max": 12.188,
"p90": 4.57,
"p99": 7.617,
"n": 42567
},
{
"year": 2025,
"mean": 2.5231,
"median": 2.109,
"sd": 1.6733,
"max": 12.773,
"p90": 4.805,
"p99": 7.969,
"n": 41269
},
{
"year": 2026,
"mean": 3.4176,
"median": 3.281,
"sd": 1.6419,
"max": 12.422,
"p90": 5.508,
"p99": 8.086,
"n": 8914
}
],
"trend_per_decade": -0.1708,
"p_value": 0.7851,
"r_squared": 0.0113
},
"wind": {
"annual_stats": [
{
"year": 2018,
"mean": 17.2612,
"median": 17.267,
"sd": 6.5813,
"max": 38,
"p90": 25.473,
"p99": 33,
"n": 4351
},
{
"year": 2019,
"mean": 15.1625,
"median": 14.943,
"sd": 6.53,
"max": 43,
"p90": 23.794,
"p99": 31,
"n": 23314
},
{
"year": 2020,
"mean": 15.8785,
"median": 15.711,
"sd": 6.8127,
"max": 50.207,
"p90": 24.705,
"p99": 32.333,
"n": 24950
},
{
"year": 2021,
"mean": 14.6538,
"median": 14.231,
"sd": 6.7396,
"max": 48.613,
"p90": 23.566,
"p99": 31.991,
"n": 43323
},
{
"year": 2022,
"mean": 15.0745,
"median": 14.8,
"sd": 6.6821,
"max": 50.093,
"p90": 23.794,
"p99": 31.991,
"n": 39957
},
{
"year": 2023,
"mean": 15.6905,
"median": 15.483,
"sd": 6.7129,
"max": 44.173,
"p90": 24.477,
"p99": 32.219,
"n": 42741
},
{
"year": 2024,
"mean": 15.4624,
"median": 15.142,
"sd": 6.5811,
"max": 47.588,
"p90": 24.136,
"p99": 32.674,
"n": 42567
},
{
"year": 2025,
"mean": 15.3419,
"median": 14.914,
"sd": 6.7905,
"max": 56.582,
"p90": 24.363,
"p99": 31.991,
"n": 41269
},
{
"year": 2026,
"mean": 18.2204,
"median": 18.216,
"sd": 6.8966,
"max": 40.644,
"p90": 27.437,
"p99": 33.927,
"n": 8914
}
],
"trend_per_decade": 0.7632,
"p_value": 0.6393,
"r_squared": 0.0331
}
}
}Correlations
The correlations.json endpoint provides overall wind-wave and wave-Hmax correlations plus inter-station pair correlations (cross-correlation analysis) for wave height, wind speed, and maximum wave height.
Fields: overall.wind_wave, overall.wave_hmax, station_pairs.wave_height, station_pairs.wind_speed, station_pairs.hmax
Overall correlations
{
"overall": {
"wind_wave": 0.6092,
"wave_hmax": 0.9767
}
}Station pair sample (wave height)
{
"station_pairs": {
"wave_height": [
{
"station1": "M2",
"station2": "M3",
"distance_km": 39,
"optimal_lag": 0,
"max_correlation": 0.6522,
"expected_lag": 1.3,
"n_obs": 45669
},
{
"station1": "M2",
"station2": "M4",
"distance_km": 233.9,
"optimal_lag": 0,
"max_correlation": 0.5568,
"expected_lag": 7.8,
"n_obs": 46692
},
{
"station1": "M2",
"station2": "M5",
"distance_km": 52.3,
"optimal_lag": 0,
"max_correlation": 0.7717,
"expected_lag": 1.7,
"n_obs": 46588
},
{
"station1": "M2",
"station2": "M6",
"distance_km": 454.3,
"optimal_lag": 2,
"max_correlation": 0.5602,
"expected_lag": 15.1,
"n_obs": 44301
},
{
"station1": "M3",
"station2": "M4",
"distance_km": 271.8,
"optimal_lag": -1,
"max_correlation": 0.8073,
"expected_lag": 9.1,
"n_obs": 50473
}
]
}
}Return Levels
The return-levels.json endpoint provides Generalised Pareto Distribution (GPD) return level estimates for extreme wave heights. The 95th percentile threshold is used, with return periods of 1, 5, and 10 years.
Method: GPD | Threshold: 95th percentile | Return periods: 1, 5, 10 years
Rogue Waves
The rogue-waves.json endpoint lists detected rogue wave events where the maximum wave height (Hmax) exceeds twice the significant wave height (Hs). Events are sorted by the Hmax/Hs ratio (most extreme first).
Total rogue wave events detected: 1,638
Data Dictionary
The data-dictionary.json endpoint defines all variables in the dataset, including names, descriptions, units, and data types.
Derived Statistics Metadata
The API includes several computed statistics (return levels, trend estimates, gust factors, etc.) derived from the raw ERDDAP data. The table below documents units and definitions for each derived quantity.
Sources
The sources.json endpoint provides data provenance information including the ERDDAP base URL, dataset ID, update frequency, license, and citation. This is a pure-constant endpoint with no upstream data dependency.
Fields: erddap_base_url, dataset_id, info_url, provider, update_frequency, license, citation, variables_measured
Station Status
The status.json endpoint provides per-station operational status including record counts, date ranges, and summary statistics.
Fields: n_stations, total_records, date_range, stations[] (each with station_id, n_records, first_date, last_date, mean_wave_height, max_wave_height, mean_wind_speed, max_wind_speed)
Trends
The trends.json endpoint provides Mann-Kendall trend test results per station and variable, plus overall annual trend statistics for wave height and wind speed.
Fields: mann_kendall (per-station/variable: tau, p_value, trend_direction), annual_trends.wave, annual_trends.wind (each with trend_per_decade, p_value, r_squared)
Extremes
The extremes.json endpoint combines GPD return levels with confidence interval comparisons (delta-method vs bootstrap) into a single resource.
Fields: method, threshold, return_periods, return_levels (nested by station/variable), ci_comparison (with methods, n_rows, records)
Decomposition
The decomposition.json endpoint provides STL decomposition results (seasonal, trend, remainder components) per station, downsampled to daily resolution to keep file size manageable.
Fields: resolution, stations (per-station: variable, n_daily_points, summary, components)
Spatial Correlations
The spatial.json endpoint provides cross-station pair correlations for wave height, wind speed, and maximum wave height including distance, optimal lag, and maximum correlation.
Fields: wave_height, wind_speed, hmax (each a data frame with station1, station2, distance_km, optimal_lag, max_correlation, expected_lag, n_obs)
Gust Factors
The gust-factors.json endpoint provides gust factor analysis per station including summary statistics, extreme gust events (capped at 500), and rogue gust thresholds.
Fields: summary, extreme_gusts, by_station, rogue_gust_threshold, n_rogue_gusts, pct_rogue_gusts
Statistical Methods
The methods.json endpoint documents all statistical methods used in the analyses, including parameter choices, thresholds, and academic references.
Methods covered: GPD extreme value analysis, Mann-Kendall trend tests, STL decomposition, rogue wave detection, gust factor analysis, cross-correlation.
{
"gpd": {
"description": "Generalised Pareto Distribution fitted to exceedances above a threshold using maximum likelihood estimation (mev::fit.gpd).",
"threshold": "95th percentile of the variable's distribution",
"return_periods": [1, 5, 10],
"observations_per_year": 8760,
"ci_methods": {
"delta": "Delta method (asymptotic normal approximation of MLE)",
"bootstrap": "Block bootstrap (block_size=48h) with 500 resamples; percentile CIs at 95% level"
},
"references": ["Coles, S. (2001). An Introduction to Statistical Modeling of Extreme Values. Springer.", "Beirlant, J. et al. (2004). Statistics of Extremes. Wiley."]
}
}Data Sources
All data originates from the Marine Institute’s ERDDAP server:
- ERDDAP base URL: https://erddap.marine.ie/erddap/tabledap/IWBNetwork
- Dataset ID:
IWBNetwork - Direct data query (HTML): https://erddap.marine.ie/erddap/tabledap/IWBNetwork.html
- Metadata (info page): https://erddap.marine.ie/erddap/info/IWBNetwork/index.html
Example ERDDAP queries:
# Latest 100 rows as CSV
curl "https://erddap.marine.ie/erddap/tabledap/IWBNetwork.csv?&orderByLimit(%22100%22)"
# Station metadata as JSON
curl "https://erddap.marine.ie/erddap/tabledap/IWBNetwork.json?station_id,longitude,latitude&distinct()"Usage Examples
curl
# Fetch latest observations (one per station)
curl https://johngavin.github.io/irishbuoys/api/v1/latest.json R (jsonlite)
# R: Read the API index
library(jsonlite)
index <- fromJSON("https://johngavin.github.io/irishbuoys/api/v1/index.json")
index$endpoints
# Read latest observations
latest <- fromJSON("https://johngavin.github.io/irishbuoys/api/v1/latest.json")
latest$observations Fetching stats and seasonal data (R)
library(jsonlite)
# Per-station statistics
stats <- fromJSON("https://johngavin.github.io/irishbuoys/api/v1/stats.json")
stats$overall
# Seasonal patterns
seasonal <- fromJSON("https://johngavin.github.io/irishbuoys/api/v1/seasonal.json")
head(seasonal$wave$monthly)
# Return levels
rl <- fromJSON("https://johngavin.github.io/irishbuoys/api/v1/return-levels.json")
str(rl$by_station, max.level = 2)Python (requests)
# Python: Read the API
import requests
import pandas as pd
base = "https://johngavin.github.io/irishbuoys/api/v1/"
# Get latest observations
latest = requests.get(base + "latest.json").json()
df = pd.DataFrame(latest["observations"])
print(df.head()) Fetching stats and seasonal data (Python)
import requests
import pandas as pd
base = "https://johngavin.github.io/irishbuoys/api/v1/"
# Per-station statistics
stats = requests.get(base + "stats.json").json()
print(stats["overall"])
# Seasonal wave patterns
seasonal = requests.get(base + "seasonal.json").json()
df_monthly = pd.DataFrame(seasonal["wave"]["monthly"])
print(df_monthly.head())Bulk Data Access
For bulk analysis, download the full dataset as Parquet:
curl -O https://johngavin.github.io/irishbuoys/vignettes/data/buoy_data.parquetRead in R with arrow::read_parquet() or in Python with pandas.read_parquet().
Bulk dataset summary: 299,753 rows, 5 stations, 22 columns (6885.4 KB). Last validated: 2026-03-16T09:01:19Z
API File Summary
# A tibble: 17 × 4
file path size_bytes size_kb
<chr> <chr> <dbl> <dbl>
1 index.json docs/api/v1/index.json 3587 3.5
2 stations.json docs/api/v1/stations.json 1416 1.4
3 stats.json docs/api/v1/stats.json 2252 2.2
4 rogue-waves.json docs/api/v1/rogue-waves.json 635943 621
5 return-levels.json docs/api/v1/return-levels.json 7889 7.7
6 data-dictionary.json docs/api/v1/data-dictionary.json 5951 5.8
7 latest.json docs/api/v1/latest.json 3582 3.5
8 seasonal.json docs/api/v1/seasonal.json 10329 10.1
9 correlations.json docs/api/v1/correlations.json 7326 7.2
10 sources.json docs/api/v1/sources.json 880 0.9
11 status.json docs/api/v1/status.json 1835 1.8
12 trends.json docs/api/v1/trends.json 1975 1.9
13 extremes.json docs/api/v1/extremes.json 38044 37.2
14 decomposition.json docs/api/v1/decomposition.json 2310582 2256.
15 spatial.json docs/api/v1/spatial.json 6656 6.5
16 gust-factors.json docs/api/v1/gust-factors.json 200993 196.
17 methods.json docs/api/v1/methods.json 2960 2.9
Live API
In addition to the static JSON files, irishbuoys provides a live REST API powered by plumber. The API serves the same pre-computed JSON data via HTTP endpoints.
Starting the API
library(irishbuoys)
run_api(port = 8080)
# API at http://localhost:8080
# Swagger docs at http://localhost:8080/__docs__/Endpoints
| Endpoint | Description |
|---|---|
GET /stations |
Station metadata and locations |
GET /rogue-waves |
Detected rogue wave events |
GET /return-levels |
Extreme value return level estimates |
GET /seasonal |
Monthly and seasonal statistics |
GET /sources |
Data provenance and citation |
GET /status |
Per-station operational status |
GET /trends |
Mann-Kendall trend tests |
GET /extremes |
GPD fits and CI comparison |
GET /decomposition |
STL decomposition per station |
GET /spatial |
Cross-station correlations |
GET /gust-factors |
Gust factor analysis |
GET /methods |
Statistical methods documentation |
Programmatic Access
# Create router without starting server (useful for testing)
pr <- create_api_router()The live API requires the plumber package (install.packages("plumber")).
Update Schedule
- Frequency: Every 6 hours (0:00, 6:00, 12:00, 18:00 UTC)
- Source: Marine Institute ERDDAP server
- Pipeline:
targets::tar_make()with incremental DuckDB updates - CI: data-update.yml
Data freshness depends on the ERDDAP server. The pipeline downloads the latest 72 hours of observations each run to catch any late-arriving data.