Use Python with GridLive to explore UK energy consumption.
Data is easy to fetch from GridLive using Python. The requests package can be used to easily download the data. Once downloaded the data can then in turn be processed using a range of libraries, including pandas. Examples of fetching metadata, time-series data, and processing the data are provided below.
# Simple example of fetching ESA Metadata from the GridLive API
# External library imports
import pandas as pd
from requests import get
# Define the API endpoint and parameters
url = "https://api.gridlive.shef.ac.uk/esa_metadata/dno/ssen"
# Make the GET request to fetch metadata
response = get(url, params={"limit": 0})
# Check if the request was successful
if response.status_code != 200:
raise Exception(f"Failed to fetch metadata. Status code: {response.status_code}")
# Parse JSON response into a DataFrame for easier manipulation
metadata_df = pd.DataFrame(response.json())
# Convert timestamps into a native datetime type
metadata_df["last_updated"] = pd.to_datetime(metadata_df["last_updated"])
print("Metadata extracted from the GridLive API and converted to Pandas DataFrame:")
print(metadata_df)
# Simple example of fetching Time-Series Smart Meter data from the GridLive API
# This example fetches data from a specified Ordnance Survey grid reference,
# but can easily be modified for any of the time-series end points
# External library imports
import pandas as pd
from requests import get
# Your GridLive API key
api_key = "YOUR API KEY HERE"
# An OS grid reference to fetch data from
os_grid_reference = "SP08" # SP08 - Birmingham
# GridLive end point to fetch from
end_point = f"smart_meter/in/{os_grid_reference}"
# Time range of data to fetch (inclusive)
time_from = "2025-05-05T18:00"
time_to = "2025-05-05T18:00"
# Make the GET request to fetch time-series data
headers = {"Authorization": api_key}
params = {"limit": 0, "start_datetime": time_from, "end_datetime": time_to}
response = get(
f"https://api.gridlive.shef.ac.uk/{end_point}",
headers=headers,
params=params,
)
# Check if the request was successful
if response.status_code != 200:
if (
"content-type" in response.headers
and "json" in response.headers["content-type"]
):
details = f" ({response.json()['detail']})"
else:
details = ""
raise Exception(
f"Failed to fetch time-series data. Status code: {response.status_code}{details}"
)
# Convert the data to a pandas DataFrame
timeseries_df = pd.DataFrame(response.json())
if len(timeseries_df) == 0:
raise Exception(f"No data for {time_from} to {time_to}")
timeseries_df["data_timestamp"] = pd.to_datetime(timeseries_df["data_timestamp"])
print("Time-series smart meter data from the GridLive API as a Pandas DataFrame:")
print(timeseries_df)
# Calculate the sum of the active consumption
active_import = timeseries_df["active_primary_consumption_import"]
sum_consumption = active_import.sum()
print(f"""
The sum of the active consumption for {os_grid_reference}
between {time_from} and {time_to}
is: {sum_consumption} kWh
""")
# Example of fetching energy consumption data from GridLive API and plotting a heatmap using Seaborn/Plotly
# Standard library imports
import io
from datetime import datetime, timedelta
# External library imports
import matplotlib.pyplot as plt
import pandas as pd
import plotly.express as px
import requests
import seaborn as sns
BASE_URL = "https://api.gridlive.shef.ac.uk/"
# Your GridLive API key
API_KEY = "YOUR API KEY HERE"
HEADERS = {"Authorization": API_KEY}
# An OS grid reference to fetch data from
os_grid_reference = "SJ39" # SJ39 - Liverpool
energy_data = None
# Fetch a week's worth of data starting from this date
data_start_date = datetime(2025, 5, 5)
print("Fetching data...", end="", flush=True)
for i in range(7):
# Set up to fetch a day's worth of data
data_end_date = data_start_date + timedelta(days=1)
# Fetch the data
res = requests.get(
f"{BASE_URL}smart_meter/in/{os_grid_reference}?limit=0&start_datetime={data_start_date.isoformat()}&end_datetime={data_end_date.isoformat()}",
headers=HEADERS,
)
print(".", end="", flush=True)
if res.status_code != 200:
print(f"Error: {res.status_code}")
break
# Store the fetched data in a Pandas DataFrame
if energy_data is not None:
energy_data = pd.concat(
[
energy_data,
pd.read_json(io.StringIO(res.text), convert_dates=["data_timestamp"]),
]
)
else:
energy_data = pd.read_json(
io.StringIO(res.text), convert_dates=["data_timestamp"]
)
# Go on to the next day's worth of data
data_start_date = data_end_date
if energy_data is None:
raise Exception("No energy data collected")
print("\nData fetched")
# Keep on the data needed for the heatmap
columns_to_keep = [
"data_timestamp",
"active_device_count",
"active_total_consumption_import",
]
data_grouped = energy_data[columns_to_keep].groupby(["data_timestamp"])
data_grouped = data_grouped.agg(
{
"active_device_count": "sum",
"active_total_consumption_import": "sum",
}
).reset_index()
# Removing data for the last settlement period as it is from 00:00 of the next day
data_grouped.drop(data_grouped.tail(1).index, inplace=True)
# Extract date and hour
data_grouped["date"] = data_grouped["data_timestamp"].dt.date
data_grouped["hour"] = data_grouped["data_timestamp"].dt.hour
# Convert to hourly data
data_grouped_by_hour_date = (
data_grouped.groupby(["hour", "date"])["active_total_consumption_import"]
.sum()
.reset_index()
)
# Reshape into 2D data for the heatmap
heatmap_data = data_grouped_by_hour_date.pivot(
index="hour", columns="date", values="active_total_consumption_import"
)
# Uncomment to use plotly to plot the heatmap
# fig = px.imshow(
# heatmap_data,
# labels=dict(x="Date", y="Hour", color="Energy Consumption (kW)"),
# x=heatmap_data.columns,
# y=heatmap_data.index,
# color_continuous_scale="Reds",
# )
# fig.update_layout(
# title="Energy Consumption (kW) Heatmap for Liverpool",
# xaxis_nticks=len(heatmap_data.columns),
# height=1200,
# width=600,
# )
# fig.show()
# Setup a matplotlib plot with a Seaborn heatmap
plt.figure(figsize=(6, 12))
sns.heatmap(
heatmap_data,
cmap="Reds",
cbar_kws={"label": "Energy Consumption (kW)"},
)
# Set labels and title
plt.title("Energy Consumption (kW) Heatmap for Liverpool")
plt.xlabel("Date")
plt.ylabel("Hour")
# Rotate x-axis and y-axis labels for better visibility
plt.xticks(rotation=50, ha="right")
plt.yticks(rotation=0)
print("Saving figure...")
filename = f"energy_consumption_heatmap_{os_grid_reference}.png"
plt.savefig(f"energy_consumption_heatmap_{os_grid_reference}.png", dpi=300)
print(f"Figure saved to {filename}")