RadGEEToolbox 1.7.3__py3-none-any.whl → 1.7.4__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.
@@ -2,6 +2,7 @@ import ee
2
2
  import math
3
3
  import pandas as pd
4
4
  import numpy as np
5
+ import warnings
5
6
 
6
7
 
7
8
  class Sentinel1Collection:
@@ -230,6 +231,14 @@ class Sentinel1Collection:
230
231
  self._DbFromSigma0 = None
231
232
  self._multilook = None
232
233
 
234
+ def __call__(self):
235
+ """
236
+ Allows the object to be called as a function, returning itself.
237
+ This enables property-like methods to be accessed with or without parentheses
238
+ (e.g., .mosaicByDate or .mosaicByDate()).
239
+ """
240
+ return self
241
+
233
242
  @staticmethod
234
243
  def image_dater(image):
235
244
  """
@@ -245,7 +254,7 @@ class Sentinel1Collection:
245
254
  return image.set({"Date_Filter": date})
246
255
 
247
256
  @staticmethod
248
- def PixelAreaSum(
257
+ def pixelAreaSum(
249
258
  image, band_name, geometry, threshold=-1, scale=10, maxPixels=1e12
250
259
  ):
251
260
  """
@@ -304,8 +313,26 @@ class Sentinel1Collection:
304
313
  # Call to iterate the calculate_and_set_area function over the list of bands, starting with the original image
305
314
  final_image = ee.Image(bands.iterate(calculate_and_set_area, image))
306
315
  return final_image
316
+
317
+ @staticmethod
318
+ def PixelAreaSum(
319
+ image, band_name, geometry, threshold=-1, scale=10, maxPixels=1e12
320
+ ):
321
+ warnings.warn(
322
+ "The 'PixelAreaSum' method is deprecated. Please use 'pixelAreaSum' instead.",
323
+ DeprecationWarning,
324
+ stacklevel=2
325
+ )
326
+ return Sentinel1Collection.pixelAreaSum(
327
+ image=image,
328
+ band_name=band_name,
329
+ geometry=geometry,
330
+ threshold=threshold,
331
+ scale=scale,
332
+ maxPixels=maxPixels,
333
+ )
307
334
 
308
- def PixelAreaSumCollection(
335
+ def pixelAreaSumCollection(
309
336
  self, band_name, geometry, threshold=-1, scale=10, maxPixels=1e12, output_type='ImageCollection', area_data_export_path=None
310
337
  ):
311
338
  """
@@ -332,7 +359,7 @@ class Sentinel1Collection:
332
359
  collection = self.collection
333
360
  # Area calculation for each image in the collection, using the PixelAreaSum function
334
361
  AreaCollection = collection.map(
335
- lambda image: Sentinel1Collection.PixelAreaSum(
362
+ lambda image: Sentinel1Collection.pixelAreaSum(
336
363
  image,
337
364
  band_name=band_name,
338
365
  geometry=geometry,
@@ -348,17 +375,35 @@ class Sentinel1Collection:
348
375
 
349
376
  # If an export path is provided, the area data will be exported to a CSV file
350
377
  if area_data_export_path:
351
- Sentinel1Collection(collection=self._PixelAreaSumCollection).ExportProperties(property_names=prop_names, file_path=area_data_export_path+'.csv')
378
+ Sentinel1Collection(collection=self._PixelAreaSumCollection).exportProperties(property_names=prop_names, file_path=area_data_export_path+'.csv')
352
379
  # Returning the result in the desired format based on output_type argument or raising an error for invalid input
353
380
  if output_type == 'ImageCollection' or output_type == 'ee.ImageCollection':
354
381
  return self._PixelAreaSumCollection
355
382
  elif output_type == 'Sentinel1Collection':
356
383
  return Sentinel1Collection(collection=self._PixelAreaSumCollection)
357
384
  elif output_type == 'DataFrame' or output_type == 'Pandas' or output_type == 'pd' or output_type == 'dataframe' or output_type == 'df':
358
- return Sentinel1Collection(collection=self._PixelAreaSumCollection).ExportProperties(property_names=prop_names)
385
+ return Sentinel1Collection(collection=self._PixelAreaSumCollection).exportProperties(property_names=prop_names)
359
386
  else:
360
387
  raise ValueError("Incorrect `output_type`. The `output_type` argument must be one of the following: 'ImageCollection', 'ee.ImageCollection', 'Sentinel1Collection', 'DataFrame', 'Pandas', 'pd', 'dataframe', or 'df'.")
361
388
 
389
+ def PixelAreaSumCollection(
390
+ self, band_name, geometry, threshold=-1, scale=10, maxPixels=1e12, output_type='ImageCollection', area_data_export_path=None
391
+ ):
392
+ warnings.warn(
393
+ "The 'PixelAreaSumCollection' method is deprecated. Please use 'pixelAreaSumCollection' instead.",
394
+ DeprecationWarning,
395
+ stacklevel=2
396
+ )
397
+ return self.pixelAreaSumCollection(
398
+ band_name=band_name,
399
+ geometry=geometry,
400
+ threshold=threshold,
401
+ scale=scale,
402
+ maxPixels=maxPixels,
403
+ output_type=output_type,
404
+ area_data_export_path=area_data_export_path
405
+ )
406
+
362
407
  @staticmethod
363
408
  def add_month_property_fn(image):
364
409
  """
@@ -707,7 +752,7 @@ class Sentinel1Collection:
707
752
  return Sentinel1Collection(collection=self._speckle_filter)
708
753
 
709
754
  @property
710
- def Sigma0FromDb(self):
755
+ def sigma0FromDb(self):
711
756
  """
712
757
  Property attribute function to convert image collection from decibels to sigma0. Results are calculated once per class object then cached for future use.
713
758
 
@@ -732,9 +777,18 @@ class Sentinel1Collection:
732
777
  sigma0_collection = collection.map(conversion)
733
778
  self._Sigma0FromDb = sigma0_collection
734
779
  return Sentinel1Collection(collection=self._Sigma0FromDb)
780
+
781
+ @property
782
+ def Sigma0FromDb(self):
783
+ warnings.warn(
784
+ "The 'Sigma0FromDb' property is deprecated. Please use 'sigma0FromDb' instead.",
785
+ DeprecationWarning,
786
+ stacklevel=2
787
+ )
788
+ return self.sigma0FromDb
735
789
 
736
790
  @property
737
- def DbFromSigma0(self):
791
+ def dbFromSigma0(self):
738
792
  """
739
793
  Property attribute function to convert image collection from decibels to sigma0. Results are calculated once per class object then cached for future use.
740
794
 
@@ -760,6 +814,15 @@ class Sentinel1Collection:
760
814
  self._DbFromSigma0 = dB_collection
761
815
  return Sentinel1Collection(collection=self._DbFromSigma0)
762
816
 
817
+ @property
818
+ def DbFromSigma0(self):
819
+ warnings.warn(
820
+ "The 'DbFromSigma0' property is deprecated. Please use 'dbFromSigma0' instead.",
821
+ DeprecationWarning,
822
+ stacklevel=2
823
+ )
824
+ return self.dbFromSigma0
825
+
763
826
  @staticmethod
764
827
  def anomaly_fn(image, geometry, band_name=None, anomaly_band_name=None, replace=True, scale=10):
765
828
  """
@@ -847,7 +910,7 @@ class Sentinel1Collection:
847
910
  self._dates = dates
848
911
  return self._dates
849
912
 
850
- def ExportProperties(self, property_names, file_path=None):
913
+ def exportProperties(self, property_names, file_path=None):
851
914
  """
852
915
  Fetches and returns specified properties from each image in the collection as a list, and returns a pandas DataFrame and optionally saves the results to a csv file.
853
916
 
@@ -902,6 +965,14 @@ class Sentinel1Collection:
902
965
  print(f"Properties saved to {file_path}")
903
966
 
904
967
  return df
968
+
969
+ def ExportProperties(self, property_names, file_path=None):
970
+ warnings.warn(
971
+ "The 'ExportProperties' method is deprecated. Please use 'exportProperties' instead.",
972
+ DeprecationWarning,
973
+ stacklevel=2
974
+ )
975
+ return self.exportProperties(property_names=property_names, file_path=file_path)
905
976
 
906
977
  def get_filtered_collection(self):
907
978
  """
@@ -1966,6 +2037,9 @@ class Sentinel1Collection:
1966
2037
 
1967
2038
  if geometry is not None and not isinstance(geometry, ee.Geometry):
1968
2039
  raise ValueError(f'The chosen `geometry`: {geometry} is not a valid ee.Geometry object.')
2040
+
2041
+ native_projection = image_collection.first().select(target_band).projection()
2042
+
1969
2043
  # define the join, which will join all images newer than the current image
1970
2044
  # use system:time_start if the image does not have a Date_Filter property
1971
2045
  if join_method == 'system:time_start':
@@ -2021,7 +2095,7 @@ class Sentinel1Collection:
2021
2095
  # convert the image collection to an image of s_statistic values per pixel
2022
2096
  # where the s_statistic is the sum of partial s values
2023
2097
  # renaming the band as 's_statistic' for later usage
2024
- final_s_image = partial_s_col.sum().rename('s_statistic')
2098
+ final_s_image = partial_s_col.sum().rename('s_statistic').setDefaultProjection(native_projection)
2025
2099
 
2026
2100
 
2027
2101
  ########## PART 2 - VARIANCE and Z-SCORE ##########
@@ -2084,7 +2158,7 @@ class Sentinel1Collection:
2084
2158
  mask = ee.Image(1).clip(geometry)
2085
2159
  final_image = final_image.updateMask(mask)
2086
2160
 
2087
- return final_image
2161
+ return final_image.setDefaultProjection(native_projection)
2088
2162
 
2089
2163
  def sens_slope_trend(self, target_band=None, join_method='system:time_start', geometry=None):
2090
2164
  """
@@ -2120,6 +2194,8 @@ class Sentinel1Collection:
2120
2194
  if geometry is not None and not isinstance(geometry, ee.Geometry):
2121
2195
  raise ValueError(f'The chosen `geometry`: {geometry} is not a valid ee.Geometry object.')
2122
2196
 
2197
+ native_projection = image_collection.first().select(target_band).projection()
2198
+
2123
2199
  # Add Year Band (Time X-Axis)
2124
2200
  def add_year_band(image):
2125
2201
  # Handle user-defined date strings vs system time
@@ -2147,7 +2223,7 @@ class Sentinel1Collection:
2147
2223
  mask = ee.Image(1).clip(geometry)
2148
2224
  slope_band = slope_band.updateMask(mask)
2149
2225
 
2150
- return slope_band
2226
+ return slope_band.setDefaultProjection(native_projection)
2151
2227
 
2152
2228
 
2153
2229
  def mask_to_polygon(self, polygon):
@@ -2161,20 +2237,15 @@ class Sentinel1Collection:
2161
2237
  Sentinel1Collection: masked Sentinel1Collection image collection
2162
2238
 
2163
2239
  """
2164
- if self._geometry_masked_collection is None:
2165
- # Convert the polygon to a mask
2166
- mask = ee.Image.constant(1).clip(polygon)
2240
+ # Convert the polygon to a mask
2241
+ mask = ee.Image.constant(1).clip(polygon)
2167
2242
 
2168
- # Update the mask of each image in the collection
2169
- masked_collection = self.collection.map(lambda img: img.updateMask(mask).copyProperties(img).set('system:time_start', img.get('system:time_start')))
2170
-
2171
- # Update the internal collection state
2172
- self._geometry_masked_collection = Sentinel1Collection(
2173
- collection=masked_collection
2174
- )
2243
+ # Update the mask of each image in the collection
2244
+ masked_collection = self.collection.map(lambda img: img.updateMask(mask)\
2245
+ .copyProperties(img).set('system:time_start', img.get('system:time_start')))
2175
2246
 
2176
2247
  # Return the updated object
2177
- return self._geometry_masked_collection
2248
+ return Sentinel1Collection(collection=masked_collection)
2178
2249
 
2179
2250
  def mask_out_polygon(self, polygon):
2180
2251
  """
@@ -2187,23 +2258,18 @@ class Sentinel1Collection:
2187
2258
  Sentinel1Collection: masked Sentinel1Collection image collection
2188
2259
 
2189
2260
  """
2190
- if self._geometry_masked_out_collection is None:
2191
- # Convert the polygon to a mask
2192
- full_mask = ee.Image.constant(1)
2261
+ # Convert the polygon to a mask
2262
+ full_mask = ee.Image.constant(1)
2193
2263
 
2194
- # Use paint to set pixels inside polygon as 0
2195
- area = full_mask.paint(polygon, 0)
2264
+ # Use paint to set pixels inside polygon as 0
2265
+ area = full_mask.paint(polygon, 0)
2196
2266
 
2197
- # Update the mask of each image in the collection
2198
- masked_collection = self.collection.map(lambda img: img.updateMask(area).copyProperties(img).set('system:time_start', img.get('system:time_start')))
2199
-
2200
- # Update the internal collection state
2201
- self._geometry_masked_out_collection = Sentinel1Collection(
2202
- collection=masked_collection
2203
- )
2267
+ # Update the mask of each image in the collection
2268
+ masked_collection = self.collection.map(lambda img: img.updateMask(area)\
2269
+ .copyProperties(img).set('system:time_start', img.get('system:time_start')))
2204
2270
 
2205
2271
  # Return the updated object
2206
- return self._geometry_masked_out_collection
2272
+ return Sentinel1Collection(collection=masked_collection)
2207
2273
 
2208
2274
  def image_grab(self, img_selector):
2209
2275
  """
@@ -2255,7 +2321,7 @@ class Sentinel1Collection:
2255
2321
  new_col = self.collection.filter(ee.Filter.eq("Date_Filter", img_date))
2256
2322
  return new_col.first()
2257
2323
 
2258
- def CollectionStitch(self, img_col2):
2324
+ def collectionStitch(self, img_col2):
2259
2325
  """
2260
2326
  Function to mosaic two Sentinel1Collection objects which share image dates.
2261
2327
  Mosaics are only formed for dates where both image collections have images.
@@ -2307,9 +2373,17 @@ class Sentinel1Collection:
2307
2373
 
2308
2374
  # Return a Sentinel1Collection instance
2309
2375
  return Sentinel1Collection(collection=new_col)
2376
+
2377
+ def CollectionStitch(self, img_col2):
2378
+ warnings.warn(
2379
+ "The 'CollectionStitch' method is deprecated. Please use 'collectionStitch' instead.",
2380
+ DeprecationWarning,
2381
+ stacklevel=2
2382
+ )
2383
+ return self.collectionStitch(img_col2)
2310
2384
 
2311
2385
  @property
2312
- def MosaicByDate(self):
2386
+ def mosaicByDateDepr(self):
2313
2387
  """
2314
2388
  Property attribute function to mosaic collection images that share the same date.
2315
2389
  The property CLOUD_COVER for each image is used to calculate an overall mean,
@@ -2370,6 +2444,74 @@ class Sentinel1Collection:
2370
2444
 
2371
2445
  # Convert the list of mosaics to an ImageCollection
2372
2446
  return self._MosaicByDate
2447
+
2448
+ @property
2449
+ def mosaicByDate(self):
2450
+ """
2451
+ Property attribute function to mosaic collection images that share the same date.
2452
+
2453
+ The property CLOUD_COVER for each image is used to calculate an overall mean,
2454
+ which replaces the CLOUD_COVER property for each mosaiced image.
2455
+ Server-side friendly.
2456
+
2457
+ NOTE: if images are removed from the collection from cloud filtering, you may have mosaics composed of only one image.
2458
+
2459
+ Returns:
2460
+ LandsatCollection: LandsatCollection image collection with mosaiced imagery and mean CLOUD_COVER as a property
2461
+ """
2462
+ if self._MosaicByDate is None:
2463
+ distinct_dates = self.collection.distinct("Date_Filter")
2464
+
2465
+ # Define a join to link images by Date_Filter
2466
+ filter_date = ee.Filter.equals(leftField="Date_Filter", rightField="Date_Filter")
2467
+ join = ee.Join.saveAll(matchesKey="date_matches")
2468
+
2469
+ # Apply the join
2470
+ # Primary: Distinct dates collection
2471
+ # Secondary: The full original collection
2472
+ joined_col = ee.ImageCollection(join.apply(distinct_dates, self.collection, filter_date))
2473
+
2474
+ # Define the mosaicking function
2475
+ def _mosaic_day(img):
2476
+ # Recover the list of images for this day
2477
+ daily_list = ee.List(img.get("date_matches"))
2478
+ daily_col = ee.ImageCollection.fromImages(daily_list)
2479
+
2480
+ # Create the mosaic
2481
+ mosaic = daily_col.mosaic().setDefaultProjection(img.projection())
2482
+
2483
+ # Properties to preserve from the representative image
2484
+ props_of_interest = [
2485
+ "platform_number",
2486
+ "instrument",
2487
+ "instrumentMode",
2488
+ "orbitNumber_start",
2489
+ "orbitNumber_stop",
2490
+ "orbitProperties_pass",
2491
+ "resolution_meters",
2492
+ "transmitterReceiverPolarisation",
2493
+ "system:time_start",
2494
+ "crs"
2495
+ ]
2496
+
2497
+ # Return mosaic with properties set
2498
+ return mosaic.copyProperties(img, props_of_interest)
2499
+
2500
+ # 5. Map the function and wrap the result
2501
+ mosaiced_col = joined_col.map(_mosaic_day)
2502
+ self._MosaicByDate = Sentinel1Collection(collection=mosaiced_col)
2503
+
2504
+ # Convert the list of mosaics to an ImageCollection
2505
+ return self._MosaicByDate
2506
+
2507
+ @property
2508
+ def MosaicByDate(self):
2509
+ warnings.warn(
2510
+ "The 'MosaicByDate' property is deprecated. Please use 'mosaicByDate' instead.",
2511
+ DeprecationWarning,
2512
+ stacklevel=2
2513
+ )
2514
+ return self.mosaicByDate
2373
2515
 
2374
2516
  @staticmethod
2375
2517
  def ee_to_df(