Plot every version of a forecast

Read a forecast as it was known hour by hour, and draw each version it went through.

A forecast is published, then revised. The API keeps every version, so one call returns the forecast as it stood at each hour, and the versions can be drawn on top of each other.

This example reads Fingrid's day-ahead load forecast for Finland, as published on the ENTSO-E Transparency Platform, for yesterday:

Read one snapshot per hour. as_of=PT1H returns the whole window as it was known at every hour. The window starts two days before the delivery day, so it also covers the hours when the forecast was issued and revised.

Keep the versions. From each snapshot keep the delivery day, and drop the snapshots that did not change it: what remains are the versions of the forecast.

Plot them, coloured from the oldest to the newest.

import os
from datetime import datetime, timedelta, timezone

import matplotlib.pyplot as plt
import pandas as pd
import requests

API = "https://grid.rebase.energy/api/v1"
HEADERS = {"X-API-Key": os.environ["GRID_API_KEY"]}
ENTITY = "FI"
NAME = "consumption.load_forecast.day_ahead_total_load_forecast"

# The delivery day is yesterday. The window starts two days earlier, so the snapshots also
# cover the hours before the delivery day, when the forecast was issued and revised.
day = datetime.now(timezone.utc).replace(hour=0, minute=0, second=0, microsecond=0) - timedelta(days=1)
start, end = day - timedelta(days=2), day + timedelta(days=1)

# One snapshot per hour: each is the whole window as it was known at that hour.
r = requests.get(
    f"{API}/entities/{ENTITY}/timeseries/{NAME}/values",
    headers=HEADERS,
    params={
        "provider": "entsoe",
        "start": start.isoformat(),
        "end": end.isoformat(),
        "as_of": "PT1H",
        "max_snapshots": 1000,
    },
)
r.raise_for_status()

# Keep the delivery day from each snapshot, and only the snapshots that changed it: those are
# the versions of the forecast.
versions = []
for snapshot in r.json()["snapshots"]:
    points = pd.DataFrame(snapshot["points"])
    points["valid_time"] = pd.to_datetime(points["valid_time"])
    points = points[(points["valid_time"] >= day) & (points["valid_time"] < day + timedelta(days=1))]
    if points.empty:
        continue
    series = points.set_index("valid_time")["value"]
    if versions and series.equals(versions[-1][1]):
        continue
    versions.append((snapshot["as_of"], series))

fig, ax = plt.subplots(figsize=(10, 5))
colors = plt.cm.viridis([i / max(len(versions) - 1, 1) for i in range(len(versions))])
for (as_of, series), color in zip(versions, colors):
    ax.plot(series.index, series.values, color=color, linewidth=1.2, label=f"as of {as_of[5:16]}")
ax.set_title(f"{ENTITY} day-ahead load forecast for {day:%Y-%m-%d}: {len(versions)} versions")
ax.set_ylabel("MW")
ax.legend(fontsize=7, ncol=2)
fig.tight_layout()
plt.show()

Five versions of the Finnish day-ahead load forecast for one day, drawn as overlapping lines

Version history starts when the collection of a series starts, so the earliest delivery day with versions is 3 September 2026. For the snapshot forms of as_of, see Reading values.

The script is docs-site/examples/forecast_versions.py; it needs requests, pandas and matplotlib, and the key in GRID_API_KEY.