Visualization of map_raster test

This notebook visualizes the test for map_raster using: - Real S1A SAR coordinates (Gulf of California) - Synthetic ECMWF wind data

Source: tests/test_map_raster_4cases.py (comprehensive 4-case test suite)

[1]:
import sys
from pathlib import Path

# Add parent directories to path to import from tests and mapraster
sys.path.insert(0, str(Path.cwd().parent.parent))

import numpy as np
import xarray as xr
import matplotlib.pyplot as plt
from mapraster.main import map_raster
from tests.tools_test import fake_ecmwf_0100_1h, build_footprint

%matplotlib inline

1. Create SAR dataset with real S1A coordinates

[2]:
def create_real_sar_dataset():
    """
    Create SAR dataset with real S1A coordinates from Gulf of California.
    Based on s1a-iw-owi-dv-20210909t130650-20210909t130715-039605-04AE83.nc

    Returns synthetic dataset with bilinear interpolation between corner points.
    """
    # Real corner coordinates from S1A SAR
    corners = {
        'lon': np.array([-106.73246, -109.26672, -109.43854, -106.90172]),
        'lat': np.array([21.72079, 22.14191, 20.64836, 20.22559])
    }

    # SAR grid dimensions
    nlines, nsamples = 167, 256

    # Create meshgrid indices
    lines = np.arange(nlines)
    samples = np.arange(nsamples)

    # Bilinear interpolation
    s_norm = samples / (nsamples - 1)
    l_norm = lines / (nlines - 1)

    # Top edge (line=0): interpolate between corners[0] and corners[1]
    lon_top = corners['lon'][0] + s_norm * (corners['lon'][1] - corners['lon'][0])
    lat_top = corners['lat'][0] + s_norm * (corners['lat'][1] - corners['lat'][0])

    # Bottom edge (line=-1): interpolate between corners[3] and corners[2]
    lon_bottom = corners['lon'][3] + s_norm * (corners['lon'][2] - corners['lon'][3])
    lat_bottom = corners['lat'][3] + s_norm * (corners['lat'][2] - corners['lat'][3])

    # Full grid: interpolate between top and bottom edges
    lon_grid = lon_top[None, :] + l_norm[:, None] * (lon_bottom[None, :] - lon_top[None, :])
    lat_grid = lat_top[None, :] + l_norm[:, None] * (lat_bottom[None, :] - lat_top[None, :])

    # Create xarray Dataset
    ds = xr.Dataset(
        {
            'longitude': (['line', 'sample'], lon_grid),
            'latitude': (['line', 'sample'], lat_grid),
        },
        coords={
            'line': lines,
            'sample': samples,
        }
    )

    return ds

sar_dataset = create_real_sar_dataset()
print(f"SAR shape: {sar_dataset['longitude'].shape}")
print(f"SAR lon range: [{sar_dataset['longitude'].min().values:.2f}, {sar_dataset['longitude'].max().values:.2f}]")
print(f"SAR lat range: [{sar_dataset['latitude'].min().values:.2f}, {sar_dataset['latitude'].max().values:.2f}]")
SAR shape: (167, 256)
SAR lon range: [-109.44, -106.73]
SAR lat range: [20.23, 22.14]
[3]:
sar_dataset

[3]:
<xarray.Dataset> Size: 687kB
Dimensions:    (line: 167, sample: 256)
Coordinates:
  * line       (line) int64 1kB 0 1 2 3 4 5 6 7 ... 160 161 162 163 164 165 166
  * sample     (sample) int64 2kB 0 1 2 3 4 5 6 ... 249 250 251 252 253 254 255
Data variables:
    longitude  (line, sample) float64 342kB -106.7 -106.7 ... -109.4 -109.4
    latitude   (line, sample) float64 342kB 21.72 21.72 21.72 ... 20.65 20.65

2. Create synthetic ECMWF wind data

[4]:
ecmwf_dataset = fake_ecmwf_0100_1h(to180=True, with_nan=False)
print(f"ECMWF shape: {ecmwf_dataset['U10'].shape}")
print(f"ECMWF x range: [{ecmwf_dataset['x'].min().values:.2f}, {ecmwf_dataset['x'].max().values:.2f}]")
print(f"ECMWF y range: [{ecmwf_dataset['y'].min().values:.2f}, {ecmwf_dataset['y'].max().values:.2f}]")
ECMWF shape: (1810, 3600)
ECMWF x range: [-180.00, 179.90]
ECMWF y range: [-90.00, 90.00]
[5]:
ecmwf_dataset
[5]:
<xarray.Dataset> Size: 104MB
Dimensions:      (y: 1810, x: 3600)
Coordinates:
  * y            (y) float64 14kB -90.0 -89.9 -89.8 -89.7 ... 89.8 89.9 90.0
  * x            (x) float64 29kB -180.0 -179.9 -179.8 ... 179.7 179.8 179.9
    spatial_ref  int64 8B 0
Data variables:
    U10          (y, x) float64 52MB 5.0 5.0 5.0 5.0 5.0 ... 5.0 5.0 5.0 5.0 5.0
    V10          (y, x) float64 52MB 2.449e-16 -0.003491 ... 0.006981 0.003491
Attributes:
    time:     2023-03-03 07:00:00

3. Run map_raster

[6]:
footprint = build_footprint(sar_dataset)

result = map_raster(
    raster_ds=ecmwf_dataset,
    originalDataset=sar_dataset,
    footprint=footprint,
    cross_antimeridian=False,
)

print(f"Result shape: {result['U10'].shape}")
print(f"Result U10 range: [{result['U10'].min().values:.2f}, {result['U10'].max().values:.2f}]")
print(f"Result V10 range: [{result['V10'].min().values:.2f}, {result['V10'].max().values:.2f}]")
Result shape: (167, 256)
Result U10 range: [6.85, 6.88]
Result V10 range: [-1.92, -1.89]

4. Visualizations

4.1 SAR grid geometry

[7]:
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5))

# Longitude
im1 = ax1.pcolormesh(
    sar_dataset['sample'],
    sar_dataset['line'],
    sar_dataset['longitude'],
    shading='auto',
    cmap='viridis'
)
ax1.set_xlabel('Sample')
ax1.set_ylabel('Line')
ax1.set_title('SAR Longitude Grid')
plt.colorbar(im1, ax=ax1, label='Longitude (°)')

# Latitude
im2 = ax2.pcolormesh(
    sar_dataset['sample'],
    sar_dataset['line'],
    sar_dataset['latitude'],
    shading='auto',
    cmap='plasma'
)
ax2.set_xlabel('Sample')
ax2.set_ylabel('Line')
ax2.set_title('SAR Latitude Grid')
plt.colorbar(im2, ax=ax2, label='Latitude (°)')

plt.tight_layout()
plt.show()
../_images/examples_test_map_raster_visualization_12_0.png

4.2 ECMWF wind fields (global)

[8]:
fig, (ax1, ax2, ax3) = plt.subplots(3, 1, figsize=(14, 12))

# Wind speed
wind_speed_ecmwf = np.sqrt(ecmwf_dataset['U10']**2 + ecmwf_dataset['V10']**2)
im0 = ax1.pcolormesh(
    ecmwf_dataset['x'],
    ecmwf_dataset['y'],
    wind_speed_ecmwf,
    shading='auto',
    cmap='viridis',
    vmin=0,
    vmax=15
)
ax1.set_xlabel('Longitude (°)')
ax1.set_ylabel('Latitude (°)')
ax1.set_title('ECMWF Wind Speed (global)')
plt.colorbar(im0, ax=ax1, label='Wind Speed (m/s)')

# U10
im1 = ax2.pcolormesh(
    ecmwf_dataset['x'],
    ecmwf_dataset['y'],
    ecmwf_dataset['U10'],
    shading='auto',
    cmap='RdBu_r',
    vmin=-10,
    vmax=10
)
ax2.set_xlabel('Longitude (°)')
ax2.set_ylabel('Latitude (°)')
ax2.set_title('ECMWF U10 Wind Component (global)')
plt.colorbar(im1, ax=ax2, label='U10 (m/s)')

# V10
im2 = ax3.pcolormesh(
    ecmwf_dataset['x'],
    ecmwf_dataset['y'],
    ecmwf_dataset['V10'],
    shading='auto',
    cmap='RdBu_r',
    vmin=-10,
    vmax=10
)
ax3.set_xlabel('Longitude (°)')
ax3.set_ylabel('Latitude (°)')
ax3.set_title('ECMWF V10 Wind Component (global)')
plt.colorbar(im2, ax=ax3, label='V10 (m/s)')

plt.tight_layout()
plt.show()
../_images/examples_test_map_raster_visualization_14_0.png

4.3 ECMWF wind fields (SAR region zoom)

[9]:
# Extract SAR region from ECMWF
lon_min, lon_max = sar_dataset['longitude'].min().values, sar_dataset['longitude'].max().values
lat_min, lat_max = sar_dataset['latitude'].min().values, sar_dataset['latitude'].max().values

ecmwf_subset = ecmwf_dataset.sel(
    x=slice(lon_min-1, lon_max+1),
    y=slice(lat_min-1, lat_max+1)
)

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5))

# U10 zoom
im1 = ax1.pcolormesh(
    ecmwf_subset['x'],
    ecmwf_subset['y'],
    ecmwf_subset['U10'],
    shading='auto',
    cmap='RdBu_r'
)
ax1.set_xlabel('Longitude (°)')
ax1.set_ylabel('Latitude (°)')
ax1.set_title('ECMWF U10 (SAR region)')
plt.colorbar(im1, ax=ax1, label='U10 (m/s)')

# Add SAR footprint
lon_corners = sar_dataset['longitude'].values[[0, 0, -1, -1, 0], [0, -1, -1, 0, 0]]
lat_corners = sar_dataset['latitude'].values[[0, 0, -1, -1, 0], [0, -1, -1, 0, 0]]
ax1.plot(lon_corners, lat_corners, 'k-', linewidth=2, label='SAR footprint')
ax1.legend()

# V10 zoom
im2 = ax2.pcolormesh(
    ecmwf_subset['x'],
    ecmwf_subset['y'],
    ecmwf_subset['V10'],
    shading='auto',
    cmap='RdBu_r'
)
ax2.set_xlabel('Longitude (°)')
ax2.set_ylabel('Latitude (°)')
ax2.set_title('ECMWF V10 (SAR region)')
plt.colorbar(im2, ax=ax2, label='V10 (m/s)')

# Add SAR footprint
ax2.plot(lon_corners, lat_corners, 'k-', linewidth=2, label='SAR footprint')
ax2.legend()

plt.tight_layout()
plt.show()
../_images/examples_test_map_raster_visualization_16_0.png

4.4 Interpolated wind on SAR grid (result of map_raster)

[10]:
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5))

# U10 interpolated
im1 = ax1.pcolormesh(
    sar_dataset['sample'],
    sar_dataset['line'],
    result['U10'],
    shading='auto',
    cmap='RdBu_r'
)
ax1.set_xlabel('Sample')
ax1.set_ylabel('Line')
ax1.set_title('Interpolated U10 on SAR grid')
plt.colorbar(im1, ax=ax1, label='U10 (m/s)')

# V10 interpolated
im2 = ax2.pcolormesh(
    sar_dataset['sample'],
    sar_dataset['line'],
    result['V10'],
    shading='auto',
    cmap='RdBu_r'
)
ax2.set_xlabel('Sample')
ax2.set_ylabel('Line')
ax2.set_title('Interpolated V10 on SAR grid')
plt.colorbar(im2, ax=ax2, label='V10 (m/s)')

plt.tight_layout()
plt.show()
../_images/examples_test_map_raster_visualization_18_0.png

4.5 Before/After comparison in lon/lat coordinates

[11]:
fig, axes = plt.subplots(2, 2, figsize=(16, 12))

# Extract SAR coordinates
sar_lon = sar_dataset['longitude'].values
sar_lat = sar_dataset['latitude'].values

# U10: Before (ECMWF subset)
ax1 = axes[0, 0]
im1 = ax1.pcolormesh(
    ecmwf_subset['x'],
    ecmwf_subset['y'],
    ecmwf_subset['U10'],
    shading='auto',
    cmap='RdBu_r'
)
ax1.plot(lon_corners, lat_corners, 'k-', linewidth=2, label='SAR footprint')
ax1.set_xlabel('Longitude (°)')
ax1.set_ylabel('Latitude (°)')
ax1.set_title('ECMWF U10 (Before interpolation)')
ax1.legend()
plt.colorbar(im1, ax=ax1, label='U10 (m/s)')

# U10: After (interpolated on SAR grid)
ax2 = axes[0, 1]
im2 = ax2.scatter(
    sar_lon.flatten(),
    sar_lat.flatten(),
    c=result['U10'].values.flatten(),
    s=5,
    cmap='RdBu_r',
    vmin=im1.get_clim()[0],
    vmax=im1.get_clim()[1]
)
ax2.set_xlabel('Longitude (°)')
ax2.set_ylabel('Latitude (°)')
ax2.set_title('Interpolated U10 (After map_raster)')
plt.colorbar(im2, ax=ax2, label='U10 (m/s)')

# V10: Before (ECMWF subset)
ax3 = axes[1, 0]
im3 = ax3.pcolormesh(
    ecmwf_subset['x'],
    ecmwf_subset['y'],
    ecmwf_subset['V10'],
    shading='auto',
    cmap='RdBu_r'
)
ax3.plot(lon_corners, lat_corners, 'k-', linewidth=2, label='SAR footprint')
ax3.set_xlabel('Longitude (°)')
ax3.set_ylabel('Latitude (°)')
ax3.set_title('ECMWF V10 (Before interpolation)')
ax3.legend()
plt.colorbar(im3, ax=ax3, label='V10 (m/s)')

# V10: After (interpolated on SAR grid)
ax4 = axes[1, 1]
im4 = ax4.scatter(
    sar_lon.flatten(),
    sar_lat.flatten(),
    c=result['V10'].values.flatten(),
    s=5,
    cmap='RdBu_r',
    vmin=im3.get_clim()[0],
    vmax=im3.get_clim()[1]
)
ax4.set_xlabel('Longitude (°)')
ax4.set_ylabel('Latitude (°)')
ax4.set_title('Interpolated V10 (After map_raster)')
plt.colorbar(im4, ax=ax4, label='V10 (m/s)')

plt.tight_layout()
plt.show()
../_images/examples_test_map_raster_visualization_20_0.png
[ ]: