loadcurve.eu

Methodology

What this is

loadcurve.eu shows European electricity data — consumption, wind and solar generation, total renewable generation, and temperature — across 35 bidding zones, hour by hour, from 2015 to the present. The raw inputs are public; the work is in the processing: consistent zone-level aggregation, honest metric definitions, degree-day and weather-normalisation derivations, and cleaned, auditable time series. This page documents exactly how each number is produced, and — just as importantly — what each number does not claim.

The site treats Europe as a single system rather than privileging any one country. There is no “home market”; every bidding zone is handled the same way.

For the bigger picture — what this project is, the stack and design decisions behind it, and who built it — see the About page.

Data sources & licence

Two public sources feed the site, both CC-BY 4.0:

  • ENTSO-E Transparency Platform — consumption (actual total load) and generation by production type. Published by Europe's transmission system operators under EU Regulation 543/2013. The data items used here are on the Platform's list of data available for re-use, licensed CC-BY 4.0.
  • Open-Meteo — hourly 2-metre air temperature, one representative point per zone (see Temperature & degree-days), licensed CC-BY 4.0.

Both sources are processed and aggregated here, not republished verbatim: hourly temperature is converted into degree-days, generation is summed into the metrics below, and series are cleaned and re-gridded. CC-BY requires indicating that changes were made — they were, as described throughout this page.

The footer carries the required attribution with links on every page:

EN: Weather data by Open-Meteo.com (CC BY 4.0) · Electricity data: ENTSO-E Transparency Platform (CC BY 4.0) — both processed/aggregated.

HU: Időjárási adatok: Open-Meteo.com (CC BY 4.0) · Villamosenergia-adatok: ENTSO-E Transparency Platform (CC BY 4.0) — feldolgozva/aggregálva.

(Links are not optional under CC-BY: link Open-Meteo to open-meteo.com and the CC-BY licence, and ENTSO-E to its Transparency Platform and the licence.)

The current build uses load + generation + temperature only; no day-ahead price data is ingested yet.

All timestamps are handled in both local zone time and UTC (see Day basis). The site is rebuilt automatically every hour.

Coverage

35 bidding zones, hourly resolution, from 1 January 2015 to the present. Multi-zone countries are kept at bidding-zone granularity (for example Italy, Norway, Sweden and Denmark are split into their constituent zones); single-zone countries are represented by one zone. Coverage is not uniform across the whole period — see Known limitations and Deliberate exclusions.

Zone aggregation

For each zone, hourly load and generation series are aligned on a common hourly index, de-duplicated (keeping the first value where the source reports duplicates), and resampled to a clean hourly grid. Generation arrives as a breakdown by production type; the relevant types are summed into the published series (see Metrics). Country- and Europe-level figures are sums of the constituent zones for the selected period.

Temperature & degree-days

Each zone is assigned one representative weather point (a single latitude/longitude, typically a major load centre), from which hourly temperature is drawn. This is a deliberate simplification: it is not a population-weighted or area-weighted temperature for the whole zone, and it will diverge from a zone-wide average in large or climatically varied zones.

Zone table unavailable — run the ETL compose step to generate it.

Degree-days are computed from the hourly temperature, not from a daily mean. For each hour, the heating contribution is max(0, 18 °C − T) and the cooling contribution is max(0, T − 22 °C); these are averaged over the hours of each day. Computing degree-days hour by hour (rather than from the daily-mean temperature) is more accurate in shoulder seasons, when temperature crosses the base threshold within a single day.

The bases are 18 °C for heating (HDD) and 22 °C for cooling (CDD). The 18–22 °C band is a deliberate dead zone in which neither heating nor cooling demand is attributed — a comfort range rather than a single switch point.

Metrics

There are two distinct renewable metrics on the site. They are not interchangeable, and they are named to keep them apart.

Wind+solar share (variable renewables)

(wind + solar) / load for the selected zone(s) and period. This is the variable, weather-driven share of demand — the metric that the Dunkelflaute view and the “highest / lowest wind+solar hour” records are built on. It deliberately excludes hydro and all dispatchable renewables, because Dunkelflaute (“dark doldrums”) is specifically about low wind and low sun; folding hydro in would defeat the concept.

Total renewable share (all sources)

renewable / load, where renewable is the sum of these ENTSO-E production types (exact match, not substring):

Biomass (B01), Geothermal (B09), Hydro Run-of-river and poundage (B11), Hydro Water Reservoir (B12), Other renewable (B15), Solar (B16), Wind Offshore (B18), Wind Onshore (B19).

Two exclusions are deliberate and worth stating plainly:

  • Hydro Pumped Storage (B10) is excluded. Its output comes from water previously pumped uphill using grid electricity (often non-renewable); counting it would overstate renewable generation. It also shares the word “Hydro” with the reservoir and run-of-river types, so the matching is exact rather than a “Hydro” substring, specifically to keep B10 out.
  • Waste (B17) is excluded. It is only partly renewable, so it is left out rather than counted in full.

This total-renewable metric is what drives the cross-country comparisons — the map's renewable layer, the headline “renewable share” figure, and the “greenest country” reading. It is why hydro-dominated zones (much of Norway, Sweden, Austria) read as highly renewable here, as they should.

Nuclear is not counted as renewable and does not appear in this metric at all. A zone can therefore be low-carbon in practice while still showing a low renewable share here — France is the clearest case: its generation is dominated by nuclear, so its total-renewable share reads as modest even though its carbon intensity is among the lowest in Europe. “Renewable” and “low-carbon” are not the same question; the Low-carbon share & CO₂ intensity section below is the place that addresses the latter.

A shared caveat on both shares

Both shares use consumption (load) as the denominator, not total generation. They therefore measure renewable (or wind+solar) generation relative to local demand, not the renewable fraction of the local generation mix. In a zone that exports heavily from renewables the ratio can approach or exceed 100%; in a net importer it reads lower than the physical electricity actually consumed there. The figures do not account for cross-border flows.

Low-carbon share & CO₂ intensity

Two further metrics sit alongside the renewable shares above. Neither is a renewable metric — they answer a different question: how much of this zone's electricity comes from low-carbon sources, and how carbon-intensive is the mix actually generated here?

Low-carbon share

(renewable + nuclear) / load. Nuclear is not renewable — it does not appear in the renewable-share metric above, and it never enters renewable_mwh — but it is low-carbon on a lifecycle basis (see factors below). This is exactly why this metric exists: a zone like France, Hungary or Slovakia can read as low on total-renewable share while still being among the lowest-carbon zones on the continent, because nuclear supplies most of its low-carbon generation rather than wind, solar or hydro. The two metrics are deliberately kept apart so that "renewable" and "low-carbon" are never conflated.

CO₂ intensity

Reported in gCO₂eq/kWh, computed as:

CO₂ intensity = Σ(generation × emission factor) / Σ(generation)

summed over whichever period is selected — never the average of hourly or daily intensities. Averaging intensities would distort the figure (a low-generation, high-intensity hour would count as much as a high-generation hour), so the building blocks (total emissions and total qualifying generation) are aggregated first, and the ratio is taken last, at every level from a single hour up to a multi-year period.

This is a production-based figure: it is the intensity of the electricity mix generated in the zone, not the electricity consumed there. loadcurve.eu has no cross-border flow data, so a consumption-based (flow-traced) figure — the kind published by tools like Electricity Maps — cannot be computed here. A heavily-importing zone with a clean local mix will show a low figure even if some of the power it actually consumes was generated elsewhere and is dirtier; this is the same caveat already stated for the renewable shares (see above), applied to carbon intensity.

Emission factors

Factors are lifecycle (cradle-to-grave) gCO₂eq/kWh, applied per ENTSO-E production type (exact match, never a substring — the same discipline as the renewable-type matching above). Most figures are the IPCC Fifth Assessment Report (AR5, 2014) lifecycle medians, the same default set published by Electricity Maps: nuclear 12, wind onshore 11, wind offshore 12, hydro 24, solar 45, geothermal 38, gas 490, hard coal 820. A few types have no clean AR5 figure and are documented estimates instead: lignite/brown coal (1080, scaled from the AR5 hard-coal median — lignite plants run materially less efficiently than hard coal), oil (650, from the UK Parliamentary Office of Science and Technology, the same non-AR5 source Electricity Maps itself uses), oil shale, peat, coal-derived gas, marine, "other renewable" and waste.

Biomass (230 g/kWh) is explicitly flagged as contested. It is the AR5/Electricity Maps figure, used here for consistency with the rest of the table — but biomass accounting varies enormously by convention, from near-zero (treating combustion as carbon-neutral at the point of burning) to well over 700 g/kWh (full land-use and harvest-cycle accounting). This site picks one number and states it plainly rather than picking the most flattering one.

Excluded from both the numerator and the denominator: Hydro Pumped Storage (B10) — it is storage, not net generation, so including it would double-count electricity that was itself drawn from the grid earlier — and "Other" (unspecified mix) — its composition is unknown, so folding it in at any factor would either inflate or dilute the intensity with an uncosted guess. Both exclusions mean the qualifying-generation denominator can be smaller than total reported generation for a zone; the figure is the intensity of the costed mix, not a claim about 100% of generation.

As with every other metric on this site: where a zone's generation mix is missing or incomplete for an hour, the low-carbon share and CO₂ intensity are shown as absent, never as a false zero.

Weather-normalised consumption trend

This is the site's attempt to answer: once you remove the effect of weather, is underlying electricity consumption rising or falling?

For each zone, daily consumption is regressed on heating and cooling degree-days using ordinary least squares:

load ≈ b₀ + b₁·HDD + b₂·CDD

The fitted coefficients give the estimated weather sensitivity. Each day's consumption is then adjusted to a common reference weather — the mean HDD and CDD — by removing the weather-driven deviation:

normalised = load − b₁·(HDD − meanHDD) − b₂·(CDD − meanCDD)

The normalised daily values are averaged per year to produce the trend line. In effect: what would consumption have been if every day had had average heating and cooling demand?

The regression is fitted on each zone's full available history (roughly 7–11 years of data per zone), and the result is shown for the selected period only — so the trend's shape and level are stable regardless of what period you have selected for display.

In one sentence: the trend is weather-normalised — the effect of temperature is removed using heating and cooling degree-days (HDD/CDD) via a linear regression on each zone's full history — so the remaining movement reflects factors other than the weather.

Disclaimer shown with the chart: a deliberately simple linear model (consumption ~ HDD + CDD); it does not account for weekdays, holidays, economic cycles, or growth in renewable capacity. It is an indicative trend, not a forecast.

What this trend does and does not claim

It removes the influence of temperature. It does not isolate any single other driver. Whatever remains — economic activity, the pandemic, efficiency gains, electrification of heating and transport — is left in. A falling normalised line means “consumption fell for reasons other than the weather,” not “the economy shrank” or “efficiency improved”; those are among the possible causes, not a conclusion.

Three further limits are inherent to the method:

  • The model assumes a constant weather sensitivity over the whole period (one b₁ and one b₂ per zone). If a zone's response to temperature changes over time — as heat-pump and air-conditioning adoption grows — that change is not captured by the model and instead appears in the normalised trend.
  • Degree-days come from a single representative point per zone (see above), so the weather signal is an approximation of the zone's true weather.
  • It is a linear model in HDD/CDD with no calendar terms (no weekday/holiday effects). It is a deliberately simple, transparent specification, not a forecasting model.

Note: the “normalise” toggle in the free explorer is a different operation — it rescales each zone's series by that zone's own mean so multiple zones can be compared on one axis. It is unrelated to the weather normalisation described here.

Records

Records are computed over the full history (or the selected period, where the period view is active):

  • Peak consumption — the highest Europe-wide load hour (or day, in period view).
  • Highest / lowest wind+solar hour — the hours with the greatest and smallest Europe-wide (wind+solar)/load. The lowest is the deepest Dunkelflaute.

Day basis

Every daily figure is computed on two bases — the local calendar day of the zone and the UTC calendar day — and stored separately. The map, “now” figures and records use the UTC basis for cross-zone comparability; the day picker and hourly drill-down respect this so a single selected day shows its 24 hours consistently.

Update cadence & revisions

The pipeline runs hourly. On each incremental run it re-fetches the most recent 10 days and overwrites them, because ENTSO-E revises recent values after first publication; the rolling re-fetch lets those corrections flow through rather than freezing first-published numbers.

Deliberate exclusions

  • Germany before 1 October 2018. Until then, Germany shared a single combined bidding zone with Austria and Luxembourg (DE-AT-LU). Austria is tracked separately on this site, so including the pre-split combined data would double-count Austrian (and Luxembourg) consumption in the European totals. The German (DE) series therefore begins on 1 October 2018, when the combined zone split into a standalone DE-LU zone. This is why an automated coverage check flags Germany's early years as “missing” — the data is omitted on purpose, not lost. (A two-day junk fragment in 2015 is removed by the cutoff rule.)
  • Europe as one system. Countries are not weighted or singled out; European aggregates are straightforward sums of the included zones.

Known limitations

Coverage is complete across the 35 zones aside from the deliberate German exclusion above. The figures carry a few inherent limitations worth knowing:

  • The renewable share compares a zone's local generation to local consumption. In import-dependent demand centres (for example Sweden's SE-3) the figure can read lower than the share of green electricity actually consumed there, because some of that electricity is imported.
  • Net-exporting zones can exceed 100% — the northern Norwegian and Swedish zones (NO-5, SE-2, NO-2, NO-4, SE-1) generate more renewable power than they consume and export the surplus, so renewable-over-consumption rises above 100%.
  • Some countries also report generation under aggregated or “not specified” categories that ENTSO-E does not break down by type; that output is not counted in the renewable sum, so the true renewable share can be somewhat higher than shown in those zones.
  • The German (DE) zone begins on 1 October 2018 (see Deliberate exclusions).

Reproducibility & stack

The site is static and build-less: pre-generated JSON/parquet files served directly, read in the browser at runtime, with charts drawn by Observable Plot and the map by d3-geo. The processing pipeline is a single Python script using DuckDB. There is no server-side computation at request time — what you see is the output of the last hourly build.