openforis-whisp 2.0.0a5__py3-none-any.whl → 2.0.0b1__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.
openforis_whisp/risk.py CHANGED
@@ -112,6 +112,7 @@ def whisp_risk(
112
112
  high_name: str = "yes",
113
113
  explicit_unit_type: str = None,
114
114
  national_codes: list[str] = None, # List of ISO2 country codes to filter by
115
+ custom_bands_info: dict = None, # New parameter for custom band risk info
115
116
  ) -> data_lookup_type:
116
117
  """
117
118
  Adds the EUDR (European Union Deforestation Risk) column to the DataFrame based on indicator values.
@@ -134,25 +135,43 @@ def whisp_risk(
134
135
  high_name (str, optional): Value shown in table if more than the threshold. Defaults to "yes".
135
136
  explicit_unit_type (str, optional): Override the autodetected unit type ('ha' or 'percent').
136
137
  If not provided, will detect from dataframe 'unit' column.
138
+ custom_bands_info (dict, optional): Custom band risk information. Dict format:
139
+ {
140
+ 'band_name': {
141
+ 'theme': 'treecover', # or 'commodities', 'disturbance_before', 'disturbance_after'
142
+ 'theme_timber': 'primary', # or 'naturally_reg_2020', 'planted_plantation_2020', etc.
143
+ 'use_for_risk': 1, # 0 or 1
144
+ 'use_for_risk_timber': 1, # 0 or 1
145
+ }
146
+ }
147
+ If None, custom bands won't be included in risk calculations.
137
148
 
138
149
  Returns:
139
- data_lookup_type: DataFrame with added 'EUDR_risk' column.
150
+ data_lookup_type: DataFrame with added risk columns.
140
151
  """
141
- # Determine the unit type to use based on input data and overrid
152
+ # Determine the unit type
142
153
  unit_type = detect_unit_type(df, explicit_unit_type)
143
-
144
154
  print(f"Using unit type: {unit_type}")
145
155
 
146
156
  lookup_df_copy = lookup_gee_datasets_df.copy()
147
157
 
148
- # filter by national codes (even if None - this removes all country columns unless specified)
158
+ # Add custom bands to lookup if provided
159
+ if custom_bands_info:
160
+ lookup_df_copy = add_custom_bands_info_to_lookup(
161
+ lookup_df_copy, custom_bands_info, df.columns
162
+ )
163
+ print(f"Including custom bands: {list(custom_bands_info.keys())}")
164
+ # print(f"appended custom bands info to lookup table")
165
+ if national_codes:
166
+ print(f"Filtering by national codes: {national_codes}")
167
+ # Filter by national codes
149
168
  filtered_lookup_gee_datasets_df = filter_lookup_by_country_codes(
150
169
  lookup_df=lookup_df_copy,
151
170
  filter_col="ISO2_code",
152
171
  national_codes=national_codes,
153
172
  )
154
173
 
155
- # Rest of the function remains the same, but pass unit_type to add_indicators
174
+ # Get indicator columns (now includes custom bands)
156
175
  if ind_1_input_columns is None:
157
176
  ind_1_input_columns = get_cols_ind_01_treecover(filtered_lookup_gee_datasets_df)
158
177
  if ind_2_input_columns is None:
@@ -393,7 +412,7 @@ def add_eudr_risk_timber_col(
393
412
  """
394
413
 
395
414
  for index, row in df.iterrows():
396
- # If there is a commodity in 2020 (ind_2_name)
415
+ # If there is a commodity in 2020 (ind_2_name)
397
416
  # OR if there is planted-plantation in 2020 (ind_7_name) AND no agriculture in 2023 (ind_10_name), set EUDR_risk_timber to "low"
398
417
  if row[ind_2_name] == "yes" or (
399
418
  row[ind_7_name] == "yes" and row[ind_10_name] == "no"
@@ -411,7 +430,7 @@ def add_eudr_risk_timber_col(
411
430
  ind_8_name
412
431
  ] == "yes":
413
432
  df.at[index, "risk_timber"] = "high"
414
- # No data yet on OWL conversion
433
+ # No data yet on OWL conversion
415
434
  # If primary or naturally regenerating or planted forest in 2020 and OWL in 2023, set EUDR_risk to high
416
435
  # elif (row[ind_5_name] == "yes" or row[ind_6_name] == "yes" or row[ind_7_name] == "yes") and row[ind_10_name] == "yes":
417
436
  # df.at[index, 'EUDR_risk_timber'] = "high"
@@ -699,7 +718,7 @@ def get_cols_ind_09_treecover_after_2020(lookup_gee_datasets_df):
699
718
  return list(
700
719
  lookup_gee_datasets_df["name"][
701
720
  (lookup_gee_datasets_df["use_for_risk_timber"] == 1)
702
- & (lookup_gee_datasets_df["theme_timber"] == "treecover_post2020")
721
+ & (lookup_gee_datasets_df["theme_timber"] == "treecover_after_2020")
703
722
  ]
704
723
  )
705
724
 
@@ -769,3 +788,61 @@ def clamp(
769
788
  def check_range(value: float) -> None:
770
789
  if not (0 <= value <= 100):
771
790
  raise ValueError("Value must be between 0 and 100.")
791
+
792
+
793
+ def add_custom_bands_info_to_lookup(
794
+ lookup_df: pd.DataFrame, custom_bands_info: dict, df_columns: list
795
+ ) -> pd.DataFrame:
796
+ """
797
+ Add custom bands to the lookup DataFrame for risk calculations.
798
+
799
+ Parameters
800
+ ----------
801
+ lookup_df : pd.DataFrame
802
+ Original lookup DataFrame
803
+ custom_bands_info : dict
804
+ Custom band definitions with risk info
805
+ df_columns : list
806
+ List of columns in the actual data DataFrame
807
+
808
+ Returns
809
+ -------
810
+ pd.DataFrame
811
+ Lookup DataFrame with custom bands added
812
+ """
813
+ custom_rows = []
814
+
815
+ for band_name, band_info in custom_bands_info.items():
816
+ # Only add bands that actually exist in the DataFrame
817
+ if band_name in df_columns:
818
+ custom_row = {
819
+ "name": band_name, # Use the band name as provided
820
+ "theme": band_info.get(
821
+ "theme", pd.NA
822
+ ), # default to empty if not provided
823
+ "theme_timber": band_info.get(
824
+ "theme_timber", pd.NA
825
+ ), # default to empty if not provided
826
+ "use_for_risk": band_info.get(
827
+ "use_for_risk", 0
828
+ ), # default to 0 if not provided
829
+ "use_for_risk_timber": band_info.get(
830
+ "use_for_risk_timber", 0
831
+ ), # default to 0 if not provided
832
+ "exclude_from_output": 0, # 0 here is so we don't exclude custom bands
833
+ "ISO2_code": pd.NA, # Global, i.e., empty string, by default
834
+ # Add other required columns with defaults
835
+ "col_type": "float64", # default to float64 if not provided
836
+ "is_nullable": 1,
837
+ "is_required": 0,
838
+ "order": 9999, # Put at end unless specified otherwise
839
+ "corresponding_variable": pd.NA, # not necessary for custom bands
840
+ }
841
+ custom_rows.append(custom_row)
842
+
843
+ if custom_rows:
844
+ custom_df = pd.DataFrame(custom_rows)
845
+ # Combine with original lookup
846
+ lookup_df = pd.concat([lookup_df, custom_df], ignore_index=True)
847
+
848
+ return lookup_df
openforis_whisp/stats.py CHANGED
@@ -27,7 +27,10 @@ from .data_conversion import (
27
27
  # convert_csv_to_geojson,
28
28
  convert_df_to_geojson,
29
29
  ) # copied functions from whisp-api and geemap (accessed 2024) to avoid dependency
30
- from .reformat import validate_dataframe_using_lookups
30
+ from .reformat import (
31
+ validate_dataframe_using_lookups,
32
+ validate_dataframe_using_lookups_flexible,
33
+ )
31
34
 
32
35
  # NB functions that included "formatted" in the name apply a schema for validation and reformatting of the output dataframe. The schema is created from lookup tables.
33
36
 
@@ -38,6 +41,8 @@ def whisp_formatted_stats_geojson_to_df(
38
41
  remove_geom=False,
39
42
  national_codes=None,
40
43
  unit_type="ha",
44
+ whisp_image=None,
45
+ custom_bands=None, # New parameter
41
46
  ) -> pd.DataFrame:
42
47
  """
43
48
  Main function for most users.
@@ -65,6 +70,15 @@ def whisp_formatted_stats_geojson_to_df(
65
70
  List of ISO2 country codes to include national datasets.
66
71
  unit_type: str, optional
67
72
  Whether to use hectares ("ha") or percentage ("percent"), by default "ha".
73
+ whisp_image : ee.Image, optional
74
+ Pre-combined multiband Earth Engine Image containing all Whisp datasets.
75
+ If provided, this image will be used instead of combining datasets based on national_codes.
76
+ If None, datasets will be combined automatically using national_codes parameter.
77
+ custom_bands : list or dict, optional
78
+ Custom band information for extra columns. Can be:
79
+ - List of band names: ['Aa_test', 'elevation']
80
+ - Dict with types: {'Aa_test': 'float64', 'elevation': 'float32'}
81
+ - None: preserves all extra columns automatically
68
82
 
69
83
  Returns
70
84
  -------
@@ -78,7 +92,9 @@ def whisp_formatted_stats_geojson_to_df(
78
92
  external_id_column,
79
93
  remove_geom,
80
94
  national_codes=national_codes,
81
- unit_type=unit_type, # Fixed: now it's a keyword argument
95
+ unit_type=unit_type,
96
+ whisp_image=whisp_image,
97
+ custom_bands=custom_bands, # Pass through
82
98
  )
83
99
 
84
100
 
@@ -89,6 +105,7 @@ def whisp_formatted_stats_geojson_to_geojson(
89
105
  geo_column: str = "geo",
90
106
  national_codes=None,
91
107
  unit_type="ha",
108
+ whisp_image=None, # New parameter
92
109
  ):
93
110
  """
94
111
  Convert a formatted GeoJSON file with a geo column into a GeoJSON file containing Whisp stats.
@@ -107,6 +124,8 @@ def whisp_formatted_stats_geojson_to_geojson(
107
124
  List of ISO2 country codes to include national datasets.
108
125
  unit_type : str, optional
109
126
  Whether to use hectares ("ha") or percentage ("percent"), by default "ha".
127
+ whisp_image : ee.Image, optional
128
+ Pre-combined multiband Earth Engine Image containing all Whisp datasets.
110
129
 
111
130
  Returns
112
131
  -------
@@ -117,6 +136,7 @@ def whisp_formatted_stats_geojson_to_geojson(
117
136
  external_id_column=external_id_column,
118
137
  national_codes=national_codes,
119
138
  unit_type=unit_type,
139
+ whisp_image=whisp_image, # Pass through
120
140
  )
121
141
  # Convert the df to GeoJSON
122
142
  convert_df_to_geojson(df, output_geojson_filepath, geo_column)
@@ -131,6 +151,7 @@ def whisp_formatted_stats_ee_to_geojson(
131
151
  geo_column: str = "geo",
132
152
  national_codes=None,
133
153
  unit_type="ha",
154
+ whisp_image=None, # New parameter
134
155
  ):
135
156
  """
136
157
  Convert an Earth Engine FeatureCollection to a GeoJSON file containing Whisp stats.
@@ -149,6 +170,8 @@ def whisp_formatted_stats_ee_to_geojson(
149
170
  List of ISO2 country codes to include national datasets.
150
171
  unit_type : str, optional
151
172
  Whether to use hectares ("ha") or percentage ("percent"), by default "ha".
173
+ whisp_image : ee.Image, optional
174
+ Pre-combined multiband Earth Engine Image containing all Whisp datasets.
152
175
  Returns
153
176
  -------
154
177
  None
@@ -159,6 +182,7 @@ def whisp_formatted_stats_ee_to_geojson(
159
182
  external_id_column,
160
183
  national_codes=national_codes,
161
184
  unit_type=unit_type,
185
+ whisp_image=whisp_image, # Pass through
162
186
  )
163
187
 
164
188
  # Convert the df to GeoJSON
@@ -173,6 +197,8 @@ def whisp_formatted_stats_ee_to_df(
173
197
  remove_geom=False,
174
198
  national_codes=None,
175
199
  unit_type="ha",
200
+ whisp_image=None,
201
+ custom_bands=None, # New parameter
176
202
  ) -> pd.DataFrame:
177
203
  """
178
204
  Convert a feature collection to a validated DataFrame with Whisp statistics.
@@ -189,6 +215,10 @@ def whisp_formatted_stats_ee_to_df(
189
215
  List of ISO2 country codes to include national datasets.
190
216
  unit_type : str, optional
191
217
  Whether to use hectares ("ha") or percentage ("percent"), by default "ha".
218
+ whisp_image : ee.Image, optional
219
+ Pre-combined multiband Earth Engine Image containing all Whisp datasets.
220
+ custom_bands : list or dict, optional
221
+ Custom band information for extra columns.
192
222
 
193
223
  Returns
194
224
  -------
@@ -202,11 +232,12 @@ def whisp_formatted_stats_ee_to_df(
202
232
  remove_geom,
203
233
  national_codes=national_codes,
204
234
  unit_type=unit_type,
235
+ whisp_image=whisp_image,
205
236
  )
206
237
 
207
- # Pass national_codes to validation function to filter schema
208
- validated_df = validate_dataframe_using_lookups(
209
- df_stats, national_codes=national_codes
238
+ # Use flexible validation that handles custom bands
239
+ validated_df = validate_dataframe_using_lookups_flexible(
240
+ df_stats, national_codes=national_codes, custom_bands=custom_bands
210
241
  )
211
242
  return validated_df
212
243
 
@@ -220,6 +251,7 @@ def whisp_stats_geojson_to_df(
220
251
  remove_geom=False,
221
252
  national_codes=None,
222
253
  unit_type="ha",
254
+ whisp_image=None, # New parameter
223
255
  ) -> pd.DataFrame:
224
256
  """
225
257
  Convert a GeoJSON file to a pandas DataFrame with Whisp statistics.
@@ -236,6 +268,8 @@ def whisp_stats_geojson_to_df(
236
268
  List of ISO2 country codes to include national datasets.
237
269
  unit_type : str, optional
238
270
  Whether to use hectares ("ha") or percentage ("percent"), by default "ha".
271
+ whisp_image : ee.Image, optional
272
+ Pre-combined multiband Earth Engine Image containing all Whisp datasets.
239
273
 
240
274
  Returns
241
275
  -------
@@ -250,6 +284,7 @@ def whisp_stats_geojson_to_df(
250
284
  remove_geom,
251
285
  national_codes=national_codes,
252
286
  unit_type=unit_type,
287
+ whisp_image=whisp_image, # Pass through
253
288
  )
254
289
 
255
290
 
@@ -257,6 +292,7 @@ def whisp_stats_geojson_to_ee(
257
292
  input_geojson_filepath: Path | str,
258
293
  external_id_column=None,
259
294
  national_codes=None,
295
+ whisp_image=None, # New parameter
260
296
  ) -> ee.FeatureCollection:
261
297
  """
262
298
  Convert a GeoJSON file to an Earth Engine FeatureCollection with Whisp statistics.
@@ -269,6 +305,8 @@ def whisp_stats_geojson_to_ee(
269
305
  The name of the external ID column, by default None.
270
306
  national_codes : list, optional
271
307
  List of ISO2 country codes to include national datasets.
308
+ whisp_image : ee.Image, optional
309
+ Pre-combined multiband Earth Engine Image containing all Whisp datasets.
272
310
 
273
311
  Returns
274
312
  -------
@@ -278,7 +316,10 @@ def whisp_stats_geojson_to_ee(
278
316
  feature_collection = convert_geojson_to_ee(str(input_geojson_filepath))
279
317
 
280
318
  return whisp_stats_ee_to_ee(
281
- feature_collection, external_id_column, national_codes=national_codes
319
+ feature_collection,
320
+ external_id_column,
321
+ national_codes=national_codes,
322
+ whisp_image=whisp_image, # Pass through
282
323
  )
283
324
 
284
325
 
@@ -288,6 +329,7 @@ def whisp_stats_geojson_to_geojson(
288
329
  external_id_column=None,
289
330
  national_codes=None,
290
331
  unit_type="ha",
332
+ whisp_image=None, # New parameter
291
333
  ):
292
334
  """
293
335
  Convert a GeoJSON file to a GeoJSON object containing Whisp stats for the input ROI.
@@ -304,6 +346,8 @@ def whisp_stats_geojson_to_geojson(
304
346
  List of ISO2 country codes to include national datasets.
305
347
  unit_type : str, optional
306
348
  Whether to use hectares ("ha") or percentage ("percent"), by default "ha".
349
+ whisp_image : ee.Image, optional
350
+ Pre-combined multiband Earth Engine Image containing all Whisp datasets.
307
351
 
308
352
  Returns
309
353
  -------
@@ -318,6 +362,7 @@ def whisp_stats_geojson_to_geojson(
318
362
  external_id_column,
319
363
  national_codes=national_codes,
320
364
  unit_type=unit_type,
365
+ whisp_image=whisp_image, # Pass through
321
366
  )
322
367
 
323
368
  # Convert the stats FeatureCollection to GeoJSON
@@ -333,6 +378,7 @@ def whisp_stats_geojson_to_drive(
333
378
  external_id_column=None,
334
379
  national_codes=None,
335
380
  unit_type="ha",
381
+ whisp_image=None, # New parameter
336
382
  ):
337
383
  """
338
384
  Export Whisp statistics for a GeoJSON file to Google Drive.
@@ -347,6 +393,8 @@ def whisp_stats_geojson_to_drive(
347
393
  List of ISO2 country codes to include national datasets.
348
394
  unit_type : str, optional
349
395
  Whether to use hectares ("ha") or percentage ("percent"), by default "ha".
396
+ whisp_image : ee.Image, optional
397
+ Pre-combined multiband Earth Engine Image containing all Whisp datasets.
350
398
 
351
399
  Returns
352
400
  -------
@@ -364,6 +412,7 @@ def whisp_stats_geojson_to_drive(
364
412
  external_id_column,
365
413
  national_codes=national_codes,
366
414
  unit_type=unit_type,
415
+ whisp_image=whisp_image, # Pass through
367
416
  )
368
417
 
369
418
  except Exception as e:
@@ -376,6 +425,7 @@ def whisp_stats_ee_to_ee(
376
425
  national_codes=None,
377
426
  unit_type="ha",
378
427
  keep_properties=None,
428
+ whisp_image=None, # New parameter
379
429
  ):
380
430
  """
381
431
  Process a feature collection to get statistics for each feature.
@@ -389,6 +439,9 @@ def whisp_stats_ee_to_ee(
389
439
  - None: Remove all properties (default behavior)
390
440
  - True: Keep all properties
391
441
  - list: Keep only the specified properties
442
+ whisp_image (ee.Image, optional): Pre-combined multiband Earth Engine Image containing
443
+ all Whisp datasets. If provided, this image will be used instead of combining
444
+ datasets based on national_codes.
392
445
 
393
446
  Returns:
394
447
  ee.FeatureCollection: The output feature collection with statistics.
@@ -449,7 +502,10 @@ def whisp_stats_ee_to_ee(
449
502
  feature_collection = _keep_fc_properties(feature_collection, keep_properties)
450
503
 
451
504
  fc = get_stats(
452
- feature_collection, national_codes=national_codes, unit_type=unit_type
505
+ feature_collection,
506
+ national_codes=national_codes,
507
+ unit_type=unit_type,
508
+ whisp_image=whisp_image, # Pass through
453
509
  )
454
510
 
455
511
  return add_id_to_feature_collection(dataset=fc, id_name=plot_id_column)
@@ -478,6 +534,7 @@ def whisp_stats_ee_to_df(
478
534
  remove_geom=False,
479
535
  national_codes=None,
480
536
  unit_type="ha",
537
+ whisp_image=None, # New parameter
481
538
  ) -> pd.DataFrame:
482
539
  """
483
540
  Convert a Google Earth Engine FeatureCollection to a pandas DataFrame and convert ISO3 to ISO2 country codes.
@@ -494,25 +551,36 @@ def whisp_stats_ee_to_df(
494
551
  List of ISO2 country codes to include national datasets.
495
552
  unit_type : str, optional
496
553
  Whether to use hectares ("ha") or percentage ("percent"), by default "ha".
554
+ whisp_image : ee.Image, optional
555
+ Pre-combined multiband Earth Engine Image containing all Whisp datasets.
497
556
 
498
557
  Returns
499
558
  -------
500
559
  df_stats : pd.DataFrame
501
560
  The dataframe containing the Whisp stats for the input ROI.
502
561
  """
562
+ # First, do the whisp processing to get the EE feature collection with stats
563
+ try:
564
+ stats_feature_collection = whisp_stats_ee_to_ee(
565
+ feature_collection,
566
+ external_id_column,
567
+ national_codes=national_codes,
568
+ unit_type=unit_type,
569
+ whisp_image=whisp_image, # Pass through
570
+ )
571
+ except Exception as e:
572
+ print(f"An error occurred during Whisp stats processing: {e}")
573
+ raise e
574
+
575
+ # Then, convert the EE feature collection to DataFrame
503
576
  try:
504
577
  df_stats = convert_ee_to_df(
505
- ee_object=whisp_stats_ee_to_ee(
506
- feature_collection,
507
- external_id_column,
508
- national_codes=national_codes,
509
- unit_type=unit_type,
510
- ),
578
+ ee_object=stats_feature_collection,
511
579
  remove_geom=remove_geom,
512
580
  )
513
581
  except Exception as e:
514
582
  print(f"An error occurred during the conversion from EE to DataFrame: {e}")
515
- return pd.DataFrame() # Return an empty DataFrame in case of error
583
+ raise e
516
584
 
517
585
  try:
518
586
  df_stats = convert_iso3_to_iso2(
@@ -532,6 +600,7 @@ def whisp_stats_ee_to_drive(
532
600
  external_id_column=None,
533
601
  national_codes=None,
534
602
  unit_type="ha",
603
+ whisp_image=None, # New parameter
535
604
  ):
536
605
  """
537
606
  Export Whisp statistics for a feature collection to Google Drive.
@@ -546,6 +615,8 @@ def whisp_stats_ee_to_drive(
546
615
  List of ISO2 country codes to include national datasets.
547
616
  unit_type : str, optional
548
617
  Whether to use hectares ("ha") or percentage ("percent"), by default "ha".
618
+ whisp_image : ee.Image, optional
619
+ Pre-combined multiband Earth Engine Image containing all Whisp datasets.
549
620
  Returns
550
621
  -------
551
622
  None
@@ -557,6 +628,7 @@ def whisp_stats_ee_to_drive(
557
628
  external_id_column,
558
629
  national_codes=national_codes,
559
630
  unit_type=unit_type,
631
+ whisp_image=whisp_image, # Pass through
560
632
  ),
561
633
  description="whisp_output_table",
562
634
  # folder="whisp_results",
@@ -574,29 +646,42 @@ def whisp_stats_ee_to_drive(
574
646
 
575
647
 
576
648
  # Get stats for a feature or feature collection
577
- def get_stats(feature_or_feature_col, national_codes=None, unit_type="ha"):
649
+ def get_stats(
650
+ feature_or_feature_col, national_codes=None, unit_type="ha", whisp_image=None
651
+ ):
578
652
  """
579
- Get stats for a feature or feature collection with optional filtering by national codes.
653
+ Get stats for a feature or feature collection with optional pre-combined image.
580
654
 
581
- Parameters
582
- ----------
583
- feature_or_feature_col : ee.Feature or ee.FeatureCollection
584
- The input feature or feature collection to analyze
585
- national_codes : list, optional
586
- List of ISO2 country codes to include national datasets
655
+ Parameters
656
+ ----------
657
+ feature_or_feature_col : ee.Feature or ee.FeatureCollection
658
+ The input feature or feature collection to analyze
659
+ national_codes : list, optional
660
+ List of ISO2 country codes to include national datasets.
661
+ Only used if whisp_image is None.
587
662
  unit_type : str, optional
588
- Whether to use hectares ("ha") or percentage ("percent"), by default "ha".
589
- Returns
590
- -------
591
- ee.FeatureCollection
592
- Feature collection with calculated statistics
663
+ Whether to use hectares ("ha") or percentage ("percent"), by default "ha".
664
+ whisp_image : ee.Image, optional
665
+ Pre-combined multiband Earth Engine Image containing all Whisp datasets.
666
+ If provided, this will be used instead of combining datasets based on national_codes.
667
+ If None, datasets will be combined automatically using national_codes parameter.
668
+ Returns
669
+ -------
670
+ ee.FeatureCollection
671
+ Feature collection with calculated statistics
593
672
  """
673
+
674
+ # Use provided image or combine datasets
675
+ if whisp_image is not None:
676
+ img_combined = whisp_image
677
+ print("Using provided whisp_image")
678
+ else:
679
+ img_combined = combine_datasets(national_codes=national_codes)
680
+ print(f"Combining datasets with national_codes: {national_codes}")
681
+
594
682
  # Check if the input is a Feature or a FeatureCollection
595
683
  if isinstance(feature_or_feature_col, ee.Feature):
596
- # If the input is a Feature, call the server-side function for processing
597
- print("feature")
598
- # For a single feature, we need to combine datasets with the national_codes filter
599
- img_combined = combine_datasets(national_codes=national_codes)
684
+ print("Processing single feature")
600
685
  output = ee.FeatureCollection(
601
686
  [
602
687
  get_stats_feature(
@@ -605,9 +690,12 @@ def get_stats(feature_or_feature_col, national_codes=None, unit_type="ha"):
605
690
  ]
606
691
  )
607
692
  elif isinstance(feature_or_feature_col, ee.FeatureCollection):
608
- # If the input is a FeatureCollection, call the server-side function for processing
693
+ print("Processing feature collection")
609
694
  output = get_stats_fc(
610
- feature_or_feature_col, national_codes=national_codes, unit_type=unit_type
695
+ feature_or_feature_col,
696
+ national_codes=national_codes,
697
+ unit_type=unit_type,
698
+ img_combined=img_combined, # Pass the image directly
611
699
  )
612
700
  else:
613
701
  output = "Check inputs: not an ee.Feature or ee.FeatureCollection"
@@ -615,28 +703,33 @@ def get_stats(feature_or_feature_col, national_codes=None, unit_type="ha"):
615
703
 
616
704
 
617
705
  # Get statistics for a feature collection
618
- def get_stats_fc(feature_col, national_codes=None, unit_type="ha"):
706
+ def get_stats_fc(feature_col, national_codes=None, unit_type="ha", img_combined=None):
619
707
  """
620
- Calculate statistics for a feature collection using Whisp datasets.
708
+ Calculate statistics for a feature collection using Whisp datasets.
621
709
 
622
- Parameters
623
- ----------
624
- feature_col : ee.FeatureCollection
625
- The input feature collection to analyze
626
- national_codes : list, optional
627
- List of ISO2 country codes (e.g., ["BR", "US"]) to include national datasets.
628
- If provided, only national datasets for these countries and global datasets will be used.
629
- If None (default), only global datasets will be used.
710
+ Parameters
711
+ ----------
712
+ feature_col : ee.FeatureCollection
713
+ The input feature collection to analyze
714
+ national_codes : list, optional
715
+ List of ISO2 country codes (e.g., ["BR", "US"]) to include national datasets.
716
+ If provided, only national datasets for these countries and global datasets will be used.
717
+ If None (default), only global datasets will be used.
718
+ Only used if img_combined is None.
630
719
  unit_type : str, optional
631
- Whether to use hectares ("ha") or percentage ("percent"), by default "ha".
632
- Returns
633
- -------
634
- ee.FeatureCollection
635
- Feature collection with calculated statistics
720
+ Whether to use hectares ("ha") or percentage ("percent"), by default "ha".
721
+ img_combined : ee.Image, optional
722
+ Pre-combined multiband image containing all Whisp datasets.
723
+ If provided, this will be used instead of combining datasets based on national_codes.
724
+ Returns
725
+ -------
726
+ ee.FeatureCollection
727
+ Feature collection with calculated statistics
636
728
  """
637
- img_combined = combine_datasets(
638
- national_codes=national_codes
639
- ) # Pass national_codes to combine_datasets
729
+
730
+ # # Use provided image or combine datasets
731
+ # if img_combined is None:
732
+ # img_combined = combine_datasets(national_codes=national_codes)
640
733
 
641
734
  out_feature_col = ee.FeatureCollection(
642
735
  feature_col.map(
@@ -651,6 +744,7 @@ def get_stats_fc(feature_col, national_codes=None, unit_type="ha"):
651
744
 
652
745
 
653
746
  # Get statistics for a single feature
747
+ # Note: This function doesn't need whisp_image parameter since it already accepts img_combined directly
654
748
 
655
749
 
656
750
  def get_stats_feature(feature, img_combined, unit_type="ha"):
openforis_whisp/utils.py CHANGED
@@ -4,6 +4,9 @@ import math
4
4
  import os
5
5
  import pandas as pd
6
6
 
7
+ import urllib.request
8
+ import os
9
+
7
10
  import importlib.resources as pkg_resources
8
11
 
9
12
  from dotenv import load_dotenv
@@ -152,3 +155,40 @@ class DotEnvNotFoundError(FileNotFoundError):
152
155
  "Running tests requires setting an appropriate '.env' in the root directory or in your current working "
153
156
  "directory. You may copy and edit the '.env.template' file from the root directory or from the README.",
154
157
  )
158
+
159
+
160
+ def get_example_geojson(filename="geojson_example.geojson", cache=True):
161
+ """
162
+ Download example geojson file for testing whisp functionality.
163
+
164
+ Parameters:
165
+ -----------
166
+ filename : str
167
+ Local filename to save the geojson
168
+ cache : bool
169
+ If True, cache file in user directory to avoid re-downloading
170
+
171
+ Returns:
172
+ --------
173
+ str
174
+ Path to the downloaded geojson file
175
+ """
176
+ url = "https://raw.githubusercontent.com/forestdatapartnership/whisp/main/tests/fixtures/geojson_example.geojson"
177
+
178
+ if cache:
179
+ cache_dir = os.path.join(os.path.expanduser("~"), ".whisp_cache")
180
+ os.makedirs(cache_dir, exist_ok=True)
181
+ filepath = os.path.join(cache_dir, filename)
182
+
183
+ if os.path.exists(filepath):
184
+ return filepath
185
+ else:
186
+ filepath = filename
187
+
188
+ try:
189
+ urllib.request.urlretrieve(url, filepath)
190
+ return filepath
191
+ except Exception as e:
192
+ raise RuntimeError(f"Failed to download example geojson: {e}")
193
+
194
+
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: openforis-whisp
3
- Version: 2.0.0a5
3
+ Version: 2.0.0b1
4
4
  Summary: Whisp (What is in that plot) is an open-source solution which helps to produce relevant forest monitoring information and support compliance with deforestation-related regulations.
5
5
  License: MIT
6
6
  Keywords: whisp,geospatial,data-processing
7
7
  Author: Andy Arnell
8
- Author-email: and.arnell@fao.org
8
+ Author-email: andrew.arnell@fao.org
9
9
  Requires-Python: >=3.10
10
10
  Classifier: Development Status :: 3 - Alpha
11
11
  Classifier: Intended Audience :: Developers