Services Stack Expérience Me contacter

Building a hydrological data visualizer with Hub'eau and Leaflet — technical retrospective


Introduction

Hydro Explorer is an open source hydrological data visualizer I built to explore the Hub’eau API and deepen my skills in interactive mapping. The result is publicly available: French hydrometric stations on a Leaflet map, with real-time charts and optional layers (piezometry, Vigicrues).

This technical retrospective covers the architecture choices, challenges encountered, and solutions adopted.

The Hub’eau Hydrometry v2 API

Hub’eau is the French public water data portal. The Hydrometry v2 API exposes measurement stations (water level and flow rate) across all French waterways.

Key endpoints used:

  • /referentiel/stations — list of 3,000+ active stations with geographic coordinates
  • /observations_tr — real-time observations (level H and flow Q) over a given period

Pagination is handled via size and cursor parameters. Coordinates are in WGS84, directly compatible with Leaflet.

const response = await fetch(
  'https://hubeau.eaufrance.fr/api/v2/hydrometrie/referentiel/stations'
  + '?size=5000&fields=code_station,libelle_station,longitude_station,latitude_station'
  + '&en_service=true&format=json'
);
const { data } = await response.json();

Leaflet 1.9 Integration

Leaflet remains the reference for lightweight web mapping. No framework, no build step — just a JS file and a <script> tag.

IGN Géoplateforme tiles replace OpenStreetMap for a rendering better suited to the French hydrological context:

L.tileLayer(
  'https://data.geopf.fr/wmts?SERVICE=WMTS&REQUEST=GetTile'
  + '&layer=GEOGRAPHICALGRIDSYSTEMS.PLANIGNV2'
  + '&style=normal&tilematrixset=PM&TileMatrix={z}&TileCol={x}&TileRow={y}'
  + '&format=image/png',
  { attribution: '© IGN Géoplateforme', maxZoom: 18 }
).addTo(map);

Clustering 3,000 Markers

Displaying 3,000 markers without clustering severely degrades performance. Leaflet.markercluster groups markers according to zoom level:

const clusterGroup = L.markerClusterGroup({
  chunkedLoading: true,
  maxClusterRadius: 60,
});
stations.forEach(station => {
  const marker = L.marker([station.latitude, station.longitude]);
  clusterGroup.addLayer(marker);
});
map.addLayer(clusterGroup);

Marker colours indicate data freshness: green (recent data), yellow (warning), grey (inactive).

Plotly Charts with Dual Axis

Plotly handles time series with a dual H/Q axis (water level and flow rate over the same period):

Plotly.react('chart', [
  { x: dates, y: levels, name: 'Level (m)', yaxis: 'y' },
  { x: dates, y: flows, name: 'Flow (m³/s)', yaxis: 'y2', type: 'scatter' },
], {
  yaxis: { title: 'Level (m)' },
  yaxis2: { title: 'Flow (m³/s)', overlaying: 'y', side: 'right' },
});

PWA and IndexedDB Cache

The Service Worker caches the shell (HTML, CSS, JS) for offline use. Observation data is cached in IndexedDB with a 30-minute TTL to avoid hitting the API on every click.

// Composite cache key: station + period
const cacheKey = `${stationCode}_${periodDays}`;
const cached = flowCache.get(cacheKey);
if (cached) return cached;

Conclusion

Hydro Explorer is available on GitHub and as a live demo on GitHub Pages.

The project gave me hands-on mastery of advanced Leaflet, the Hub’eau API, marker clustering, and Progressive Web Apps — skills directly applicable to environmental data visualisation projects.