Global Weather Forecast Time Lapses with geeViz

This notebook demonstrates how to visualize weather forecast data from multiple global models using geeViz.geeView time-lapse features.

Model

Collection

Type

Resolution

Forecast Range

Time Step

NOAA GFS

NOAA/GFS0P25

Deterministic

0.25°

384h (16 days)

3-6h

ECMWF IFS

ECMWF/NRT_FORECAST/IFS/OPER

Deterministic

0.25°

240h (10 days)

3h

WeatherNext Graph

projects/gcp-public-data-weathernext/assets/59572747_4_0

Deterministic (AI)

0.25°

240h (10 days)

6h

WeatherNext 2

projects/gcp-public-data-weathernext/assets/weathernext_2_0_0

64-member Ensemble (AI)

0.25°

360h (15 days)

6h

Each section loads the most recent model run and adds time-lapse layers for temperature, precipitation, wind, pressure, and upper-air fields.

Copyright 2026 Ian Housman

Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

import os, sys, math, datetime

try:
    import geeViz.getImagesLib as gil
except:
    !python -m pip install geeViz
    import geeViz.getImagesLib as gil

import geeViz.geeView as gv
import geeViz.geePalettes as palettes

ee = gv.ee
Map = gv.Map
Map.clearMap()

today = ee.Date(datetime.datetime.now())
print('Imports ready')

Common Settings

  • Shared palettes, unit conversions, and visualization parameters used across all models

  • Forecast window: first 5 days (120 hours) at 6-hour intervals

  • All temperatures converted from Kelvin to Celsius

  • All wind speeds converted from m/s to km/h

# Forecast hours to display (every 6 hours for 5 days)
which_hours_6h = list(range(6, 120 + 1, 6))    # for 6h-step models
which_hours_3h = list(range(3, 120 + 1, 3))    # for 3h-step models (GFS, ECMWF)

# --- Palettes ---
cmOceanThermal = palettes.cmocean['Thermal'][7]
cmOceanSpeed   = palettes.cmocean['Speed'][7]
cmOceanTempo   = palettes.cmocean['Tempo'][7]
cmOceanDeep    = palettes.cmocean['Deep'][7]

# Circular wind direction palette
windDirPalette = list(cmOceanDeep) + list(reversed(cmOceanDeep))

# Precipitation: white -> blue -> purple
precipPalette = ['ffffff', 'c6dbef', '9ecae1', '6baed6', '3182bd', '08519c', '4a1486']

# Pressure: blue (low) -> white -> red (high)
mslpPalette = ['08306b', '2171b5', '6baed6', 'c6dbef', 'fcbba1', 'fb6a4a', 'cb181d', '67000d']

# Inferno for ensemble spread / uncertainty
spreadPalette = ['000004', '420a68', '932667', 'dd513a', 'fca50a', 'fcffa4']

# SST: ocean thermal
sstPalette = ['03045e', '0077b6', '00b4d8', '90e0ef', 'caf0f8', 'fef9ef', 'fed9b7', 'f07167', 'd62828']

# 500 hPa heights
z500Palette = ['08306b', '2171b5', '6baed6', 'c6dbef', 'fee0d2', 'fc9272', 'de2d26', 'a50f15']

# --- Helper functions ---
def wind_speed_direction(img, u_band, v_band):
    """Compute wind speed (km/h) and direction (degrees) from u/v components."""
    u = img.select([u_band])
    v = img.select([v_band])
    speed = u.hypot(v).multiply(3.6)  # m/s -> km/h
    direction = u.atan2(v).divide(math.pi).add(1).multiply(180)
    return img.addBands(
        ee.Image.cat([speed, direction]).rename(['Speed', 'Direction'])
    ).copyProperties(img, img.propertyNames())

print('Palettes and helpers ready')

1. NOAA GFS (Global Forecast System)

  • Operational NWP model from NCEP, 0.25° resolution

  • Deterministic forecast out to 384 hours (16 days)

  • 3-hour time steps (first 120h), 12-hour steps beyond

  • Band naming convention: variable_level (e.g. temperature_2m_above_ground)

  • Initialization via creation_time property (epoch ms)

print('Loading GFS...')
gfs_raw = (
    ee.ImageCollection('NOAA/GFS0P25')
    .filter(ee.Filter.gt('creation_time', today.advance(-1, 'day').millis()))
)

# Most recent model run
gfs_init = ee.Number.parse(
    gfs_raw.aggregate_histogram('creation_time').keys().reduce(ee.Reducer.max())
)
gfs = (
    gfs_raw
    .filter(ee.Filter.eq('creation_time', gfs_init))
    .filter(ee.Filter.inList('forecast_hours', which_hours_3h))
)

gfs_proj = gfs.first().projection().getInfo()
gfs_crs = gfs_proj['wkt']

# Common viz params for GFS layers
gfs_viz = {
    'dateFormat': 'YY-MM-dd HH',
    'advanceInterval': 'hour',
    'canAreaChart': True,
    'areaChartParams': {'scale': 27830, 'crs': gfs_crs, 'minZoomSpecifiedScale': 5},
    'reducer': ee.Reducer.mean(),
}

# Wind speed + direction
gfs_wind = gfs.map(
    lambda img: wind_speed_direction(img, 'u_component_of_wind_10m_above_ground', 'v_component_of_wind_10m_above_ground')
)

print(f'GFS images: {gfs.size().getInfo()}')

# --- Add GFS layers ---
Map.addTimeLapse(
    gfs.select(['temperature_2m_above_ground']),
    {**gfs_viz, 'min': -20, 'max': 40, 'palette': cmOceanThermal,
     'legendLabelLeftAfter': 'C', 'legendLabelRightAfter': 'C'},
    'GFS: Temperature (2m)',
)

Map.addTimeLapse(
    gfs.select(['precipitable_water_entire_atmosphere']),
    {**gfs_viz, 'min': 0, 'max': 30, 'palette': cmOceanTempo,
     'legendLabelLeftAfter': 'kg/m²', 'legendLabelRightAfter': 'kg/m²'},
    'GFS: Precipitable Water',
)

Map.addTimeLapse(
    gfs_wind.select(['Speed']),
    {**gfs_viz, 'min': 0, 'max': 60, 'palette': cmOceanSpeed,
     'legendLabelLeftAfter': 'km/h', 'legendLabelRightAfter': 'km/h'},
    'GFS: Wind Speed (10m)',
)

Map.addTimeLapse(
    gfs_wind.select(['Direction']),
    {**gfs_viz, 'min': 0, 'max': 360, 'palette': windDirPalette,
     'legendLabelLeftAfter': 'deg', 'legendLabelRightAfter': 'deg'},
    'GFS: Wind Direction (10m)',
)

print('GFS layers added')

2. ECMWF IFS (European Centre for Medium-Range Weather Forecasts)

  • Widely regarded as the world’s best operational NWP model

  • Deterministic high-resolution forecast, 0.25° resolution

  • 3-hour time steps out to 240 hours (10 days)

  • Band naming convention: variable_surface or variable_plXXX for pressure levels

  • Initialization via creation_time property (epoch ms)

  • Includes pressure-level fields (divergence, vorticity, geopotential height)

print('Loading ECMWF IFS...')
ecmwf_raw = (
    ee.ImageCollection('ECMWF/NRT_FORECAST/IFS/OPER')
    .filter(ee.Filter.gt('creation_time', today.advance(-1, 'day').millis()))
)

# Most recent model run
ecmwf_init = ee.Number.parse(
    ecmwf_raw.aggregate_histogram('creation_time').keys().reduce(ee.Reducer.max())
)
ecmwf = (
    ecmwf_raw
    .filter(ee.Filter.eq('creation_time', ecmwf_init))
    .filter(ee.Filter.inList('forecast_hours', which_hours_3h))
)

ecmwf_viz = {
    'dateFormat': 'YY-MM-dd HH',
    'advanceInterval': 'hour',
    'canAreaChart': True,
    'areaChartParams': {'scale': 27830, 'crs': gfs_crs, 'minZoomSpecifiedScale': 5},
    'reducer': ee.Reducer.mean(),
}

# Wind speed + direction
ecmwf_wind = ecmwf.map(
    lambda img: wind_speed_direction(img, 'u_component_of_wind_10m_sfc', 'v_component_of_wind_10m_sfc')
)

print(f'ECMWF images: {ecmwf.size().getInfo()}')

# --- Add ECMWF layers ---
# Temperature (already in Kelvin for ECMWF, convert to C)
ecmwf_temp = ecmwf.map(
    lambda img: img.select(['temperature_2m_sfc']).subtract(273.15)
        .rename(['Temperature_C']).copyProperties(img, img.propertyNames())
)
Map.addTimeLapse(
    ecmwf_temp,
    {**ecmwf_viz, 'min': -20, 'max': 45, 'palette': cmOceanThermal,
     'legendLabelLeftAfter': 'C', 'legendLabelRightAfter': 'C'},
    'ECMWF: Temperature (2m)',
)

# Total precipitation (meters -> mm)
ecmwf_precip = ecmwf.map(
    lambda img: img.select(['total_precipitation_sfc']).multiply(1000)
        .rename(['Precip_mm']).copyProperties(img, img.propertyNames())
)
Map.addTimeLapse(
    ecmwf_precip,
    {**ecmwf_viz, 'min': 0, 'max': 50, 'palette': precipPalette,
     'legendLabelLeftAfter': 'mm', 'legendLabelRightAfter': 'mm'},
    'ECMWF: Total Precipitation',
)

Map.addTimeLapse(
    ecmwf_wind.select(['Speed']),
    {**ecmwf_viz, 'min': 0, 'max': 80, 'palette': cmOceanSpeed,
     'legendLabelLeftAfter': 'km/h', 'legendLabelRightAfter': 'km/h'},
    'ECMWF: Wind Speed (10m)',
)

# Mean sea level pressure (Pa -> hPa)
ecmwf_mslp = ecmwf.map(
    lambda img: img.select(['mean_sea_level_pressure_sfc']).divide(100)
        .rename(['MSLP_hPa']).copyProperties(img, img.propertyNames())
)
Map.addTimeLapse(
    ecmwf_mslp,
    {**ecmwf_viz, 'min': 980, 'max': 1040, 'palette': mslpPalette,
     'legendLabelLeftAfter': 'hPa', 'legendLabelRightAfter': 'hPa'},
    'ECMWF: Sea Level Pressure',
)

# 500 hPa geopotential height (already in meters for ECMWF)
Map.addTimeLapse(
    ecmwf.select(['geopotential_height_pl500']),
    {**ecmwf_viz, 'min': 4800, 'max': 5900, 'palette': z500Palette,
     'legendLabelLeftAfter': 'm', 'legendLabelRightAfter': 'm'},
    'ECMWF: 500 hPa Height',
)

# Dewpoint temperature (K -> C) — useful for moisture analysis
ecmwf_dew = ecmwf.map(
    lambda img: img.select(['dewpoint_temperature_2m_sfc']).subtract(273.15)
        .rename(['Dewpoint_C']).copyProperties(img, img.propertyNames())
)
Map.addTimeLapse(
    ecmwf_dew,
    {**ecmwf_viz, 'min': -30, 'max': 25, 'palette': cmOceanTempo,
     'legendLabelLeftAfter': 'C', 'legendLabelRightAfter': 'C'},
    'ECMWF: Dewpoint Temperature (2m)',
)

print('ECMWF layers added')

3. WeatherNext Graph — Deterministic AI Forecast

  • Google’s GraphCast-based AI weather model

  • Single deterministic run (no ensemble members)

  • 6-hour time steps out to 240 hours (10 days)

  • Initialization via start_time property (ISO 8601 string)

  • Bands use ERA5-style naming: 2m_temperature, 10m_u_component_of_wind, etc.

  • Includes pressure-level fields at 13 levels (50-1000 hPa)

print('Loading WeatherNext Graph (deterministic)...')

def wn_prep(img):
    """Set system:time_start to forecast valid time for WeatherNext."""
    start = ee.Date(img.get('start_time'))
    fh = ee.Number(img.get('forecast_hour'))
    return img.set('system:time_start', start.advance(fh, 'hour').millis())

graph_raw = (
    ee.ImageCollection('projects/gcp-public-data-weathernext/assets/59572747_4_0')
    .filter(ee.Filter.gt('system:time_start', today.advance(-12, 'hour').millis()))
    .filter(ee.Filter.inList('forecast_hour', which_hours_6h))
)
graph_init = graph_raw.aggregate_array('start_time').distinct().sort().get(-1)
graph = graph_raw.filter(ee.Filter.eq('start_time', graph_init)).map(wn_prep)

wn_viz = {
    'dateFormat': 'YY-MM-dd HH',
    'advanceInterval': 'hour',
    'canAreaChart': True,
    'areaChartParams': {'scale': 27830, 'crs': gfs_crs, 'minZoomSpecifiedScale': 5},
    'reducer': ee.Reducer.mean(),
}

# Temperature (K -> C)
graph_temp = graph.map(
    lambda img: img.select(['2m_temperature']).subtract(273.15)
        .rename(['Temperature_C']).copyProperties(img, img.propertyNames())
)

# Wind
graph_wind = graph.map(
    lambda img: wind_speed_direction(img, '10m_u_component_of_wind', '10m_v_component_of_wind')
)

# Precipitation (m -> mm)
graph_precip = graph.map(
    lambda img: img.select(['total_precipitation_6hr']).multiply(1000)
        .rename(['Precip_mm']).copyProperties(img, img.propertyNames())
)

# MSLP (Pa -> hPa)
graph_mslp = graph.map(
    lambda img: img.select(['mean_sea_level_pressure']).divide(100)
        .rename(['MSLP_hPa']).copyProperties(img, img.propertyNames())
)

# 500 hPa height (geopotential / g)
graph_z500 = graph.map(
    lambda img: img.select(['500_geopotential']).divide(9.80665)
        .rename(['Z500_m']).copyProperties(img, img.propertyNames())
)

# SST (K -> C)
graph_sst = graph.map(
    lambda img: img.select(['sea_surface_temperature']).subtract(273.15)
        .rename(['SST_C']).copyProperties(img, img.propertyNames())
)

print(f'Graph images: {graph.size().getInfo()}')

# --- Add Graph layers ---
Map.addTimeLapse(graph_temp, {**wn_viz, 'min': -20, 'max': 45, 'palette': cmOceanThermal,
    'legendLabelLeftAfter': 'C', 'legendLabelRightAfter': 'C'}, 'WN Graph: Temperature (2m)')

Map.addTimeLapse(graph_precip, {**wn_viz, 'min': 0, 'max': 30, 'palette': precipPalette,
    'legendLabelLeftAfter': 'mm', 'legendLabelRightAfter': 'mm'}, 'WN Graph: Precipitation (6hr)')

Map.addTimeLapse(graph_wind.select(['Speed']), {**wn_viz, 'min': 0, 'max': 80, 'palette': cmOceanSpeed,
    'legendLabelLeftAfter': 'km/h', 'legendLabelRightAfter': 'km/h'}, 'WN Graph: Wind Speed (10m)')

Map.addTimeLapse(graph_wind.select(['Direction']), {**wn_viz, 'min': 0, 'max': 360, 'palette': windDirPalette,
    'legendLabelLeftAfter': 'deg', 'legendLabelRightAfter': 'deg'}, 'WN Graph: Wind Direction (10m)')

Map.addTimeLapse(graph_mslp, {**wn_viz, 'min': 980, 'max': 1040, 'palette': mslpPalette,
    'legendLabelLeftAfter': 'hPa', 'legendLabelRightAfter': 'hPa'}, 'WN Graph: Sea Level Pressure')

Map.addTimeLapse(graph_z500, {**wn_viz, 'min': 4800, 'max': 5900, 'palette': z500Palette,
    'legendLabelLeftAfter': 'm', 'legendLabelRightAfter': 'm'}, 'WN Graph: 500 hPa Height')

Map.addTimeLapse(graph_sst, {**wn_viz, 'min': -2, 'max': 32, 'palette': sstPalette,
    'legendLabelLeftAfter': 'C', 'legendLabelRightAfter': 'C'}, 'WN Graph: Sea Surface Temperature')

print('WeatherNext Graph layers added')

4. WeatherNext 2 — 64-Member Ensemble

  • Google’s ensemble AI weather model with 64 members

  • Each member is a plausible forecast trajectory

  • By computing mean and standard deviation across members we get:

    • Ensemble mean: best-estimate forecast (smooths out individual member noise)

    • Ensemble spread (StdDev): forecast uncertainty — low spread = high confidence, high spread = uncertain

    • Ensemble max: worst-case envelope (e.g., heaviest precipitation any member predicts)

  • Spread typically increases with lead time as forecast uncertainty grows

  • 6-hour time steps out to 360 hours (15 days)

print('Loading WeatherNext 2 (64-member ensemble)...')
wn2_raw = (
    ee.ImageCollection('projects/gcp-public-data-weathernext/assets/weathernext_2_0_0')
    .filter(ee.Filter.gt('system:time_start', today.advance(-12, 'hour').millis()))
    .filter(ee.Filter.inList('forecast_hour', which_hours_6h))
)
wn2_init = wn2_raw.aggregate_array('start_time').distinct().sort().get(-1)
wn2 = wn2_raw.filter(ee.Filter.eq('start_time', wn2_init))

def ensemble_stats(hour):
    """Compute ensemble mean, std dev, and max across all members for one forecast hour."""
    hour = ee.Number(hour)
    members = wn2.filter(ee.Filter.eq('forecast_hour', hour))

    # Temperature (K -> C)
    temp = members.map(lambda img: img.select(['2m_temperature']).subtract(273.15).rename(['T']))
    t_mean = temp.mean().rename(['Temp_Mean'])
    t_std  = temp.reduce(ee.Reducer.stdDev()).rename(['Temp_Spread'])

    # Precipitation (m -> mm)
    precip = members.map(lambda img: img.select(['total_precipitation_6hr']).multiply(1000).rename(['P']))
    p_mean = precip.mean().rename(['Precip_Mean'])
    p_max  = precip.max().rename(['Precip_Max'])

    # Wind speed (m/s -> km/h)
    wind = members.map(lambda img: wind_speed_direction(img, '10m_u_component_of_wind', '10m_v_component_of_wind'))
    w_mean = wind.select(['Speed']).mean().rename(['Wind_Mean'])
    w_std  = wind.select(['Speed']).reduce(ee.Reducer.stdDev()).rename(['Wind_Spread'])

    valid_time = ee.Date(wn2_init).advance(hour, 'hour')
    return (
        ee.Image.cat([t_mean, t_std, p_mean, p_max, w_mean, w_std])
        .set('system:time_start', valid_time.millis())
        .set('forecast_hour', hour)
    )

wn2_stats = ee.ImageCollection(ee.List(which_hours_6h).map(ensemble_stats))
print(f'WN2 ensemble stat images: {wn2_stats.size().getInfo()}')

# --- Add ensemble layers ---
# Temperature mean
Map.addTimeLapse(wn2_stats.select(['Temp_Mean']),
    {**wn_viz, 'min': -20, 'max': 45, 'palette': cmOceanThermal,
     'legendLabelLeftAfter': 'C', 'legendLabelRightAfter': 'C'},
    'WN2 Ensemble: Temp Mean')

# Temperature spread — shows where forecasts diverge
Map.addTimeLapse(wn2_stats.select(['Temp_Spread']),
    {**wn_viz, 'min': 0, 'max': 8, 'palette': spreadPalette,
     'legendLabelLeftAfter': 'C', 'legendLabelRightAfter': 'C'},
    'WN2 Ensemble: Temp Spread (uncertainty)')

# Precip mean
Map.addTimeLapse(wn2_stats.select(['Precip_Mean']),
    {**wn_viz, 'min': 0, 'max': 30, 'palette': precipPalette,
     'legendLabelLeftAfter': 'mm', 'legendLabelRightAfter': 'mm'},
    'WN2 Ensemble: Precip Mean (6hr)')

# Precip max — worst-case across all 64 members
Map.addTimeLapse(wn2_stats.select(['Precip_Max']),
    {**wn_viz, 'min': 0, 'max': 50, 'palette': precipPalette,
     'legendLabelLeftAfter': 'mm', 'legendLabelRightAfter': 'mm'},
    'WN2 Ensemble: Precip Max (worst-case)')

# Wind mean
Map.addTimeLapse(wn2_stats.select(['Wind_Mean']),
    {**wn_viz, 'min': 0, 'max': 80, 'palette': cmOceanSpeed,
     'legendLabelLeftAfter': 'km/h', 'legendLabelRightAfter': 'km/h'},
    'WN2 Ensemble: Wind Speed Mean')

# Wind spread
Map.addTimeLapse(wn2_stats.select(['Wind_Spread']),
    {**wn_viz, 'min': 0, 'max': 15, 'palette': spreadPalette,
     'legendLabelLeftAfter': 'km/h', 'legendLabelRightAfter': 'km/h'},
    'WN2 Ensemble: Wind Spread (uncertainty)')

print('WeatherNext 2 ensemble layers added')

5. Model Comparison — Temperature Difference Maps

  • Compare model forecasts by computing the difference between two models at matching valid times

  • Useful for identifying where models agree (near zero) and where they diverge (large positive/negative)

  • Here we compare: ECMWF vs GFS, WeatherNext Graph vs GFS, and WN2 Ensemble Mean vs GFS

# Difference palette: blue (model A warmer) -> white (agree) -> red (model B warmer)
diffPalette = ['2166ac', '67a9cf', 'd1e5f0', 'f7f7f7', 'fddbc7', 'ef8a62', 'b2182b']

# To compute differences we need matching valid times.
# Use 6h steps (common to all models) and join on system:time_start.

# GFS temp in Celsius (GFS reports in Celsius already for 2m temp)
gfs_temp_6h = gfs.filter(ee.Filter.inList('forecast_hours', which_hours_6h)).select(['temperature_2m_above_ground'])

# Build difference: WN Graph - GFS
def diff_graph_gfs(graph_img):
    t = graph_img.get('system:time_start')
    gfs_match = gfs_temp_6h.filter(ee.Filter.eq('forecast_time', t)).first()
    diff = graph_img.select(['Temperature_C']).subtract(gfs_match.rename(['Temperature_C']))
    return diff.rename(['Temp_Diff_C']).set('system:time_start', t)

try:
    diff_wn_gfs = graph_temp.map(diff_graph_gfs)
    Map.addTimeLapse(diff_wn_gfs,
        {**wn_viz, 'min': -5, 'max': 5, 'palette': diffPalette,
         'legendLabelLeftAfter': 'C', 'legendLabelRightAfter': 'C'},
        'Diff: WN Graph - GFS Temperature')
    print('Difference layer added')
except Exception as e:
    print(f'Difference layer skipped (time mismatch): {e}')

View the Map

  • Toggle layers in the layer panel to compare models

  • Use the time slider to step through forecast hours

  • Click on the map to see area charts of forecast values

  • Compare ensemble spread layers to see how uncertainty evolves with forecast lead time

Map.setQueryDateFormat('YYYY-MM-dd HH:mm')
Map.turnOnInspector()
Map.view()

Summary of Available Bands

Surface / Single-Level Variables

Variable

GFS Band

ECMWF Band

WeatherNext Band

Units

Temperature (2m)

temperature_2m_above_ground

temperature_2m_sfc

2m_temperature

K (ECMWF/WN) or C (GFS)

Dewpoint (2m)

dew_point_temperature_2m_above_ground

dewpoint_temperature_2m_sfc

K

U-wind (10m)

u_component_of_wind_10m_above_ground

u_component_of_wind_10m_sfc

10m_u_component_of_wind

m/s

V-wind (10m)

v_component_of_wind_10m_above_ground

v_component_of_wind_10m_sfc

10m_v_component_of_wind

m/s

U-wind (100m)

u_component_of_wind_100m_sfc

100m_u_component_of_wind

m/s

V-wind (100m)

v_component_of_wind_100m_sfc

100m_v_component_of_wind

m/s

MSLP

mean_sea_level_pressure_sfc

mean_sea_level_pressure

Pa

Precipitation

precipitation_rate

total_precipitation_sfc

total_precipitation_6hr

varies

Precipitable Water

precipitable_water_entire_atmosphere

kg/m²

SST

skin_temperature_sfc

sea_surface_temperature

K

Pressure-Level Variables (selected levels)

Variable

ECMWF Pattern

WeatherNext Pattern

Levels

Geopotential Height

geopotential_height_plXXX

XXX_geopotential

50-1000 hPa

Temperature

temperature_plXXX

XXX_temperature

50-1000 hPa

U-wind

u_component_of_wind_plXXX

XXX_u_component_of_wind

50-1000 hPa

V-wind

v_component_of_wind_plXXX

XXX_v_component_of_wind

50-1000 hPa

Specific Humidity

specific_humidity_plXXX

XXX_specific_humidity

50-1000 hPa

Vorticity

vorticity_plXXX

50-1000 hPa

Model Initialization Properties

Property

GFS

ECMWF

WeatherNext

Init time

creation_time (epoch ms)

creation_time (epoch ms)

start_time (ISO 8601 string)

Forecast hour

forecast_hours

forecast_hours

forecast_hour

Valid time

forecast_time (epoch ms)

forecast_time (epoch ms)

computed from start_time + forecast_hour

Ensemble member

ensemble_member (WN2 only, 0-63)