Migration Guide: Xee v0.1.0
This guide helps you update your code from Xee v0.0.x to v0.1.0. The 0.1 release includes two major improvements:
New grid parameter system for specifying output geography
Updated dimension ordering from
[time, x, y]to[time, y, x]
Quick Migration Checklist
[ ] Replace
scaleandgeometryparameters with grid parameter helpers[ ] Remove
.transpose()calls before plotting or passing to libraries expecting[time, y, x][ ] Update any code that explicitly references dimension order
[ ] Test your workflows with the new API
1. Geography Specification Changes
Old API (v0.0.x)
The old API used simple crs, scale, and geometry parameters:
import ee
import xarray as xr
ds = xr.open_dataset(
'ECMWF/ERA5_LAND/MONTHLY_AGGR',
engine='ee',
crs='EPSG:4326',
scale=0.25, # pixel size in degrees
geometry=ee.Geometry.Rectangle([-180, -90, 180, 90])
)
New API (v0.1.0)
The new API requires explicit grid parameters: crs, crs_transform, and shape_2d. We provide helper functions to make this easy:
Option 1: Match Source Grid (Recommended for simplicity)
import ee
import xarray as xr
from xee import helpers
ic = ee.ImageCollection('ECMWF/ERA5_LAND/MONTHLY_AGGR')
grid_params = helpers.extract_grid_params(ic)
ds = xr.open_dataset(ic, engine='ee', **grid_params)
Option 2: Fit Geometry with Specific Scale
import ee
import xarray as xr
from xee import helpers
import shapely
# Define your area of interest using shapely
aoi = shapely.geometry.box(-180, -90, 180, 90) # Global extent
grid_params = helpers.fit_geometry(
geometry=aoi,
grid_crs='EPSG:4326',
grid_scale=(0.25, -0.25) # (x_scale, y_scale) in degrees
)
ds = xr.open_dataset(
'ECMWF/ERA5_LAND/MONTHLY_AGGR',
engine='ee',
**grid_params
)
Option 3: Fit Geometry with Specific Shape
import shapely
from xee import helpers
aoi = shapely.geometry.box(113.33, -43.63, 153.56, -10.66) # Australia
grid_params = helpers.fit_geometry(
geometry=aoi,
grid_crs='EPSG:4326',
grid_shape=(256, 256) # (width, height) in pixels
)
ds = xr.open_dataset(
'ECMWF/ERA5_LAND/MONTHLY_AGGR',
engine='ee',
**grid_params
)
Migration Examples
Example 1: Global dataset at fixed scale
Before (v0.1.0):
ds = xr.open_dataset(
'ECMWF/ERA5_LAND/MONTHLY_AGGR',
engine='ee',
crs='EPSG:4326',
scale=1.0,
geometry=ee.Geometry.Rectangle([-180, -90, 180, 90])
)
After (v0.1.0):
import shapely
from xee import helpers
global_geom = shapely.geometry.box(-180, -90, 180, 90)
grid_params = helpers.fit_geometry(
geometry=global_geom,
grid_crs='EPSG:4326',
grid_scale=(1.0, -1.0) # Note: negative y-scale for north-up orientation
)
ds = xr.open_dataset(
'ECMWF/ERA5_LAND/MONTHLY_AGGR',
engine='ee',
**grid_params
)
Example 2: Regional dataset with EE geometry
Before (v0.1.0):
import ee
aoi = ee.Geometry.Rectangle([-122.5, 37.0, -121.5, 38.0])
ds = xr.open_dataset(
'LANDSAT/LC09/C02/T1_L2',
engine='ee',
crs='EPSG:32610',
scale=30,
geometry=aoi
)
After (v0.1.0):
import ee
import shapely
from xee import helpers
# Convert EE geometry to shapely (or create directly with shapely)
aoi = shapely.geometry.box(-122.5, 37.0, -121.5, 38.0)
grid_params = helpers.fit_geometry(
geometry=aoi,
geometry_crs='EPSG:4326', # Input geometry CRS
grid_crs='EPSG:32610', # Output grid CRS (UTM Zone 10N)
grid_scale=(30, -30) # 30m resolution
)
ds = xr.open_dataset(
'LANDSAT/LC09/C02/T1_L2',
engine='ee',
**grid_params
)
Example 3: Using source resolution for a custom area
Before (v0.1.0):
# You had to manually determine the scale from the dataset
ds = xr.open_dataset(
collection,
engine='ee',
crs='EPSG:4326',
scale=0.25, # Manually determined
geometry=my_region
)
After (v0.1.0):
from xee import helpers
import shapely
# 1. Extract source grid parameters
ic = ee.ImageCollection('ECMWF/ERA5_LAND/MONTHLY_AGGR')
source_params = helpers.extract_grid_params(ic)
# 2. Get the source scale
source_crs = source_params['crs']
source_transform = source_params['crs_transform']
source_scale = (source_transform[0], source_transform[4])
# 3. Apply to your custom region
my_region = shapely.geometry.box(-10, 35, 5, 50) # Western Europe
grid_params = helpers.fit_geometry(
geometry=my_region,
geometry_crs='EPSG:4326',
grid_crs=source_crs,
grid_scale=source_scale
)
ds = xr.open_dataset(ic, engine='ee', **grid_params)
2. Dimension Ordering Changes
What Changed
Xee v0.1.0 outputs dimensions in [time, y, x] order (matching CF conventions and most geospatial tools), instead of the previous [time, x, y] order.
Impact on Your Code
Plotting
Before (v0.1.0):
# Required transpose for correct visualization
ds['temperature_2m'].isel(time=0).transpose().plot()
After (v0.1.0):
# No transpose needed - plots correctly by default
ds['temperature_2m'].isel(time=0).plot()
Integration with Other Libraries
Many geospatial libraries expect [time, y, x] ordering. You may have been using .transpose() to accommodate this.
Before (v0.1.0):
# Had to transpose for libraries expecting [time, y, x]
data_array = ds['temperature_2m'].transpose('time', 'y', 'x')
export_to_geotiff(data_array)
After (v0.1.0):
# Dimension order is already correct
data_array = ds['temperature_2m']
export_to_geotiff(data_array)
Explicit Dimension Access
If you have code that explicitly references dimension positions, update it:
Before (v0.1.0):
# Dimensions were [time, x, y]
time_dim, x_dim, y_dim = ds['temperature_2m'].dims
# or
width = ds['temperature_2m'].shape[1] # x dimension
height = ds['temperature_2m'].shape[2] # y dimension
After (v0.1.0):
# Dimensions are now [time, y, x]
time_dim, y_dim, x_dim = ds['temperature_2m'].dims
# or
height = ds['temperature_2m'].shape[1] # y dimension
width = ds['temperature_2m'].shape[2] # x dimension
Better approach (dimension-agnostic):
# This works in both versions
dims = ds['temperature_2m'].dims
width = ds.sizes['x']
height = ds.sizes['y']
time_length = ds.sizes['time']
3. Common Migration Patterns
Pattern 1: Simple global analysis
Before (v0.1.0):
import ee
import xarray as xr
ee.Initialize()
ds = xr.open_dataset(
'ECMWF/ERA5_LAND/MONTHLY_AGGR',
engine='ee',
crs='EPSG:4326',
scale=1.0,
geometry=ee.Geometry.Rectangle([-180, -90, 180, 90])
)
mean_temp = ds['temperature_2m'].mean(dim='time')
mean_temp.transpose().plot()
After (v0.1.0):
import ee
import xarray as xr
from xee import helpers
import shapely
ee.Initialize()
global_geom = shapely.geometry.box(-180, -90, 180, 90)
grid_params = helpers.fit_geometry(
geometry=global_geom,
grid_crs='EPSG:4326',
grid_scale=(1.0, -1.0)
)
ds = xr.open_dataset(
'ECMWF/ERA5_LAND/MONTHLY_AGGR',
engine='ee',
**grid_params
)
mean_temp = ds['temperature_2m'].mean(dim='time')
mean_temp.plot() # No transpose needed
Pattern 2: Regional analysis with preprocessing
Before (v0.1.0):
import ee
import xarray as xr
def add_ndvi(image):
ndvi = image.normalizedDifference(['SR_B5', 'SR_B4']).rename('NDVI')
return image.addBands(ndvi)
aoi = ee.Geometry.Rectangle([-122.5, 37.5, -122.0, 38.0])
collection = (ee.ImageCollection('LANDSAT/LC09/C02/T1_L2')
.filterDate('2024-01-01', '2024-12-31')
.filterBounds(aoi)
.map(add_ndvi)
.select(['NDVI']))
ds = xr.open_dataset(
collection,
engine='ee',
crs='EPSG:32610',
scale=30,
geometry=aoi
)
After (v0.1.0):
import ee
import xarray as xr
from xee import helpers
import shapely
def add_ndvi(image):
ndvi = image.normalizedDifference(['SR_B5', 'SR_B4']).rename('NDVI')
return image.addBands(ndvi)
# Use shapely for geometry
aoi_shapely = shapely.geometry.box(-122.5, 37.5, -122.0, 38.0)
# Create ee.Geometry for server-side filtering
coords = list(aoi_shapely.exterior.coords)
aoi_ee = ee.Geometry.Polygon(coords)
collection = (ee.ImageCollection('LANDSAT/LC09/C02/T1_L2')
.filterDate('2024-01-01', '2024-12-31')
.filterBounds(aoi_ee)
.map(add_ndvi)
.select(['NDVI']))
grid_params = helpers.fit_geometry(
geometry=aoi_shapely,
geometry_crs='EPSG:4326',
grid_crs='EPSG:32610',
grid_scale=(30, -30)
)
ds = xr.open_dataset(collection, engine='ee', **grid_params)
Pattern 3: Export workflows
Before (v0.1.0):
import xarray as xr
ds = xr.open_dataset(
collection,
engine='ee',
crs='EPSG:4326',
scale=0.1,
geometry=region
)
# Transpose for proper export
data = ds['variable'].transpose('time', 'y', 'x')
data.to_netcdf('output.nc')
After (v0.1.0):
import xarray as xr
from xee import helpers
grid_params = helpers.fit_geometry(
geometry=region,
grid_crs='EPSG:4326',
grid_scale=(0.1, -0.1)
)
ds = xr.open_dataset(collection, engine='ee', **grid_params)
# Already in correct dimension order
data = ds['variable']
data.to_netcdf('output.nc')
4. Understanding Grid Parameters
The Three Required Parameters
crs: Coordinate Reference System (e.g.,'EPSG:4326','EPSG:32610')crs_transform: Affine transformation tuple(a, b, c, d, e, f)where:a= pixel width (x-scale)b= row rotation (typically 0)c= x-coordinate of upper-left cornerd= column rotation (typically 0)e= pixel height (y-scale, typically negative for north-up)f= y-coordinate of upper-left corner
shape_2d: Tuple of(width, height)in pixels
Helper Function Summary
Function |
Use Case |
Parameters |
|---|---|---|
|
Match the native grid of an EE Image/ImageCollection |
EE object |
|
Define grid by pixel size |
geometry, CRS, scale |
|
Define grid by pixel count |
geometry, CRS, shape |
Manual Grid Definition
For advanced use cases, you can still define grid parameters manually:
ds = xr.open_dataset(
'ECMWF/ERA5_LAND/MONTHLY_AGGR',
engine='ee',
crs='EPSG:4326',
crs_transform=(1.0, 0, -180.0, 0, -1.0, 90.0),
shape_2d=(360, 180)
)
5. Troubleshooting
Issue: “Missing required parameter”
Error: TypeError: missing required argument: 'crs_transform'
Solution: You’re using the old API syntax. Update to use grid parameter helpers:
# Add these imports
from xee import helpers
import shapely
# Replace your old xr.open_dataset call with helper-based approach
grid_params = helpers.fit_geometry(
geometry=your_geometry,
grid_crs='EPSG:4326',
grid_scale=(your_scale, -your_scale)
)
ds = xr.open_dataset(collection, engine='ee', **grid_params)
Issue: “Plots are rotated/flipped”
Problem: You’re still using .transpose() from v0.0.x code
Solution: Remove the .transpose() call - v0.1.0 outputs in the correct orientation by default
Issue: “Dimension order is wrong for my export”
Check: What order does your export library expect?
Most modern geospatial tools expect [time, y, x] (which v0.1.0 provides). If you have legacy code expecting [time, x, y], you can still transpose:
# Only if your downstream tool requires the old ordering
data = ds['variable'].transpose('time', 'x', 'y')
Issue: “I need the old behavior”
If you must maintain the old API temporarily, you can pin to v0.0.x:
pip install "xee<0.1.0"
However, we strongly recommend migrating to v0.1.0 for better CF compliance and ecosystem compatibility.
6. Testing Your Migration
After updating your code, verify it works correctly:
import ee
import xarray as xr
from xee import helpers
import shapely
# Initialize Earth Engine
ee.Initialize(project='YOUR-PROJECT')
# Test 1: Open a dataset
ic = ee.ImageCollection('ECMWF/ERA5_LAND/MONTHLY_AGGR').limit(5)
grid_params = helpers.extract_grid_params(ic)
ds = xr.open_dataset(ic, engine='ee', **grid_params)
# Test 2: Check dimensions
print("Dimensions:", ds['temperature_2m'].dims)
# Should print: ('time', 'y', 'x')
# Test 3: Plot without transpose
ds['temperature_2m'].isel(time=0).plot()
# Test 4: Verify CRS and transform
print("CRS:", grid_params['crs'])
print("Transform:", grid_params['crs_transform'])
print("Shape:", grid_params['shape_2d'])
7. Additional Resources
Main Guide - Complete usage guide with examples
API Documentation - Detailed API reference
Client vs Server Guide - Examples using v0.1.0 API
GitHub Issues - Report problems or ask questions
Need Help?
If you encounter issues during migration:
Check this guide for common patterns
Review the updated examples
Open a GitHub Discussion
File an issue with a reproducible example
Welcome to Xee v0.1.0! We believe these changes make the library more powerful, standards-compliant, and easier to integrate with the broader scientific Python ecosystem.