aemetxfb.pred

Prediction (hourly forecast) module.

Prediction module for AEMet data.

This module provides access to weather forecast data and station lookup utilities for the Spanish national weather service (AEMet).

class aemetxfb.pred.Forecast(xml_text)[source]

Bases: object

Parsed hourly forecast for a single municipality.

Holds metadata, sunrise/sunset times, hourly observations, and 6-hourly probability blocks. All data is exposed via typed getter methods that return either scalars, dicts, or pd.DataFrame instances.

Parameters:

xml_text (str) – Raw XML content from the AEMet hourly forecast endpoint.

Raises:

ValueError – If the XML cannot be parsed or is missing required elements.

get_metadata(key=None)[source]

Return forecast metadata.

Parameters:

key (str or None) – If None, return the full metadata dictionary. If a string, return the value for that specific key (e.g. "name", "link", "province").

Returns:

Full metadata dict when key is None; otherwise the value associated with key.

Return type:

dict or scalar

Raises:

KeyError – If key is not found in the metadata.

Examples

>>> forecast.get_metadata()
{'id': '50130', 'name': 'Jarque', ...}
>>> forecast.get_metadata("link")
'https://www.aemet.es/...'
get_sunrise_sunset()[source]

Return sunrise and sunset times for each forecast day.

Returns:

Columns: date (date), sunrise (time), sunset (time).

Return type:

pd.DataFrame

Examples

>>> forecast.get_sunrise_sunset()
          date sunrise    sunset
0  2026-06-24  06:33:00  21:45:00
1  2026-06-25  06:33:00  21:45:00
2  2026-06-26  06:33:00  21:45:00
get_hourly(variable=None)[source]

Return hourly forecast data.

Parameters:

variable (str or None) –

If None, return all hourly columns. If a string, return only date, hour, and the requested variable column.

Accepted values (case-insensitive):

  • "temperature", "apparent_temperature"

  • "humidity", "relative_humidity"

  • "precipitation", "rain"

  • "snow"

  • "wind_direction", "wind_speed", "gust", "gust_speed"

  • "sky", "sky_code", "sky_description", "weather"

Returns:

Full hourly data or filtered subset.

Return type:

pd.DataFrame

Raises:

ValueError – If variable is not recognised.

Examples

>>> forecast.get_hourly("temperature")
           date  hour  temperature
0   2026-06-24      9         26.0
1   2026-06-24     10         29.0
...
get_probability(variable=None)[source]

Return 6-hourly probability data.

Parameters:

variable (str or None) –

If None, return all probability types (wide format with one column per type). If a string, return only that type.

Accepted values (case-insensitive):

  • "precipitation", "rain"

  • "storm", "thunderstorm"

  • "snow"

Returns:

When variable is None: columns date, period, precipitation, storm, snow (pivoted wide format).

When variable is given: columns date, period, probability.

Return type:

pd.DataFrame

Raises:

ValueError – If variable is not recognised.

Examples

>>> forecast.get_probability()
           date period  precipitation  storm  snow
0   2026-06-24   0814              0      0     0
...
>>> forecast.get_probability("storm")
           date period  probability
0   2026-06-24   0814            0
...
aemetxfb.pred.find_nearest_location(lat, lon)[source]

Find the prediction station closest to the given coordinates.

Uses vectorised numpy operations to compute Euclidean distance on the lat/lon grid and return the ID of the nearest station.

Parameters:
  • lat (float) – Latitude in decimal degrees.

  • lon (float) – Longitude in decimal degrees.

Returns:

The ID of the nearest station (e.g. "id01001").

Return type:

str

Raises:

ValueError – If the station registry is empty.

Examples

>>> find_nearest_location(40.4168, -3.7038)  # Madrid city centre
'id28079'
aemetxfb.pred.get_forecast(lat_or_name, lon=None)[source]

Fetch the hourly forecast for a Spanish municipality.

Accepts either a municipality name (string) or coordinates (lat/lon as floats).

Resolution strategy:

  1. If lat_or_name is a string, look up the station by name (exact or substring match, case-insensitive).

  2. If lat_or_name is a number, resolve the nearest station via find_nearest_location() using lat_or_name and lon.

Parameters:
  • lat_or_name (str or float) – Municipality name (e.g. "Madrid") or latitude in decimal degrees.

  • lon (float or None) – Longitude in decimal degrees. Required when lat_or_name is a number; ignored when it is a string.

Returns:

Parsed forecast object with query methods.

Return type:

Forecast

Raises:
  • ValueError – If no municipality matches the given name, if the name is ambiguous, or if coordinates are incomplete.

  • RuntimeError – If the XML cannot be fetched or parsed.

Examples

>>> forecast = get_forecast("Madrid")
>>> forecast.get_metadata("name")
'Madrid'
>>> forecast = get_forecast(40.4168, -3.7038)
>>> forecast.get_hourly("temperature").head(3)
aemetxfb.pred.get_predicted_stations()[source]

Return all prediction stations.

Data is loaded lazily from stations.json and cached after the first call so that subsequent accesses are instant.

Returns:

Mapping of station ID to {"name": ..., "lat": ..., "lon": ...}.

Return type:

dict[str, dict]

Examples

>>> stations = get_predicted_stations()
>>> "id01001" in stations
True
>>> stations["id01001"]["name"]
'Alegría-Dulantzi'

aemetxfb.pred.pred

Core forecast parsing and factory function.

Hourly weather forecasts for Spanish municipalities from AEMet XML API.

This module fetches the hourly forecast XML for a given municipality ID and exposes it through a Forecast object with convenient query methods.

Examples

>>> forecast = get_forecast("Madrid")
>>> forecast.get_metadata("name")
'Madrid'
>>> forecast = get_forecast(40.4168, -3.7038)
>>> forecast.get_hourly("temperature").head()
>>> forecast.get_probability("precipitation")
class aemetxfb.pred.pred.Forecast(xml_text)[source]

Bases: object

Parsed hourly forecast for a single municipality.

Holds metadata, sunrise/sunset times, hourly observations, and 6-hourly probability blocks. All data is exposed via typed getter methods that return either scalars, dicts, or pd.DataFrame instances.

Parameters:

xml_text (str) – Raw XML content from the AEMet hourly forecast endpoint.

Raises:

ValueError – If the XML cannot be parsed or is missing required elements.

get_metadata(key=None)[source]

Return forecast metadata.

Parameters:

key (str or None) – If None, return the full metadata dictionary. If a string, return the value for that specific key (e.g. "name", "link", "province").

Returns:

Full metadata dict when key is None; otherwise the value associated with key.

Return type:

dict or scalar

Raises:

KeyError – If key is not found in the metadata.

Examples

>>> forecast.get_metadata()
{'id': '50130', 'name': 'Jarque', ...}
>>> forecast.get_metadata("link")
'https://www.aemet.es/...'
get_sunrise_sunset()[source]

Return sunrise and sunset times for each forecast day.

Returns:

Columns: date (date), sunrise (time), sunset (time).

Return type:

pd.DataFrame

Examples

>>> forecast.get_sunrise_sunset()
          date sunrise    sunset
0  2026-06-24  06:33:00  21:45:00
1  2026-06-25  06:33:00  21:45:00
2  2026-06-26  06:33:00  21:45:00
get_hourly(variable=None)[source]

Return hourly forecast data.

Parameters:

variable (str or None) –

If None, return all hourly columns. If a string, return only date, hour, and the requested variable column.

Accepted values (case-insensitive):

  • "temperature", "apparent_temperature"

  • "humidity", "relative_humidity"

  • "precipitation", "rain"

  • "snow"

  • "wind_direction", "wind_speed", "gust", "gust_speed"

  • "sky", "sky_code", "sky_description", "weather"

Returns:

Full hourly data or filtered subset.

Return type:

pd.DataFrame

Raises:

ValueError – If variable is not recognised.

Examples

>>> forecast.get_hourly("temperature")
           date  hour  temperature
0   2026-06-24      9         26.0
1   2026-06-24     10         29.0
...
get_probability(variable=None)[source]

Return 6-hourly probability data.

Parameters:

variable (str or None) –

If None, return all probability types (wide format with one column per type). If a string, return only that type.

Accepted values (case-insensitive):

  • "precipitation", "rain"

  • "storm", "thunderstorm"

  • "snow"

Returns:

When variable is None: columns date, period, precipitation, storm, snow (pivoted wide format).

When variable is given: columns date, period, probability.

Return type:

pd.DataFrame

Raises:

ValueError – If variable is not recognised.

Examples

>>> forecast.get_probability()
           date period  precipitation  storm  snow
0   2026-06-24   0814              0      0     0
...
>>> forecast.get_probability("storm")
           date period  probability
0   2026-06-24   0814            0
...
aemetxfb.pred.pred.get_forecast(lat_or_name, lon=None)[source]

Fetch the hourly forecast for a Spanish municipality.

Accepts either a municipality name (string) or coordinates (lat/lon as floats).

Resolution strategy:

  1. If lat_or_name is a string, look up the station by name (exact or substring match, case-insensitive).

  2. If lat_or_name is a number, resolve the nearest station via find_nearest_location() using lat_or_name and lon.

Parameters:
  • lat_or_name (str or float) – Municipality name (e.g. "Madrid") or latitude in decimal degrees.

  • lon (float or None) – Longitude in decimal degrees. Required when lat_or_name is a number; ignored when it is a string.

Returns:

Parsed forecast object with query methods.

Return type:

Forecast

Raises:
  • ValueError – If no municipality matches the given name, if the name is ambiguous, or if coordinates are incomplete.

  • RuntimeError – If the XML cannot be fetched or parsed.

Examples

>>> forecast = get_forecast("Madrid")
>>> forecast.get_metadata("name")
'Madrid'
>>> forecast = get_forecast(40.4168, -3.7038)
>>> forecast.get_hourly("temperature").head(3)

aemetxfb.pred._stations

Station registry with lazy loading and vectorised nearest-neighbour search.

Prediction station registry with lazy loading and vectorised search.

Stations are stored in stations.json (shipped with the package) and loaded on first access. Latitude and longitude columns are cached as numpy arrays so that nearest-neighbour searches use vectorised operations instead of a Python loop.

aemetxfb.pred._stations._load_stations()[source]

Load station data from JSON and build numpy arrays (lazy, cached).

Returns:

(stations_dict, lat_array, lon_array, ids_list). The dict is the full registry; the arrays and list are aligned by position so that lat_array[i], lon_array[i] and ids_list[i] refer to the same station.

Return type:

tuple

aemetxfb.pred._stations.get_predicted_stations()[source]

Return all prediction stations.

Data is loaded lazily from stations.json and cached after the first call so that subsequent accesses are instant.

Returns:

Mapping of station ID to {"name": ..., "lat": ..., "lon": ...}.

Return type:

dict[str, dict]

Examples

>>> stations = get_predicted_stations()
>>> "id01001" in stations
True
>>> stations["id01001"]["name"]
'Alegría-Dulantzi'
aemetxfb.pred._stations.find_nearest_location(lat, lon)[source]

Find the prediction station closest to the given coordinates.

Uses vectorised numpy operations to compute Euclidean distance on the lat/lon grid and return the ID of the nearest station.

Parameters:
  • lat (float) – Latitude in decimal degrees.

  • lon (float) – Longitude in decimal degrees.

Returns:

The ID of the nearest station (e.g. "id01001").

Return type:

str

Raises:

ValueError – If the station registry is empty.

Examples

>>> find_nearest_location(40.4168, -3.7038)  # Madrid city centre
'id28079'
aemetxfb.pred._stations._find_station_by_name(name)[source]

Find a prediction station by its municipality name (internal).

Search strategy (case-insensitive):

  1. Exact match — if a single station name matches exactly, return it.

  2. Substring match — if no exact match, return the first station whose name contains the query string.

Parameters:

name (str) – Municipality name (e.g. "Madrid", "zaragoza", "jarque"). Matching is case-insensitive.

Returns:

The ID of the matched station (e.g. "id28079").

Return type:

str

Raises:

ValueError – If no station matches or if the name is ambiguous (multiple exact matches).