RadGEEToolbox 1.6.8__py3-none-any.whl → 1.6.10__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- RadGEEToolbox/LandsatCollection.py +620 -13
- RadGEEToolbox/Sentinel1Collection.py +153 -7
- RadGEEToolbox/Sentinel2Collection.py +595 -15
- RadGEEToolbox/__init__.py +1 -1
- {radgeetoolbox-1.6.8.dist-info → radgeetoolbox-1.6.10.dist-info}/METADATA +22 -13
- radgeetoolbox-1.6.10.dist-info/RECORD +12 -0
- radgeetoolbox-1.6.8.dist-info/RECORD +0 -12
- {radgeetoolbox-1.6.8.dist-info → radgeetoolbox-1.6.10.dist-info}/WHEEL +0 -0
- {radgeetoolbox-1.6.8.dist-info → radgeetoolbox-1.6.10.dist-info}/licenses/LICENSE.txt +0 -0
- {radgeetoolbox-1.6.8.dist-info → radgeetoolbox-1.6.10.dist-info}/top_level.txt +0 -0
|
@@ -346,12 +346,12 @@ class Sentinel1Collection:
|
|
|
346
346
|
else:
|
|
347
347
|
raise ValueError("output_type must be 'ImageCollection' or 'Sentinel1Collection'")
|
|
348
348
|
|
|
349
|
-
def
|
|
349
|
+
def combine(self, other):
|
|
350
350
|
"""
|
|
351
|
-
|
|
351
|
+
Combines the current Sentinel1Collection with another Sentinel1Collection, using the `combine` method.
|
|
352
352
|
|
|
353
353
|
Args:
|
|
354
|
-
other (Sentinel1Collection): Another Sentinel1Collection to
|
|
354
|
+
other (Sentinel1Collection): Another Sentinel1Collection to combine with current collection.
|
|
355
355
|
|
|
356
356
|
Returns:
|
|
357
357
|
Sentinel1Collection: A new Sentinel1Collection containing images from both collections.
|
|
@@ -364,6 +364,73 @@ class Sentinel1Collection:
|
|
|
364
364
|
merged_collection = self.collection.combine(other.collection)
|
|
365
365
|
return Sentinel1Collection(collection=merged_collection)
|
|
366
366
|
|
|
367
|
+
def merge(self, collections=None, multiband_collection=None, date_key='Date_Filter'):
|
|
368
|
+
"""
|
|
369
|
+
Merge many singleband Sentinel1Collection products into the parent collection,
|
|
370
|
+
or merge a single multiband collection with parent collection,
|
|
371
|
+
pairing images by exact Date_Filter and returning one multiband image per date.
|
|
372
|
+
|
|
373
|
+
NOTE: if you want to merge two multiband collections, use the `combine` method instead.
|
|
374
|
+
|
|
375
|
+
Args:
|
|
376
|
+
collections (list): List of singleband collections to merge with parent collection, effectively adds one band per collection to each image in parent
|
|
377
|
+
multiband_collection (Sentinel1Collection, optional): A multiband collection to merge with parent. Specifying a collection here will override `collections`.
|
|
378
|
+
date_key (str): image property key for exact pairing (default 'Date_Filter')
|
|
379
|
+
|
|
380
|
+
Returns:
|
|
381
|
+
Sentinel1Collection: parent with extra single bands attached (one image per date)
|
|
382
|
+
"""
|
|
383
|
+
|
|
384
|
+
if collections is None and multiband_collection is not None:
|
|
385
|
+
# Exact-date inner-join merge of two collections (adds ALL bands from 'other').
|
|
386
|
+
join = ee.Join.inner()
|
|
387
|
+
flt = ee.Filter.equals(leftField=date_key, rightField=date_key)
|
|
388
|
+
paired = join.apply(self.collection, multiband_collection.collection, flt)
|
|
389
|
+
|
|
390
|
+
def _pair_two(f):
|
|
391
|
+
f = ee.Feature(f)
|
|
392
|
+
a = ee.Image(f.get('primary'))
|
|
393
|
+
b = ee.Image(f.get('secondary'))
|
|
394
|
+
# Overwrite on name collision
|
|
395
|
+
merged = a.addBands(b, None, True)
|
|
396
|
+
# Keep parent props + date key
|
|
397
|
+
merged = merged.copyProperties(a, a.propertyNames())
|
|
398
|
+
merged = merged.set(date_key, a.get(date_key))
|
|
399
|
+
return ee.Image(merged)
|
|
400
|
+
|
|
401
|
+
return Sentinel1Collection(collection=ee.ImageCollection(paired.map(_pair_two)))
|
|
402
|
+
|
|
403
|
+
# Preferred path: merge many singleband products into the parent
|
|
404
|
+
if not isinstance(collections, list) or len(collections) == 0:
|
|
405
|
+
raise ValueError("Provide a non-empty list of Sentinel1Collection objects in `collections`.")
|
|
406
|
+
|
|
407
|
+
result = self.collection
|
|
408
|
+
for extra in collections:
|
|
409
|
+
if not isinstance(extra, Sentinel1Collection):
|
|
410
|
+
raise ValueError("All items in `collections` must be Sentinel1Collection objects.")
|
|
411
|
+
|
|
412
|
+
join = ee.Join.inner()
|
|
413
|
+
flt = ee.Filter.equals(leftField=date_key, rightField=date_key)
|
|
414
|
+
paired = join.apply(result, extra.collection, flt)
|
|
415
|
+
|
|
416
|
+
def _attach_one(f):
|
|
417
|
+
f = ee.Feature(f)
|
|
418
|
+
parent = ee.Image(f.get('primary'))
|
|
419
|
+
sb = ee.Image(f.get('secondary'))
|
|
420
|
+
# Assume singleband product; grab its first band name server-side
|
|
421
|
+
bname = ee.String(sb.bandNames().get(0))
|
|
422
|
+
# Add the single band; overwrite if the name already exists in parent
|
|
423
|
+
merged = parent.addBands(sb.select([bname]).rename([bname]), None, True)
|
|
424
|
+
# Preserve parent props + date key
|
|
425
|
+
merged = merged.copyProperties(parent, parent.propertyNames())
|
|
426
|
+
merged = merged.set(date_key, parent.get(date_key))
|
|
427
|
+
return ee.Image(merged)
|
|
428
|
+
|
|
429
|
+
result = ee.ImageCollection(paired.map(_attach_one))
|
|
430
|
+
|
|
431
|
+
return Sentinel1Collection(collection=result)
|
|
432
|
+
|
|
433
|
+
|
|
367
434
|
@staticmethod
|
|
368
435
|
def multilook_fn(image, looks):
|
|
369
436
|
if looks not in [1, 2, 3, 4]:
|
|
@@ -1634,6 +1701,7 @@ class Sentinel1Collection:
|
|
|
1634
1701
|
def iterate_zonal_stats(
|
|
1635
1702
|
self,
|
|
1636
1703
|
geometries,
|
|
1704
|
+
band=None,
|
|
1637
1705
|
reducer_type="mean",
|
|
1638
1706
|
scale=10,
|
|
1639
1707
|
geometry_names=None,
|
|
@@ -1649,6 +1717,7 @@ class Sentinel1Collection:
|
|
|
1649
1717
|
|
|
1650
1718
|
Args:
|
|
1651
1719
|
geometries (ee.Geometry, ee.Feature, ee.FeatureCollection, list, or tuple): Input geometries for which to extract statistics. Can be a single ee.Geometry, an ee.Feature, an ee.FeatureCollection, a list of (lon, lat) tuples, or a list of ee.Geometry objects. Be careful to NOT provide coordinates as (lat, lon)!
|
|
1720
|
+
band (str, optional): The name of the band to use for statistics. If None, the first band is used. Defaults to None.
|
|
1652
1721
|
reducer_type (str, optional): The ee.Reducer to use, e.g., 'mean', 'median', 'max', 'sum'. Defaults to 'mean'. Any ee.Reducer method can be used.
|
|
1653
1722
|
scale (int, optional): Pixel scale in meters for the reduction. Defaults to 10.
|
|
1654
1723
|
geometry_names (list, optional): A list of string names for the geometries. If provided, must match the number of geometries. Defaults to None.
|
|
@@ -1666,6 +1735,12 @@ class Sentinel1Collection:
|
|
|
1666
1735
|
TypeError: If geometries input type is unsupported.
|
|
1667
1736
|
"""
|
|
1668
1737
|
img_collection_obj = self
|
|
1738
|
+
if band:
|
|
1739
|
+
img_collection_obj = Sentinel1Collection(collection=img_collection_obj.collection.select(band))
|
|
1740
|
+
else:
|
|
1741
|
+
first_image = img_collection_obj.image_grab(0)
|
|
1742
|
+
first_band = first_image.bandNames().get(0)
|
|
1743
|
+
img_collection_obj = Sentinel1Collection(collection=img_collection_obj.collection.select([first_band]))
|
|
1669
1744
|
# Filter collection by dates if provided
|
|
1670
1745
|
if dates:
|
|
1671
1746
|
img_collection_obj = Sentinel1Collection(
|
|
@@ -1748,18 +1823,33 @@ class Sentinel1Collection:
|
|
|
1748
1823
|
stats_fc = image.reduceRegions(
|
|
1749
1824
|
collection=features, reducer=reducer, scale=scale, tileScale=tileScale
|
|
1750
1825
|
)
|
|
1751
|
-
|
|
1826
|
+
|
|
1827
|
+
def guarantee_reducer_property(f):
|
|
1828
|
+
has_property = f.propertyNames().contains(reducer_type)
|
|
1829
|
+
return ee.Algorithms.If(has_property, f, f.set(reducer_type, -9999))
|
|
1830
|
+
fixed_stats_fc = stats_fc.map(guarantee_reducer_property)
|
|
1831
|
+
|
|
1832
|
+
return fixed_stats_fc.map(lambda f: f.set('image_date', image_date))
|
|
1752
1833
|
|
|
1753
1834
|
results_fc = ee.FeatureCollection(img_collection_obj.collection.map(calculate_stats_for_image)).flatten()
|
|
1754
1835
|
df = Sentinel1Collection.ee_to_df(results_fc, remove_geom=True)
|
|
1755
1836
|
|
|
1756
1837
|
# Checking for issues
|
|
1757
1838
|
if df.empty:
|
|
1758
|
-
print("No results found for the given parameters. Check if the geometries intersect with the images, if the dates filter is too restrictive, or if the provided bands are empty.")
|
|
1759
|
-
return df
|
|
1839
|
+
# print("No results found for the given parameters. Check if the geometries intersect with the images, if the dates filter is too restrictive, or if the provided bands are empty.")
|
|
1840
|
+
# return df
|
|
1841
|
+
raise ValueError("No results found for the given parameters. Check if the geometries intersect with the images, if the dates filter is too restrictive, or if the provided bands are empty.")
|
|
1760
1842
|
if reducer_type not in df.columns:
|
|
1761
1843
|
print(f"Warning: Reducer '{reducer_type}' not found in results.")
|
|
1762
|
-
return df
|
|
1844
|
+
# return df
|
|
1845
|
+
|
|
1846
|
+
# Get the number of rows before dropping nulls for a helpful message
|
|
1847
|
+
initial_rows = len(df)
|
|
1848
|
+
df.dropna(subset=[reducer_type], inplace=True)
|
|
1849
|
+
df = df[df[reducer_type] != -9999]
|
|
1850
|
+
dropped_rows = initial_rows - len(df)
|
|
1851
|
+
if dropped_rows > 0:
|
|
1852
|
+
print(f"Warning: Discarded {dropped_rows} results due to failed reductions (e.g., no valid pixels in geometry).")
|
|
1763
1853
|
|
|
1764
1854
|
# Reshape DataFrame to have dates as index and geometry names as columns
|
|
1765
1855
|
pivot_df = df.pivot(index='image_date', columns='geo_name', values=reducer_type)
|
|
@@ -1772,3 +1862,59 @@ class Sentinel1Collection:
|
|
|
1772
1862
|
print(f"Zonal stats saved to {file_path}.csv")
|
|
1773
1863
|
return
|
|
1774
1864
|
return pivot_df
|
|
1865
|
+
|
|
1866
|
+
def export_to_asset_collection(
|
|
1867
|
+
self,
|
|
1868
|
+
asset_collection_path,
|
|
1869
|
+
region,
|
|
1870
|
+
scale,
|
|
1871
|
+
dates=None,
|
|
1872
|
+
filename_prefix="",
|
|
1873
|
+
crs=None,
|
|
1874
|
+
max_pixels=int(1e13),
|
|
1875
|
+
description_prefix="export"
|
|
1876
|
+
):
|
|
1877
|
+
"""
|
|
1878
|
+
Exports an image collection to a Google Earth Engine asset collection. The asset collection will be created if it does not already exist,
|
|
1879
|
+
and each image exported will be named according to the provided filename prefix and date.
|
|
1880
|
+
|
|
1881
|
+
Args:
|
|
1882
|
+
asset_collection_path (str): The path to the asset collection.
|
|
1883
|
+
region (ee.Geometry): The region to export.
|
|
1884
|
+
scale (int): The scale of the export.
|
|
1885
|
+
dates (list, optional): The dates to export. Defaults to None.
|
|
1886
|
+
filename_prefix (str, optional): The filename prefix. Defaults to "", i.e. blank.
|
|
1887
|
+
crs (str, optional): The coordinate reference system. Defaults to None, which will use the image's CRS.
|
|
1888
|
+
max_pixels (int, optional): The maximum number of pixels. Defaults to int(1e13).
|
|
1889
|
+
description_prefix (str, optional): The description prefix. Defaults to "export".
|
|
1890
|
+
|
|
1891
|
+
Returns:
|
|
1892
|
+
None: (queues export tasks)
|
|
1893
|
+
"""
|
|
1894
|
+
ic = self.collection
|
|
1895
|
+
if dates is None:
|
|
1896
|
+
dates = self.dates
|
|
1897
|
+
try:
|
|
1898
|
+
ee.data.createAsset({'type': 'ImageCollection'}, asset_collection_path)
|
|
1899
|
+
except Exception:
|
|
1900
|
+
pass
|
|
1901
|
+
|
|
1902
|
+
for date_str in dates:
|
|
1903
|
+
img = ee.Image(ic.filter(ee.Filter.eq('Date_Filter', date_str)).first())
|
|
1904
|
+
asset_id = asset_collection_path + "/" + filename_prefix + date_str
|
|
1905
|
+
desc = description_prefix + "_" + filename_prefix + date_str
|
|
1906
|
+
|
|
1907
|
+
params = {
|
|
1908
|
+
'image': img,
|
|
1909
|
+
'description': desc,
|
|
1910
|
+
'assetId': asset_id,
|
|
1911
|
+
'region': region,
|
|
1912
|
+
'scale': scale,
|
|
1913
|
+
'maxPixels': max_pixels
|
|
1914
|
+
}
|
|
1915
|
+
if crs:
|
|
1916
|
+
params['crs'] = crs
|
|
1917
|
+
|
|
1918
|
+
ee.batch.Export.image.toAsset(**params).start()
|
|
1919
|
+
|
|
1920
|
+
print("Queued", len(dates), "export tasks to", asset_collection_path)
|