Tutorial Fallback: ES

python-esios: Descarga datos eléctricos españoles en pocas líneas de Python

Una librería Python que envuelve la API de ESIOS en llamadas simples — busca indicadores, descarga datos históricos y obtén DataFrames con caché automático.

python-esios: Descarga datos eléctricos españoles en pocas líneas de Python

El sistema eléctrico español funciona con más de 2.000 indicadores publicados por REE a través de la API de ESIOS — precios, demanda, generación por tecnología, flujos transfronterizos y más. Pero trabajar directamente con la API implica escribir peticiones HTTP repetitivas, gestionar la paginación para rangos largos de fechas y convertir JSON anidado en DataFrames utilizables.

python-esios envuelve todo eso en una interfaz Python limpia. En este artículo recorreremos las funcionalidades principales de la librería y construiremos análisis reales con 4 casos de uso prácticos.

Antes vs después: el momento “aha”

Sin python-esios, descargar una semana de precios de electricidad en España requiere:

# Enfoque con requests: headers manuales, paginación, parsing JSON
import requests
import pandas as pd

TOKEN = "your-token-here"
headers = {
    "Accept": "application/json; application/vnd.esios-api-v1+json",
    "Content-Type": "application/json",
    "Host": "api.esios.ree.es",
    "x-api-key": TOKEN,
}

# También necesitas gestionar el chunking para rangos largos,
# conversión de zona horaria y conversión JSON-a-DataFrame manualmente
response = requests.get(
    "https://api.esios.ree.es/indicators/600",
    headers=headers,
    params={"start_date": "2024-06-01", "end_date": "2024-06-07T23:59:59"},
)
data = response.json()["indicator"]["values"]
df = pd.DataFrame(data)
# Aún falta: parsear datetimes, filtrar por país, configurar el índice...

Con python-esios:

# python-esios: 3 líneas
from esios import ESIOSClient
client = ESIOSClient()
df = client.indicators.get(600).historical("2024-06-01", "2024-06-07")

Diferencias clave:

  • Sin boilerplate — token desde variable de entorno, headers gestionados internamente
  • Chunking automático — los rangos largos se dividen en ventanas compatibles con la API
  • Caché en Parquet — las consultas repetidas se sirven desde caché local al instante
  • DataFrames limpios — DatetimeIndex con zona horaria Europe/Madrid, columnas pivotadas por geografía

Instalación

pip install python-esios

Necesitarás un token de la API de ESIOS. Solicítalo gratuitamente en la página de la API de REE. Configúralo como variable de entorno:

export ESIOS_API_KEY=your-token-here

Explorando el catálogo de ESIOS

La API de ESIOS expone más de 2.000 indicadores. Veamos cómo navegar por ellos.

Listar todos los indicadores

df_indicators = client.indicators.list()
df_indicators[["name", "short_name"]].head(10)
Tabla con 10 filas

Buscar por nombre

client.indicators.search("eólica")
Tabla con 60 filas

Obtener metadatos de un indicador

handle = client.indicators.get(600)
handle
Out
<IndicatorHandle id=600 name='Precio mercado SPOT Diario'>

Cada handle expone las geografías disponibles del indicador:

handle.geos
Out6 lines
[{'geo_id': 1, 'geo_name': 'Portugal'},
 {'geo_id': 2, 'geo_name': 'Francia'},
 {'geo_id': 3, 'geo_name': 'España'},
 {'geo_id': 8826, 'geo_name': 'Alemania'},
 {'geo_id': 8827, 'geo_name': 'Bélgica'},
 {'geo_id': 8828, 'geo_name': 'Países Bajos'}]

Puedes resolver nombres de geografía a IDs:

handle.resolve_geo("España")
Out
3

Caso de uso 1: Precios del mercado diario

El indicador 600 es el precio del mercado SPOT. Comparemos España, Francia y Portugal durante una semana de junio de 2024:

price = client.indicators.get(600)
df_price = price.historical("2024-06-01", "2024-06-07")
df_price = df_price[["España", "Francia", "Portugal"]]
df_price.head()
Tabla con 5 filas
fig = px.line(
    df_price,
    title="Day-ahead electricity prices (June 2024)",
    labels={"value": "€/MWh", "datetime": ""},
)
fig.update_traces(line_shape="hv")
fig.update_layout(legend_title_text="Country")
fig.show()

Estadísticas de precios

df_price.describe().round(2)
Tabla con 8 filas

Caso de uso 2: Demanda en tiempo real

El indicador 1293 registra la demanda real de electricidad con resolución de 5 minutos:

demand = client.indicators.get(1293)
df_demand = demand.historical("2024-06-01", "2024-06-03")
df_demand.head()
Tabla con 5 filas
fig = px.line(
    df_demand,
    title="Real-time electricity demand — Spain (June 2024)",
    labels={"value": "MW", "datetime": ""},
)
fig.update_layout(showlegend=False)
fig.show()

Caso de uso 3: Mix de generación — eólica vs solar

Comparemos la generación programada P48 de eólica y solar fotovoltaica (el último programa antes del tiempo real):

# 82 = Eólica terrestre P48, 84 = Solar fotovoltaica P48
df_gen = client.indicators.compare(
    [82, 84],
    "2024-06-01", "2024-06-07",
)
df_gen.head()
Tabla con 5 filas
fig = px.area(
    df_gen,
    title="Wind vs Solar PV scheduled generation P48 — Spain (June 2024)",
    labels={"value": "MW", "datetime": ""},
)
fig.update_layout(legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="left", x=0), legend_title_text="", title_y=1.0, title_yanchor="top", margin=dict(t=80))
fig.show()

Totales diarios

daily = df_gen.resample("D").sum() / 1000  # Convertir MW·5min a GWh aprox
daily.columns = ["Wind (GWh)", "Solar PV (GWh)"]
daily.round(1)
Tabla con 7 filas

Caso de uso 4: Precio vs demanda

El método compare() facilita combinar varios indicadores en un solo DataFrame. Veamos cómo se relaciona el precio de España con los patrones de demanda:

df_compare = client.indicators.compare(
    [600, 1293],
    "2024-06-01", "2024-06-03",
)
df_compare = df_compare.ffill()  # Forward-fill del precio horario en filas de 5 min
df_compare.head()
Tabla con 5 filas
fig = go.Figure()

fig.add_trace(go.Scatter(
    x=df_compare.index,
    y=df_compare.iloc[:, 0],
    name="Price (€/MWh)",
    yaxis="y",
    line_shape="hv",
))

fig.add_trace(go.Scatter(
    x=df_compare.index,
    y=df_compare.iloc[:, 1],
    name="Demand (MW)",
    yaxis="y2",
    opacity=0.6,
))

fig.update_layout(
    title="Price vs Demand — Spain (June 2024)",
    yaxis=dict(title="€/MWh"),
    yaxis2=dict(title="MW", overlaying="y", side="right"),
    legend=dict(x=0.01, y=0.99),
)
fig.show()

Conclusiones

python-esios convierte la API de ESIOS en una interfaz Pythónica:

  • client.indicators.list() — explora el catálogo completo
  • client.indicators.search("...") — busca indicadores por nombre
  • client.indicators.get(id).historical(start, end) — descarga datos como DataFrames
  • client.indicators.compare([...], start, end) — combina múltiples indicadores
  • Caché automático — archivos Parquet para consultas repetidas al instante
  • Resolución geográfica — resolve_geo("España") en vez de memorizar IDs

Para más detalles, consulta el repositorio en GitHub.

Recursos

Table of Contents
Search sections

We use cookies to improve your experience and analyze site usage. You can manage your preferences at any time.