Wind Data Examples
These examples demonstrate how to retrieve and process wind speed data from Jua using two different access methods: the REST API for point forecasts and direct Zarr file access for gridded data.
Wind Data via REST API
This example shows how to fetch 100m wind speed forecasts for multiple specific locations (German cities) using the Jua REST API. This method is ideal for querying a limited number of points.
Dependencies
This script requires the following Python packages:
pandas
requests
Setting up Authentication
The script requires your Jua API Key ID and Secret to be available as environment variables for constructing the X-API-Key
header.
import os
# Retrieve credentials from environment variables
API_KEY_ID = os.environ["JUA_API_KEY_ID"]
API_SECRET = os.environ["JUA_API_SECRET"]
# Create the authentication header required by the REST API
AUTH_HEADER = {"X-API-Key": f"{API_KEY_ID}:{API_SECRET}"}
# NB: It may take up to 5 minutes for new API keys to be deployed.
# In the meantime, you may get unauthorized errors (HTTP 401).
Script
This script defines locations, sends a POST request to the API, and processes the JSON response into a Pandas DataFrame.
import os
import requests
import pandas as pd
from datetime import datetime, timezone, timedelta
# --- Authentication Setup ---
API_KEY_ID = os.environ["JUA_API_KEY_ID"]
API_SECRET = os.environ["JUA_API_SECRET"]
AUTH_HEADER = {"X-API-Key": f"{API_KEY_ID}:{API_SECRET}"}
# --- Configuration ---
# Define locations of interest (City Name: (Latitude, Longitude))
locations = {
"Hamburg": (53.5488, 9.9872),
"Berlin": (52.52, 13.40),
"Munich": (48.1351, 11.5820),
"Frankfurt": (50.1109, 8.6821),
}
# API endpoint for the latest EPT 1.5km forecast
api_url = "https://api.jua.ai/v1/forecasting/ept1_5/forecasts/latest"
# Request parameters
request_payload = {
"min_lead_time": 0, # Start from the initialization time
"max_lead_time": 12, # Get forecasts up to 12 hours ahead
"points": [
{"lat": lat, "lon": lon, "name": name}
for name, (lat, lon) in locations.items()
],
"variables": ["wind_speed_100m"], # Request 100m wind speed
}
# --- API Request ---
print(f"Requesting data from {api_url}...")
response = requests.post(
api_url,
json=request_payload,
headers=AUTH_HEADER,
)
response.raise_for_status() # Raise an exception for bad status codes (4xx or 5xx)
data = response.json()
print("Data received successfully.")
# --- Data Processing ---
# Extract forecast initialization time and convert to datetime object
init_time = datetime.fromisoformat(data["init_time"].replace("Z", "+00:00"))
# Process the results into a more usable format (list of dictionaries)
processed_data = []
for point_data in data["points"]:
point_name = point_data.get("name", f"{point_data['returned_latlon'][0]},{point_data['returned_latlon'][1]}")
returned_lat, returned_lon = point_data["returned_latlon"]
wind_speeds = point_data["variables"]["wind_speed_100m"]["values"]
for i, speed in enumerate(wind_speeds):
# Calculate the valid time for this forecast step
# Assuming lead times are hourly starting from init_time + min_lead_time
# Check API documentation for exact time handling if min_lead_time changes
lead_hour = request_payload["min_lead_time"] + i
valid_time = init_time + timedelta(hours=lead_hour)
processed_data.append(
{
"Location": point_name,
"Latitude": returned_lat,
"Longitude": returned_lon,
"ValidTime_UTC": valid_time,
"LeadTime_Hours": lead_hour,
"WindSpeed_100m_mps": speed, # m/s is the standard unit
}
)
# Convert the processed data into a Pandas DataFrame
wind_speeds_df = pd.DataFrame(processed_data)
# --- Output ---
print(f"\nWind speed forecast (Init: {init_time.strftime('%Y-%m-%d %H:%M UTC')}):")
print(wind_speeds_df)
Key Concepts Demonstrated
Authenticating REST API requests using an
X-API-Key
header.Constructing a POST request payload to specify multiple locations, variables, and time ranges.
Handling potential API errors using
response.raise_for_status()
.Parsing the JSON response structure, including initialization time and point-specific data.
Calculating valid forecast timestamps based on initialization time and lead hours.
Structuring the extracted data into a Pandas DataFrame for analysis.
Wind Data via Zarr Files
This alternative approach shows how to retrieve 100m wind speed data (100si
) for the same locations using direct access to Zarr files via xarray
. This method is better suited for accessing larger amounts of gridded data or specific historical forecasts.
Dependencies
This script requires the following Python packages:
aiohttp
xarray >= 2023.6.0 # Ensure version supports decode_timedelta=False with zarr
zarr
pandas # Used only for displaying the final DataFrame
Setting up Authentication
The script requires your Jua API Key ID and Secret to be available as environment variables for aiohttp.BasicAuth
used by xarray
's storage options.
import os
from aiohttp import BasicAuth
# Retrieve credentials from environment variables
API_KEY_ID = os.environ["JUA_API_KEY_ID"]
API_SECRET = os.environ["JUA_API_SECRET"]
# Create authentication object for xarray's storage_options
AUTH = BasicAuth(login=API_KEY_ID, password=API_SECRET)
# NB: It may take up to 5 minutes for new API keys to be deployed.
# In the meantime, you may get unauthorized errors.
Script
This script constructs URLs for multiple Zarr files corresponding to different lead times for a specific forecast initialization, opens them as a single dataset using xr.open_mfdataset
, selects the desired variable and locations, and computes the result.
import xarray as xr
from aiohttp import BasicAuth
import os
import time
import pandas as pd # Only for final display
# --- Authentication Setup ---
API_KEY_ID = os.environ["JUA_API_KEY_ID"]
API_SECRET = os.environ["JUA_API_SECRET"]
AUTH = BasicAuth(login=API_KEY_ID, password=API_SECRET)
# --- Configuration ---
# Use today's 00Z initialization time (adjust if needed)
init_time_str = time.strftime("%Y%m%d00")
# Define lead times: e.g., every 6 hours for the first 24 hours
lead_times = list(range(0, 25, 6))
# Define locations of interest (Latitude, Longitude)
# Note: Order matters for direct list selection in .sel
lats = [53.5488, 52.5200, 48.1351, 50.1109] # Hamburg, Berlin, Munich, Frankfurt
longs = [9.9872, 13.4050, 11.5820, 8.6821]
location_names = ["Hamburg", "Berlin", "Munich", "Frankfurt"]
# --- Data Loading ---
# Construct URLs for each forecast lead time Zarr file
forecast_urls = [
f"https://data.jua.ai/forecasts/ept-1.5/{init_time_str}/{lead_time}.zarr"
for lead_time in lead_times
]
print(f"Opening {len(forecast_urls)} Zarr datasets for init {init_time_str}...")
# Open multiple Zarr datasets efficiently as a single xarray Dataset
ds = xr.open_mfdataset(
forecast_urls,
parallel=True, # Use dask for parallel loading if available
engine="zarr",
consolidated=True, # Use consolidated metadata if available
decode_timedelta=False, # Keep prediction_timedelta as numeric hours
storage_options={"auth": AUTH}, # Pass authentication
)
print("Datasets opened.")
# --- Data Selection & Processing ---
# Select the '100si' variable (100m wind speed)
# Select the nearest grid points for the specified latitudes and longitudes
wind_speeds_da = ds["100si"].sel(
latitude=xr.DataArray(lats, dims="location"),
longitude=xr.DataArray(longs, dims="location"),
method="nearest"
)
# Load the data into memory (computes the result)
print("Selecting points and computing data...")
wind_speeds_computed = wind_speeds_da.compute()
print("Computation complete.")
# --- Final Output ---
# Convert to DataFrame for display
wind_speeds_df = wind_speeds_computed.to_dataframe()
# Add location names for clarity (optional)
# This requires careful index matching if the original dims were kept
# Resetting index makes it easier
wind_speeds_df = wind_speeds_df.reset_index()
# Calculate valid time (similar to API example, using the dataset's time coordinate)
wind_speeds_df["ValidTime_UTC"] = pd.to_datetime(wind_speeds_df["time"]) + pd.to_timedelta(
wind_speeds_df["prediction_timedelta"], unit="h"
)
# Map integer location index back to names if needed, or handle differently
# For simplicity, let's just print the DataFrame as is after time calc
final_df = wind_speeds_df[['time', 'prediction_timedelta', 'latitude', 'longitude', '100si', 'ValidTime_UTC']]
print(f"\nWind speed forecast from Zarr (Init: {init_time_str}):")
print(final_df)
# Close the dataset
ds.close()
Key Concepts Demonstrated
Authenticating direct Zarr access using
aiohttp.BasicAuth
withinxarray.open_mfdataset
'sstorage_options
.Constructing URLs for specific forecast initializations and lead time Zarr files.
Opening multiple remote Zarr files as a single virtual dataset using
xr.open_mfdataset
.Selecting data for multiple specific latitude/longitude points from gridded data using
xarray.sel
withmethod="nearest"
.Leveraging Dask for parallel computation via
parallel=True
and.compute()
.Extracting and processing the resulting
xarray.DataArray
, including converting to a Pandas DataFrame and calculating valid timestamps.
</rewritten_file>
Last updated