Case study · Data Engineering and Data Science
How much has Argentina warmed?
85 years of daily temperature from 27 cities, from Jujuy to Ushuaia, turned into a dashboard that updates itself. This is how I built it, from the API to the chart.
+0.8 °C
warmer than the 1961–1990 period (average of the last 10 years) (2016–2025)
Hover or tap a year to see its value.
1The problem
I wanted to answer a simple question with data: how much has Argentina warmed, and where?
- How much
- How much warmer the last 10 years are than the 1961–1990 reference period.
- Where
- Which areas warmed the most: the north, Cuyo, the Pampas or Patagonia.
- When
- Whether days or nights warmed more, and which months changed the most.
- Extremes
- How many hot days (≥ 30 °C) and frosts there are today compared with before.
2The data
The data comes from the ECMWF/Copernicus ERA5 reanalysis, through the free Open-Meteo API: daily temperature since 1940 for the 24 provincial capitals plus three more cities. Every decision aims to keep the series comparable over time.
- Pure ERA5
- The whole series comes from the same model, not from an automatic mix of sources. Mixing models of different resolution could create an artificial jump in an 85-year trend.
- 1961–1990 reference
- It is the WMO standard period for studying climate change.
- Trend since 1980
- Before the satellite era ERA5 has fewer observations, so those years are less certain.
- Complete years only
- A partial year biases the average: it is missing the summer or the winter.
3How I built it
It is an ELT pipeline: extract, load raw, and transform inside the data warehouse. Every stage can be re-run without duplicating or breaking anything.
ERA5 API
Open-Meteo, ECMWF reanalysis
Extract
Per city and decade, with retries
DuckDB
Idempotent load with upsert
dbt
Staging, intermediate and marts, with tests
Dashboard
Static site on GitHub Pages
- Extract
- Requests the API per city and decade, retries errors with growing waits, respects quota limits and can resume where it stopped. Each response is stored as received, with metadata about what was requested and when.
- Load
- DuckDB unpacks the JSON into one row per day. The load is idempotent: if a day arrives twice, the most recent extraction wins.
- Transform
- dbt in three layers (staging, intermediate and marts). The fact table is incremental, so it picks up corrections and new cities without recomputing everything.
- 90-day refresh
- The latest months of ERA5 are preliminary and corrected later, so every run requests them again and replaces the values.
- Dashboard
- A static site. GitHub Actions runs the pipeline on Mondays and Thursdays and publishes it to GitHub Pages. The heat map grid is computed once, because doing it in the browser froze the page for about 2.5 seconds.
4Quality and limits
Bad data shows up late, so every layer has its own checks. I also wrote down what the project cannot claim.
- dbt tests
- Unique keys, non-null values and relationships between tables; physically possible ranges; minimum ≤ mean ≤ maximum temperature; no missing days between the first and last data point.
- Freshness
- Warns if the latest data is more than 16 days old and fails at 30.
- Python tests
- 18 tests covering chunk planning, resuming, retries, idempotency and the newest file winning.
- Limit: the grid
- ERA5 is a roughly 25 km grid, not a weather station: in mountains or on the coast the cell can differ from the local value.
- Limit: the average
- The national average is a simple mean across 27 cities. Small provinces in the center and the Litoral weigh more than their area, and Patagonia weighs less.
5The result, year by year
Each year is the difference between the country's mean temperature and that of 1961–1990 (the thin line). The thick line is the 10-year moving average: it has risen steadily since 2000.
Hover or tap a year to see its value.