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/__init__.py +2 -3
- openforis_whisp/datasets.py +29 -36
- openforis_whisp/parameters/lookup_gee_datasets.csv +2 -1
- openforis_whisp/reformat.py +362 -161
- openforis_whisp/risk.py +85 -8
- openforis_whisp/stats.py +145 -51
- openforis_whisp/utils.py +40 -0
- {openforis_whisp-2.0.0a5.dist-info → openforis_whisp-2.0.0b1.dist-info}/METADATA +2 -2
- openforis_whisp-2.0.0b1.dist-info/RECORD +17 -0
- openforis_whisp-2.0.0a5.dist-info/RECORD +0 -17
- {openforis_whisp-2.0.0a5.dist-info → openforis_whisp-2.0.0b1.dist-info}/LICENSE +0 -0
- {openforis_whisp-2.0.0a5.dist-info → openforis_whisp-2.0.0b1.dist-info}/WHEEL +0 -0
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
|
|
150
|
+
data_lookup_type: DataFrame with added risk columns.
|
|
140
151
|
"""
|
|
141
|
-
# Determine the unit type
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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"] == "
|
|
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
|
|
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,
|
|
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
|
-
#
|
|
208
|
-
validated_df =
|
|
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,
|
|
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,
|
|
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=
|
|
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
|
-
|
|
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(
|
|
649
|
+
def get_stats(
|
|
650
|
+
feature_or_feature_col, national_codes=None, unit_type="ha", whisp_image=None
|
|
651
|
+
):
|
|
578
652
|
"""
|
|
579
|
-
|
|
653
|
+
Get stats for a feature or feature collection with optional pre-combined image.
|
|
580
654
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
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
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
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
|
-
|
|
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
|
-
|
|
693
|
+
print("Processing feature collection")
|
|
609
694
|
output = get_stats_fc(
|
|
610
|
-
feature_or_feature_col,
|
|
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
|
-
|
|
708
|
+
Calculate statistics for a feature collection using Whisp datasets.
|
|
621
709
|
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
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
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
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
|
-
|
|
638
|
-
|
|
639
|
-
|
|
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.
|
|
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:
|
|
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
|