|
| 1 | +#!/usr/bin/env -S uv run --script |
| 2 | +# |
| 3 | +# /// script |
| 4 | +# requires-python = ">=3.12" |
| 5 | +# dependencies = [ |
| 6 | +# "omfiles>=1.0.0", |
| 7 | +# "fsspec>=2025.7.0", |
| 8 | +# "s3fs", |
| 9 | +# "matplotlib", |
| 10 | +# "cartopy", |
| 11 | +# "earthkit-regrid", |
| 12 | +# ] |
| 13 | +# /// |
| 14 | + |
| 15 | +import cartopy.crs as ccrs |
| 16 | +import cartopy.feature as cfeature |
| 17 | +import fsspec |
| 18 | +import matplotlib.pyplot as plt |
| 19 | +import numpy as np |
| 20 | +from earthkit.regrid import interpolate |
| 21 | +from omfiles import OmFileReader |
| 22 | + |
| 23 | +ifs_spatial_file = f"openmeteo/data_spatial/ecmwf_ifs/2025/10/01/0000Z/2025-10-01T0000.om" |
| 24 | +backend = fsspec.open( |
| 25 | + f"blockcache::s3://{ifs_spatial_file}", |
| 26 | + mode="rb", |
| 27 | + s3={"anon": True, "default_block_size": 65536}, |
| 28 | + blockcache={"cache_storage": "cache", "same_names": True}, |
| 29 | +) |
| 30 | +with OmFileReader(backend) as reader: |
| 31 | + print("reader.is_group", reader.is_group) |
| 32 | + |
| 33 | + child = reader.get_child_by_name("temperature_2m") |
| 34 | + print("child.name", child.name) |
| 35 | + |
| 36 | + # Get the full data array |
| 37 | + print("child.shape", child.shape) |
| 38 | + print("child.chunks", child.chunks) |
| 39 | + data = child[:] |
| 40 | + print(f"Data shape: {data.shape}") |
| 41 | + print(f"Data range: {np.nanmin(data)} to {np.nanmax(data)}") |
| 42 | + |
| 43 | + # We are using earthkit-regrid for regridding: https://earthkit-regrid.readthedocs.io/en/stable/interpolate.html#interpolate |
| 44 | + # with linear interpolation. Nearest neighbor interpolation can be obtained with`method="nearest-neighbour"` |
| 45 | + regridded = interpolate(data, in_grid={"grid": "O1280"}, out_grid={"grid": [0.1, 0.1]}, method="linear") |
| 46 | + print(f"Regridded shape: {regridded.shape}") |
| 47 | + |
| 48 | + # Create plot |
| 49 | + fig = plt.figure(figsize=(12, 8)) |
| 50 | + ax = plt.axes(projection=ccrs.PlateCarree()) # use PlateCarree projection |
| 51 | + |
| 52 | + # Add map features |
| 53 | + ax.add_feature(cfeature.COASTLINE) |
| 54 | + ax.add_feature(cfeature.BORDERS) |
| 55 | + ax.add_feature(cfeature.OCEAN, alpha=0.3) |
| 56 | + ax.add_feature(cfeature.LAND, alpha=0.3) |
| 57 | + |
| 58 | + # Create coordinate arrays |
| 59 | + # These bounds need to match the output grid of the regridding! |
| 60 | + height, width = regridded.shape |
| 61 | + lon = np.linspace(0, 360, width, endpoint=False) |
| 62 | + lat = np.linspace(90, -90, height) |
| 63 | + lon_grid, lat_grid = np.meshgrid(lon, lat) |
| 64 | + |
| 65 | + # Plot the data |
| 66 | + im = ax.contourf(lon_grid, lat_grid, regridded, levels=20, transform=ccrs.PlateCarree(), cmap="viridis") |
| 67 | + plt.colorbar(im, ax=ax, shrink=0.6, label=child.name) |
| 68 | + ax.gridlines(draw_labels=True, alpha=0.3) |
| 69 | + plt.title(f"2D Map: {child.name}") |
| 70 | + ax.set_global() |
| 71 | + plt.tight_layout() |
| 72 | + |
| 73 | + output_filename = f"map_ifs_{child.name.replace('/', '_')}.png" |
| 74 | + plt.savefig(output_filename, dpi=300, bbox_inches="tight") |
| 75 | + print(f"Plot saved as: {output_filename}") |
| 76 | + plt.close() |
0 commit comments