WeatherNext forecasts on Earth Engine

WeatherNext 3 forecast data is available in Google Earth Engine as an ImageCollection across two public catalog listings: the 0.1° Gridded Collection and the 0.05° Stations Collection. Earth Engine provides precomputed ensemble statistics for surface weather variables, optimized for planetary-scale raster computation, geospatial overlays, and interactive mapping.

What is Earth Engine?

Google Earth Engine is a cloud platform for petabyte-scale scientific analysis and visualization of geospatial datasets. Computations run in parallel across Google's infrastructure, making it ideal for combining weather forecasts with satellite imagery, land cover, and custom vector boundaries.

Available datasets & collections

Earth Engine provides optimized surface forecast ImageCollections with precomputed distribution statistics. The data is split into two collections by spatial grid resolution:

Collection Earth Engine Asset ID Grid Resolution Variables & Scope
0.1° Gridded projects/gcp-public-data-weathernext/assets/weathernext_3_0_0_0p1deg 0.1°
  • 19 gridded surface variables across six precomputed statistical metrics—specifically mean, p10, p25, p50, p75, and p90 (total of 114 metrics, including total precipitation and solar radiation).
  • Hourly timesteps across all inits.
0.05° Stations projects/gcp-public-data-weathernext/assets/weathernext_3_0_0_0p05deg 0.05°
  • High-resolution station head forecasts for 2m temperature and dew point across six precomputed statistical metrics—specifically mean, p10, p25, p50, p75, and p90 (total of 12 metrics).
  • Hourly timesteps across all inits.

(For the raw 64-member ensemble and 3D atmospheric pressure levels, use Google Cloud Storage (Zarr)).

Image structure and properties

In Earth Engine, each forecast run produces a series of ee.Image assets representing lead time steps for a given initialization run:

Property Type Description
start_time String Initialization timestamp of the model run in UTC ISO 8601 format (e.g., 2026-05-01T00:00:00Z).
end_time String Valid timestamp for the forecast (start_time + forecast_hour).
forecast_hour Integer Lead time in hours from initialization (1 to 360 for 6-hourly inits, 1 to 48 for interim hourly inits).
system:time_start Long Valid time in milliseconds since the Unix epoch.
ingestion_time_utc Double Timestamp when the forecast data became available in Earth Engine.
B_ String The band names in order, starting from B0 to B11 for the 0.05° station collection and B0 to B113 for the 0.1° gridded collection.

Bands & ensemble statistics

Each base weather variable is provided across 6 ensemble statistics: _mean, _p10, _p25, _p50 (median), _p75, and _p90 (for example, temperature_2m_mean, temperature_2m_p50, u_component_of_wind_10m_mean, total_precipitation_1hr_mean).


Common query recipes

Explore common Earth Engine Python API workflows for WeatherNext image collections:

1. Load the latest forecast run

Initialize the Earth Engine Python API and filter the collection by initialization timestamp:

Python

import ee

ee.Initialize(project="YOUR_PROJECT_ID")

collection_id = "projects/gcp-public-data-weathernext/assets/weathernext_3_0_0_0p1deg"
col = ee.ImageCollection(collection_id)

# Filter for a specific forecast initialization run (e.g., 2026-05-01 00:00 UTC)
forecast_run = col.filter(
    ee.Filter.eq("start_time", "2026-05-01T00:00:00Z")
)

# Total hourly forecast images (up to 360 lead times)
print(f"Hourly steps in run: {forecast_run.size().getInfo()}")

2. Time series extraction and plotting (0.1° gridded collection)

Extract an hourly temperature forecast time series (mean, 10th, and 90th percentile bands) over a region:

Python

import ee
import matplotlib.dates as mdates
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns

ee.Initialize(project="YOUR_PROJECT_ID")

collection_id = "projects/gcp-public-data-weathernext/assets/weathernext_3_0_0_0p1deg"
col = ee.ImageCollection(collection_id)

# Define NYC bounding box (west, south, east, north)
ny_geom = ee.Geometry.BBox(-74.26, 40.50, -73.70, 40.90)

# Filter for initialization run and first 24 hours
ny_temps_ee = (col
    .filter(ee.Filter.eq("start_time", "2026-05-01T00:00:00Z"))
    .filter(ee.Filter.lte("forecast_hour", 24))
    .filterBounds(ny_geom)
    .select(["temperature_2m_mean", "temperature_2m_p10", "temperature_2m_p90"]))

# Convert ImageCollection into Pandas DataFrame using covering grid
def convert_to_dataframe(image_collection, geometry, bands_to_reducer):
  covering_grid = geometry.coveringGrid(
      image_collection.first().projection(),
      image_collection.first().projection().nominalScale()
  )
  def convert_to_feature_collection(image):
    def get_feature_for_cell(cell_polygon):
      feature_dict = {
          "time": image.get("end_time"),
          "init_time": image.get("start_time"),
          "forecast_hour": image.get("forecast_hour"),
      }
      for band_id, reducer in bands_to_reducer.items():
        val = image.reduceRegion(
            reducer=reducer,
            geometry=cell_polygon.geometry(),
            scale=image.projection().nominalScale()
        ).get(band_id)
        feature_dict[band_id] = val
      return ee.Feature(cell_polygon.geometry(), feature_dict)
    return covering_grid.map(get_feature_for_cell)

  features = image_collection.map(convert_to_feature_collection).flatten()
  df = ee.data.computeFeatures({
      "expression": features,
      "fileFormat": "PANDAS_DATAFRAME"
  })
  df["time"] = pd.to_datetime(df["time"])
  df["init_time"] = pd.to_datetime(df["init_time"])
  return df

ny_temps = convert_to_dataframe(
    ny_temps_ee,
    ny_geom,
    {
        "temperature_2m_mean": ee.Reducer.mean(),
        "temperature_2m_p10": ee.Reducer.mean(),
        "temperature_2m_p90": ee.Reducer.mean(),
    }
)

# Plot hourly mean with 10th-90th percentile envelope
ny_temps_agg = ny_temps.groupby("time", as_index=False)[
    ["temperature_2m_mean", "temperature_2m_p10", "temperature_2m_p90"]
].mean()

temp_mean_c = ny_temps_agg["temperature_2m_mean"] - 273.15
temp_p10_c = ny_temps_agg["temperature_2m_p10"] - 273.15
temp_p90_c = ny_temps_agg["temperature_2m_p90"] - 273.15
times = ny_temps_agg["time"]

plt.figure(figsize=(12, 6))
sns.set_theme(style="whitegrid")
plt.fill_between(times, temp_p10_c, temp_p90_c, color="lightcoral", alpha=0.35, label="10th-90th Percentile Range")
plt.plot(times, temp_mean_c, marker="o", markersize=4, color="firebrick", linewidth=2, label="Ensemble Mean")
plt.xlabel("Valid Time (UTC)", fontsize=12)
plt.ylabel("2m Temperature (°C)", fontsize=12)
plt.title("1-Day Temperature Forecast for New York", fontsize=14)
plt.legend(loc="upper right", fontsize=11)
plt.tight_layout()
plt.show()

3. Interactive map visualization with geemap

Display global forecast ensemble means onto an interactive map:

Python

import ee
import geemap.core as geemap

ee.Initialize(project="YOUR_PROJECT_ID")

collection_id = "projects/gcp-public-data-weathernext/assets/weathernext_3_0_0_0p1deg"
col = ee.ImageCollection(collection_id)

variable = "temperature_2m_mean"
palette = "coolwarm"

# Select single forecast valid step
world_avgs = (col
    .filter(ee.Filter.eq("start_time", "2026-04-30T18:00:00Z"))
    .filter(ee.Filter.eq("end_time", "2026-05-01T00:00:00Z"))
    .select(variable)
    .first())

# Compute global min and max for color normalization
min_max = world_avgs.reduceRegion(
    reducer=ee.Reducer.minMax(),
    geometry=ee.Geometry.BBox(-180, -90, 180, 90),
    scale=world_avgs.projection().nominalScale(),
    maxPixels=1e13
)

vis_params = {
    "bands": [variable],
    "min": min_max.get(f"{variable}_min"),
    "max": min_max.get(f"{variable}_max"),
    "palette": palette,
}

m = geemap.Map(center=[35, 0], zoom=2)
m.add_layer(world_avgs, vis_params, f"{variable} average", True, 0.5)
m

4. High-resolution station forecast query (0.05° collection)

Query the station-calibrated collection for fine-scale point and region forecasting:

Python

import ee

ee.Initialize(project="YOUR_PROJECT_ID")

stations_col = ee.ImageCollection("projects/gcp-public-data-weathernext/assets/weathernext_3_0_0_0p05deg")

# Define NYC bounding box (west, south, east, north)
ny_geom = ee.Geometry.BBox(-74.26, 40.50, -73.70, 40.90)

station_run = (stations_col
    .filter(ee.Filter.eq("start_time", "2026-05-01T00:00:00Z"))
    .filterBounds(ny_geom)
    .select(["station_head_temperature_2m_mean", "station_head_dewpoint_temperature_2m_mean"]))


Best practices

  • Filter before reducing: Apply filterBounds() and filter(ee.Filter.lte('forecast_hour', ...)) early to limit the images evaluated on Google infrastructure.
  • Leverage precomputed stats: Use the precomputed statistical bands (_mean, _p10, _p25, _p50, _p75, _p90) directly instead of attempting to calculate custom reductions over raw members.
  • Specify nominal scale: Set scale=5000 for surface temperature and dew point in the 0.05° collection, and scale=10000 for 0.1° surface fields when calling reduceRegion.

Starter guides

For interactive Colab notebooks with complete workflows and geemap tutorials:


Terms of use

For more details, see Terms of Service and Disclaimers.