AEF Mosaic
A global mosaic of Google AlphaEarth Foundations Satellite Embeddings , covering 2017-2025 at ~0.00009° resolution. The dataset is projected in EPSG:4326 with a fixed pixel size in degrees. This means that pixels cover ~10m on the ground at the equator, but less area at higher latitudes. For area-based analysis, consider reprojecting to an equal-area projection, creating your own mosaic in a custom CRS, or using the underlying COGs which are already projected to UTM. This copy is not officially supported by Google.
This dataset implements the following Zarr conventions. These Zarr conventions are not mature and may change.
License
This dataset is licensed under CC-BY 4.0 and requires the following attribution text: "The AlphaEarth Foundations Satellite Embedding dataset is produced by Google and Google DeepMind."
Visualizations
RGB Composite
PCA visualization of the embedding space projected to RGB:
RGB PCA (Zoomed)
Detailed view showing embedding structure at higher resolution:
Cosine Similarity
Similarity search using a query embedding:
Change Detection
Temporal embedding differences highlighting landscape changes:
Quick Start
1 import zarr
2 import numpy as np
3
4 root = zarr.open_group(
5 "s3://us-west-2.opendata.source.coop/tge-labs/aef-mosaic/" ,
6 mode = "r" ,
7 storage_options = { "anon" : True }
8 )
9 embeddings = root[ "embeddings" ]
10
11 # Access a spatial subset (year 0, all bands, y slice, x slice)
12 data = embeddings[ 0 , :, 516000 : 516100 , 832000 : 832100 ]
13
14 # De-quantize to float32
15 data_float = ((data / 127.5 ) ** 2 ) * np.sign(data)
1 import zarr
2 import numpy as np
3
4 root = zarr.open_group(
5 "s3://us-west-2.opendata.source.coop/tge-labs/aef-mosaic/" ,
6 mode = "r" ,
7 storage_options = { "anon" : True }
8 )
9 embeddings = root[ "embeddings" ]
10
11 # Access a spatial subset (year 0, all bands, y slice, x slice)
12 data = embeddings[ 0 , :, 516000 : 516100 , 832000 : 832100 ]
13
14 # De-quantize to float32
15 data_float = ((data / 127.5 ) ** 2 ) * np.sign(data)
Xarray
1 import xarray as xr
2
3
4 def fetch_point (ds, lat, lon, time = 0 ):
5 """Fetch AEF embedding for a single lat/lon point. Returns shape (64,)."""
6 return ds.isel( time = time).sel( x = lon, y = lat, method = "nearest" )
7
8
9 def fetch_bbox (ds, bbox, time = 0 ):
10 """Fetch AEF embeddings for a bounding box. Returns shape (64, y, x)."""
11 minx, miny, maxx, maxy = bbox
12 return ds.isel( time = time).sel( x = slice (minx, maxx), y = slice (maxy, miny))
13
14
15 def main ():
16 ds = xr.open_zarr(
17 "s3://us-west-2.opendata.source.coop/tge-labs/aef-mosaic/" ,
18 storage_options = { "anon" : True }
19 )
20
21 # Fetch embedding for a single point
22 lat, lon = 34.0522 , - 118.2437 # Los Angeles
23 point_data = fetch_point(ds, lat, lon).compute()
24 print ( f "Point shape: { point_data.embeddings.shape } " )
25
26 # Fetch embeddings for a bounding box
27 bbox = [ - 118.279668 , 34.036242 , - 118.20862 , 34.089643 ]
28 bbox_data = fetch_bbox(ds, bbox).compute()
29 print ( f "Bbox shape: { bbox_data.embeddings.shape } " )
30
31
32 if __name__ == "__main__" :
33 main()
1 import xarray as xr
2
3
4 def fetch_point (ds, lat, lon, time = 0 ):
5 """Fetch AEF embedding for a single lat/lon point. Returns shape (64,)."""
6 return ds.isel( time = time).sel( x = lon, y = lat, method = "nearest" )
7
8
9 def fetch_bbox (ds, bbox, time = 0 ):
10 """Fetch AEF embeddings for a bounding box. Returns shape (64, y, x)."""
11 minx, miny, maxx, maxy = bbox
12 return ds.isel( time = time).sel( x = slice (minx, maxx), y = slice (maxy, miny))
13
14
15 def main ():
16 ds = xr.open_zarr(
17 "s3://us-west-2.opendata.source.coop/tge-labs/aef-mosaic/" ,
18 storage_options = { "anon" : True }
19 )
20
21 # Fetch embedding for a single point
22 lat, lon = 34.0522 , - 118.2437 # Los Angeles
23 point_data = fetch_point(ds, lat, lon).compute()
24 print ( f "Point shape: { point_data.embeddings.shape } " )
25
26 # Fetch embeddings for a bounding box
27 bbox = [ - 118.279668 , 34.036242 , - 118.20862 , 34.089643 ]
28 bbox_data = fetch_bbox(ds, bbox).compute()
29 print ( f "Bbox shape: { bbox_data.embeddings.shape } " )
30
31
32 if __name__ == "__main__" :
33 main()
Zarr-python
1 import asyncio
2 from affine import Affine
3 from obstore.store import S3Store
4 from zarr.storage import ObjectStore
5 from zarr.api.asynchronous import open_group
6
7
8 store = S3Store(
9 "us-west-2.opendata.source.coop" ,
10 prefix = "tge-labs/aef-mosaic/" ,
11 region = "us-west-2" ,
12 skip_signature = True ,
13 )
14 zarr_store = ObjectStore(store, read_only = True )
15
16
17 def latlon_to_rowcol (lat, lon, transform):
18 """Convert lat/lon to row/col using the inverse transform."""
19 inv = ~ transform
20 col, row = inv * (lon, lat)
21 return int (row), int (col)
22
23
24 def bbox_to_slices (bbox, transform):
25 """Convert a bounding box to row/col slices."""
26 minx, miny, maxx, maxy = bbox
27 inv = ~ transform
28 col1, row1 = inv * (minx, maxy)
29 col2, row2 = inv * (maxx, miny)
30 row_start, row_stop = int ( min (row1, row2)), int ( max (row1, row2)) + 1
31 col_start, col_stop = int ( min (col1, col2)), int ( max (col1, col2)) + 1
32 return slice (row_start, row_stop), slice (col_start, col_stop)
33
34
35 async def fetch_point (embeddings, transform, lat, lon, year = 0 ):
36 """Fetch AEF embedding for a single lat/lon point. Returns shape (64,)."""
37 row, col = latlon_to_rowcol(lat, lon, transform)
38 return await embeddings.getitem((year, slice ( None ), row, col))
39
40
41 async def fetch_bbox (embeddings, transform, bbox, year = 0 ):
42 """Fetch AEF embeddings for a bounding box. Returns shape (64, rows, cols)."""
43 row_slice, col_slice = bbox_to_slices(bbox, transform)
44 return await embeddings.getitem((year, slice ( None ), row_slice, col_slice))
45
46
47 async def main ():
48 root = await open_group( store = zarr_store, mode = "r" )
49 embeddings = await root.get( "embeddings" )
50 transform = Affine( * root.metadata.attributes[ "spatial:transform" ])
51
52 # Fetch embedding for a single point
53 lat, lon = 34.0522 , - 118.2437 # Los Angeles
54 point_data = await fetch_point(embeddings, transform, lat, lon)
55 print ( f "Point shape: { point_data.shape } " )
56
57 # Fetch embeddings for a bounding box
58 bbox = [ - 118.279668 , 34.036242 , - 118.20862 , 34.089643 ]
59 bbox_data = await fetch_bbox(embeddings, transform, bbox)
60 print ( f "Bbox shape: { bbox_data.shape } " )
61
62
63 if __name__ == "__main__" :
64 asyncio.run(main())
1 import asyncio
2 from affine import Affine
3 from obstore.store import S3Store
4 from zarr.storage import ObjectStore
5 from zarr.api.asynchronous import open_group
6
7
8 store = S3Store(
9 "us-west-2.opendata.source.coop" ,
10 prefix = "tge-labs/aef-mosaic/" ,
11 region = "us-west-2" ,
12 skip_signature = True ,
13 )
14 zarr_store = ObjectStore(store, read_only = True )
15
16
17 def latlon_to_rowcol (lat, lon, transform):
18 """Convert lat/lon to row/col using the inverse transform."""
19 inv = ~ transform
20 col, row = inv * (lon, lat)
21 return int (row), int (col)
22
23
24 def bbox_to_slices (bbox, transform):
25 """Convert a bounding box to row/col slices."""
26 minx, miny, maxx, maxy = bbox
27 inv = ~ transform
28 col1, row1 = inv * (minx, maxy)
29 col2, row2 = inv * (maxx, miny)
30 row_start, row_stop = int ( min (row1, row2)), int ( max (row1, row2)) + 1
31 col_start, col_stop = int ( min (col1, col2)), int ( max (col1, col2)) + 1
32 return slice (row_start, row_stop), slice (col_start, col_stop)
33
34
35 async def fetch_point (embeddings, transform, lat, lon, year = 0 ):
36 """Fetch AEF embedding for a single lat/lon point. Returns shape (64,)."""
37 row, col = latlon_to_rowcol(lat, lon, transform)
38 return await embeddings.getitem((year, slice ( None ), row, col))
39
40
41 async def fetch_bbox (embeddings, transform, bbox, year = 0 ):
42 """Fetch AEF embeddings for a bounding box. Returns shape (64, rows, cols)."""
43 row_slice, col_slice = bbox_to_slices(bbox, transform)
44 return await embeddings.getitem((year, slice ( None ), row_slice, col_slice))
45
46
47 async def main ():
48 root = await open_group( store = zarr_store, mode = "r" )
49 embeddings = await root.get( "embeddings" )
50 transform = Affine( * root.metadata.attributes[ "spatial:transform" ])
51
52 # Fetch embedding for a single point
53 lat, lon = 34.0522 , - 118.2437 # Los Angeles
54 point_data = await fetch_point(embeddings, transform, lat, lon)
55 print ( f "Point shape: { point_data.shape } " )
56
57 # Fetch embeddings for a bounding box
58 bbox = [ - 118.279668 , 34.036242 , - 118.20862 , 34.089643 ]
59 bbox_data = await fetch_bbox(embeddings, transform, bbox)
60 print ( f "Bbox shape: { bbox_data.shape } " )
61
62
63 if __name__ == "__main__" :
64 asyncio.run(main())
Dataset Details
Source Code
The processing pipeline used to create this mosaic is available at:
https://github.com/geospatial-jeff/aef-mosaic
Please send any comments, questions, or points of feedback to the #opening-aef CNG slack channel.