openforis-whisp 3.0.0a6__py3-none-any.whl → 3.0.0a8__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
@@ -1,12 +1,14 @@
1
1
  import pandas as pd
2
2
 
3
3
  from .pd_schemas import data_lookup_type
4
+ from .logger import StdoutLogger
4
5
 
5
6
 
6
7
  from openforis_whisp.parameters.config_runtime import (
7
8
  geometry_area_column,
8
9
  DEFAULT_GEE_DATASETS_LOOKUP_TABLE_PATH,
9
- stats_unit_type_column, # Add this import
10
+ DEFAULT_CONTEXT_LOOKUP_TABLE_PATH,
11
+ stats_unit_type_column,
10
12
  )
11
13
 
12
14
  from openforis_whisp.reformat import filter_lookup_by_country_codes
@@ -16,6 +18,8 @@ lookup_gee_datasets_df: data_lookup_type = pd.read_csv(
16
18
  DEFAULT_GEE_DATASETS_LOOKUP_TABLE_PATH
17
19
  )
18
20
 
21
+ logger = StdoutLogger(__name__)
22
+
19
23
 
20
24
  # requires lookup_gee_datasets_df
21
25
 
@@ -113,9 +117,10 @@ def whisp_risk(
113
117
  explicit_unit_type: str = None,
114
118
  national_codes: list[str] = None, # List of ISO2 country codes to filter by
115
119
  custom_bands_info: dict = None, # New parameter for custom band risk info
120
+ drop_unused_columns: bool = False, # Remove columns not used in risk calculations
116
121
  ) -> data_lookup_type:
117
122
  """
118
- Adds the EUDR (European Union Deforestation Risk) column to the DataFrame based on indicator values.
123
+ Adds the risk column to the DataFrame based on indicator values.
119
124
 
120
125
  Args:
121
126
  df (DataFrame): Input DataFrame.
@@ -145,6 +150,9 @@ def whisp_risk(
145
150
  }
146
151
  }
147
152
  If None, custom bands won't be included in risk calculations.
153
+ drop_unused_columns (bool, optional): If True, removes dataset columns not used in risk calculations,
154
+ keeping only context/metadata columns, datasets used in indicators, indicator columns,
155
+ and final risk columns. Defaults to False (backward compatible).
148
156
 
149
157
  Returns:
150
158
  data_lookup_type: DataFrame with added risk columns.
@@ -278,7 +286,8 @@ def whisp_risk(
278
286
  unit_type, # Pass the unit type
279
287
  )
280
288
 
281
- df_w_indicators_and_risk_pcrop = add_eudr_risk_pcrop_col(
289
+ # these "add_" functions modify the 'df_w_indicators' dataframe in place
290
+ add_risk_pcrop_col(
282
291
  df=df_w_indicators,
283
292
  ind_1_name=ind_1_name,
284
293
  ind_2_name=ind_2_name,
@@ -286,14 +295,14 @@ def whisp_risk(
286
295
  ind_4_name=ind_4_name,
287
296
  )
288
297
 
289
- df_w_indicators_and_risk_acrop = add_eudr_risk_acrop_col(
298
+ add_risk_acrop_col(
290
299
  df=df_w_indicators,
291
300
  ind_1_name=ind_1_name,
292
301
  ind_2_name=ind_2_name,
293
302
  ind_4_name=ind_4_name,
294
303
  )
295
304
 
296
- df_w_indicators_and_risk_timber = add_eudr_risk_timber_col(
305
+ add_risk_timber_col(
297
306
  df=df_w_indicators,
298
307
  ind_2_name=ind_2_name,
299
308
  ind_5_name=ind_5_name,
@@ -305,10 +314,14 @@ def whisp_risk(
305
314
  ind_11_name=ind_11_name,
306
315
  )
307
316
 
308
- return df_w_indicators_and_risk_timber
317
+ # Filter to risk-relevant columns if requested (after all columns added)
318
+ if drop_unused_columns:
319
+ df_w_indicators = filter_to_risk_columns(df_w_indicators, input_cols, names)
320
+
321
+ return df_w_indicators
309
322
 
310
323
 
311
- def add_eudr_risk_pcrop_col(
324
+ def add_risk_pcrop_col(
312
325
  df: data_lookup_type,
313
326
  ind_1_name: str,
314
327
  ind_2_name: str,
@@ -316,7 +329,7 @@ def add_eudr_risk_pcrop_col(
316
329
  ind_4_name: str,
317
330
  ) -> data_lookup_type:
318
331
  """
319
- Adds the EUDR (European Union Deforestation Risk) column to the DataFrame based on indicator values.
332
+ Adds the risk column to the DataFrame based on indicator values.
320
333
 
321
334
  Args:
322
335
  df (DataFrame): Input DataFrame.
@@ -326,35 +339,35 @@ def add_eudr_risk_pcrop_col(
326
339
  ind_4_name (str, optional): Name of fourth indicator column. Defaults to "Ind_04_disturbance_after_2020".
327
340
 
328
341
  Returns:
329
- DataFrame: DataFrame with added 'EUDR_risk' column.
342
+ DataFrame: DataFrame with added 'risk' column.
330
343
  """
331
344
 
332
345
  for index, row in df.iterrows():
333
- # If any of the first three indicators suggest low risk, set EUDR_risk to "low"
346
+ # If any of the first three indicators suggest low risk, set risk to "low"
334
347
  if (
335
348
  row[ind_1_name] == "no"
336
349
  or row[ind_2_name] == "yes"
337
350
  or row[ind_3_name] == "yes"
338
351
  ):
339
352
  df.at[index, "risk_pcrop"] = "low"
340
- # If none of the first three indicators suggest low risk and Indicator 4 suggests no risk, set EUDR_risk to "more_info_needed"
353
+ # If none of the first three indicators suggest low risk and Indicator 4 suggests no risk, set risk to "more_info_needed"
341
354
  elif row[ind_4_name] == "no":
342
355
  df.at[index, "risk_pcrop"] = "more_info_needed"
343
- # If none of the above conditions are met, set EUDR_risk to "high"
356
+ # If none of the above conditions are met, set risk to "high"
344
357
  else:
345
358
  df.at[index, "risk_pcrop"] = "high"
346
359
 
347
360
  return df
348
361
 
349
362
 
350
- def add_eudr_risk_acrop_col(
363
+ def add_risk_acrop_col(
351
364
  df: data_lookup_type,
352
365
  ind_1_name: str,
353
366
  ind_2_name: str,
354
367
  ind_4_name: str,
355
368
  ) -> data_lookup_type:
356
369
  """
357
- Adds the EUDR (European Union Deforestation Risk) column to the DataFrame based on indicator values.
370
+ Adds the risk column to the DataFrame based on indicator values.
358
371
 
359
372
  Args:
360
373
  df (DataFrame): Input DataFrame.
@@ -363,25 +376,25 @@ def add_eudr_risk_acrop_col(
363
376
  ind_4_name (str, optional): Name of fourth indicator column. Defaults to "Ind_04_disturbance_after_2020".
364
377
 
365
378
  Returns:
366
- DataFrame: DataFrame with added 'EUDR_risk' column.
379
+ DataFrame: DataFrame with added 'risk' column.
367
380
  """
368
381
 
369
382
  # soy risk
370
383
  for index, row in df.iterrows():
371
- # If there is no tree cover in 2020, set EUDR_risk_soy to "low"
384
+ # If there is no tree cover in 2020, set risk_soy to "low"
372
385
  if row[ind_1_name] == "no" or row[ind_2_name] == "yes":
373
386
  df.at[index, "risk_acrop"] = "low"
374
- # If there is tree cover in 2020 and distrubances post 2020, set EUDR_risk_soy to "high"
387
+ # If there is tree cover in 2020 and distrubances post 2020, set risk_soy to "high"
375
388
  elif row[ind_1_name] == "yes" and row[ind_4_name] == "yes":
376
389
  df.at[index, "risk_acrop"] = "high"
377
- # If tree cover and no disturbances post 2020, set EUDR_risk to "more_info_needed"
390
+ # If tree cover and no disturbances post 2020, set risk to "more_info_needed"
378
391
  else:
379
392
  df.at[index, "risk_acrop"] = "more_info_needed"
380
393
 
381
394
  return df
382
395
 
383
396
 
384
- def add_eudr_risk_timber_col(
397
+ def add_risk_timber_col(
385
398
  df: data_lookup_type,
386
399
  ind_2_name: str,
387
400
  ind_5_name: str,
@@ -393,7 +406,7 @@ def add_eudr_risk_timber_col(
393
406
  ind_11_name: str,
394
407
  ) -> data_lookup_type:
395
408
  """
396
- Adds the EUDR (European Union Deforestation Risk) column to the DataFrame based on indicator values.
409
+ Adds the risk column to the DataFrame based on indicator values.
397
410
 
398
411
  Args:
399
412
  df (DataFrame): Input DataFrame.
@@ -407,42 +420,42 @@ def add_eudr_risk_timber_col(
407
420
  ind_11_name (str, optional): Name of eleventh indicator column. Defaults to "Ind_11_logging_concession_before_2020".
408
421
 
409
422
  Returns:
410
- DataFrame: DataFrame with added 'EUDR_risk' column.
423
+ DataFrame: DataFrame with added risk column.
411
424
  """
412
425
 
413
426
  for index, row in df.iterrows():
414
427
  # If there is a commodity in 2020 (ind_2_name)
415
- # 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"
428
+ # OR if there is planted-plantation in 2020 (ind_7_name) AND no agriculture in 2023 (ind_10_name), set risk_timber to "low"
416
429
  if row[ind_2_name] == "yes" or (
417
430
  row[ind_7_name] == "yes" and row[ind_10_name] == "no"
418
431
  ):
419
432
  df.at[index, "risk_timber"] = "low"
420
- # If there is a natural forest primary (ind_5_name) or naturally regenerating (ind_6_name) or planted forest (ind_7_name) in 2020 AND agricultural after 2020 (ind_10_name), set EUDR_timber to high
433
+ # If there is a natural forest primary (ind_5_name) or naturally regenerating (ind_6_name) or planted forest (ind_7_name) in 2020 AND agricultural after 2020 (ind_10_name), set risk_timber to high
421
434
  elif (
422
435
  row[ind_5_name] == "yes"
423
436
  or row[ind_6_name] == "yes"
424
437
  or row[ind_7_name] == "yes"
425
438
  ) and row[ind_10_name] == "yes":
426
439
  df.at[index, "risk_timber"] = "high"
427
- # If there is a natural forest primary (ind_5_name) or naturally regenerating (ind_6_name) AND planted after 2020 (ind_8_name), set EUDR_risk to "high"
440
+ # If there is a natural forest primary (ind_5_name) or naturally regenerating (ind_6_name) AND planted after 2020 (ind_8_name), set risk to "high"
428
441
  elif (row[ind_5_name] == "yes" or row[ind_6_name] == "yes") and row[
429
442
  ind_8_name
430
443
  ] == "yes":
431
444
  df.at[index, "risk_timber"] = "high"
432
445
  # No data yet on OWL conversion
433
- # If primary or naturally regenerating or planted forest in 2020 and OWL in 2023, set EUDR_risk to high
446
+ # If primary or naturally regenerating or planted forest in 2020 and OWL in 2023, set risk to high
434
447
  # elif (row[ind_5_name] == "yes" or row[ind_6_name] == "yes" or row[ind_7_name] == "yes") and row[ind_10_name] == "yes":
435
- # df.at[index, 'EUDR_risk_timber'] = "high"
448
+ # df.at[index, 'risk_timber'] = "high"
436
449
 
437
- # If there is a natural primary forest (ind_5_name) OR naturally regenerating in 2020 (ind_6_name) AND an information on management practice any time (ind_11_name) OR tree cover or regrowth post 2020 (ind_9_name), set EUDR_risk_timber to "low"
450
+ # If there is a natural primary forest (ind_5_name) OR naturally regenerating in 2020 (ind_6_name) AND an information on management practice any time (ind_11_name) OR tree cover or regrowth post 2020 (ind_9_name), set risk_timber to "low"
438
451
  elif (row[ind_5_name] == "yes" or row[ind_6_name] == "yes") and (
439
452
  row[ind_9_name] == "yes" or row[ind_11_name] == "yes"
440
453
  ):
441
454
  df.at[index, "risk_timber"] = "low"
442
- # If primary (ind_5_name) OR naturally regenerating in 2020 (ind_6_name) and no other info, set EUDR_risk to "more_info_needed"
455
+ # If primary (ind_5_name) OR naturally regenerating in 2020 (ind_6_name) and no other info, set risk to "more_info_needed"
443
456
  elif row[ind_5_name] == "yes" or row[ind_6_name] == "yes":
444
457
  df.at[index, "risk_timber"] = "more_info_needed"
445
- # If none of the above conditions are met, set EUDR_risk to "low"
458
+ # If none of the above conditions are met, set risk to "low"
446
459
  else:
447
460
  df.at[index, "risk_timber"] = "low"
448
461
 
@@ -790,6 +803,77 @@ def check_range(value: float) -> None:
790
803
  raise ValueError("Value must be between 0 and 100.")
791
804
 
792
805
 
806
+ def get_context_metadata_columns() -> list[str]:
807
+ """
808
+ Get list of context/metadata column names from lookup CSV.
809
+
810
+ Returns
811
+ -------
812
+ list[str]
813
+ List of column names marked as context_and_metadata
814
+ """
815
+ lookup_df = pd.read_csv(DEFAULT_CONTEXT_LOOKUP_TABLE_PATH)
816
+ return list(lookup_df["name"])
817
+
818
+
819
+ def filter_to_risk_columns(
820
+ df: pd.DataFrame, input_cols: list[list[str]], names: list[str]
821
+ ) -> pd.DataFrame:
822
+ """
823
+ Filter DataFrame to only columns relevant for risk calculations.
824
+
825
+ Keeps:
826
+ - Context/metadata columns (plotId, Area, Country, etc.)
827
+ - Dataset columns used in risk indicators
828
+ - Indicator columns (Ind_01_treecover, etc.)
829
+ - Risk columns (risk_pcrop, risk_acrop, risk_timber, risk_livestock)
830
+
831
+ Parameters
832
+ ----------
833
+ df : pd.DataFrame
834
+ DataFrame with all columns
835
+ input_cols : list[list[str]]
836
+ List of lists containing dataset column names used in each indicator
837
+ names : list[str]
838
+ Names of indicator columns
839
+
840
+ Returns
841
+ -------
842
+ pd.DataFrame
843
+ Filtered DataFrame with only risk-relevant columns
844
+ """
845
+ # Get context/metadata columns
846
+ context_cols = get_context_metadata_columns()
847
+
848
+ # Flatten input_cols to get dataset columns used in risk
849
+ dataset_cols = []
850
+ for col_list in input_cols:
851
+ dataset_cols.extend(col_list)
852
+
853
+ # Risk output columns (present in df if function called at end)
854
+ risk_cols = ["risk_pcrop", "risk_acrop", "risk_timber", "risk_livestock"]
855
+
856
+ # Post-processing metadata columns (added after validation, not in schema CSV)
857
+ metadata_cols = ["whisp_processing_metadata", "geo_original"]
858
+
859
+ # Build set of all columns to keep (for fast lookup)
860
+ cols_to_keep_set = set(
861
+ context_cols + dataset_cols + names + risk_cols + metadata_cols
862
+ )
863
+
864
+ # Preserve original DataFrame column order, filter to only columns we want to keep
865
+ cols_to_keep = [col for col in df.columns if col in cols_to_keep_set]
866
+
867
+ # Log dropped columns at debug level
868
+ dropped_cols = [col for col in df.columns if col not in cols_to_keep_set]
869
+ if dropped_cols:
870
+ logger.debug(
871
+ f"Dropped {len(dropped_cols)} columns: {', '.join(sorted(dropped_cols))}"
872
+ )
873
+
874
+ return df[cols_to_keep]
875
+
876
+
793
877
  def add_custom_bands_info_to_lookup(
794
878
  lookup_df: pd.DataFrame, custom_bands_info: dict, df_columns: list
795
879
  ) -> pd.DataFrame:
openforis_whisp/stats.py CHANGED
@@ -165,7 +165,6 @@ def whisp_formatted_stats_geojson_to_df(
165
165
  batch_size: int = 10,
166
166
  max_concurrent: int = 20,
167
167
  geometry_audit_trail: bool = False,
168
- status_file: str = None,
169
168
  ) -> pd.DataFrame:
170
169
  """
171
170
  Main entry point for converting GeoJSON to Whisp statistics.
@@ -219,13 +218,6 @@ def whisp_formatted_stats_geojson_to_df(
219
218
 
220
219
  Processing metadata stored in df.attrs['processing_metadata'].
221
220
  These columns enable full transparency for geometry modifications during processing.
222
- status_file : str, optional
223
- Path to JSON status file or directory for real-time progress tracking.
224
- If a directory is provided, creates 'whisp_processing_status.json' in that directory.
225
- Updates every 3 minutes and at progress milestones (5%, 10%, etc.).
226
- Format: {"status": "processing", "progress": "450/1000", "percent": 45.0,
227
- "elapsed_sec": 120, "eta_sec": 145, "updated_at": "2025-11-13T14:23:45"}
228
- Most useful for large concurrent jobs. Works in both concurrent and sequential modes.
229
221
 
230
222
  Returns
231
223
  -------
@@ -315,7 +307,6 @@ def whisp_formatted_stats_geojson_to_df(
315
307
  batch_size=batch_size,
316
308
  max_concurrent=max_concurrent,
317
309
  geometry_audit_trail=geometry_audit_trail,
318
- status_file=status_file,
319
310
  )
320
311
  else:
321
312
  raise ValueError(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: openforis-whisp
3
- Version: 3.0.0a6
3
+ Version: 3.0.0a8
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
@@ -29,6 +29,7 @@ Requires-Dist: pydantic-core (>=2.14.0,<3.0.0)
29
29
  Requires-Dist: python-dotenv (>=1.0.1,<2.0.0)
30
30
  Requires-Dist: rsa (>=4.2,<5.0.0)
31
31
  Requires-Dist: shapely (>=2.0.2,<3.0.0)
32
+ Project-URL: Changelog, https://github.com/forestdatapartnership/whisp/releases
32
33
  Project-URL: Documentation, https://github.com/forestdatapartnership/whisp#readme
33
34
  Project-URL: Development Branch, https://github.com/forestdatapartnership/whisp/tree/main
34
35
  Project-URL: Issues, https://github.com/forestdatapartnership/whisp/issues
@@ -62,6 +63,7 @@ Description-Content-Type: text/markdown
62
63
  - [Add data layers](#whisp_add_data)
63
64
  - [Contribute to the code](#whisp_contribute)
64
65
  - [Code of conduct](#whisp_conduct)
66
+ - [Feedback](#whisp_feedback)
65
67
 
66
68
  <br>
67
69
 
@@ -69,11 +71,11 @@ Description-Content-Type: text/markdown
69
71
  ***Whisp*** can currently be used directly or implemented in your own code through three different pathways:
70
72
 
71
73
 
72
- 1. The Whisp App with its simple interface can be used [right here](https://whisp.openforis.org/) or called from other software by [API](https://whisp.openforis.org/documentation/api-guide). The Whisp App currently supports the processing of up to 1000 geometries per job. The original JS & Python code behind the Whisp App and API can be found [here](https://github.com/forestdatapartnership/whisp-app).
74
+ 1. The Whisp App with its simple interface can be accessed [here](https://whisp.openforis.org/) or called from other software by [API](https://whisp.openforis.org/documentation/api-guide). The Whisp App currently supports the processing of up to 3,000 geometries per job. The original JS & Python code behind the Whisp App and API can be found [here](https://github.com/forestdatapartnership/whisp-app).
73
75
 
74
76
  2. [Whisp in Earthmap](https://whisp.earthmap.org/?aoi=WHISP&boundary=plot1&layers=%7B%22CocoaETH%22%3A%7B%22opacity%22%3A1%7D%2C%22JRCForestMask%22%3A%7B%22opacity%22%3A1%7D%2C%22planet_rgb%22%3A%7B%22opacity%22%3A1%2C%22date%22%3A%222020-12%22%7D%7D&map=%7B%22center%22%3A%7B%22lat%22%3A7%2C%22lng%22%3A4%7D%2C%22zoom%22%3A3%2C%22mapType%22%3A%22satellite%22%7D&statisticsOpen=true) supports the visualization of geometries on actual maps with the possibility to toggle different relevant map products around tree cover, commodities and deforestation. It is practical for demonstration purposes and spot checks of single geometries but not recommended for larger datasets.
75
77
 
76
- 3. Datasets of any size, especially when holding more than 1000 geometries, can be analyzed with Whisp through the [python package on pip](https://pypi.org/project/openforis-whisp/). See example [Colab Notebook](https://github.com/forestdatapartnership/whisp/blob/main/notebooks/Colab_whisp_geojson_to_csv.ipynb) for implementation with a geojson input. For the detailed procedure please go to the section [Whisp notebooks](#whisp_notebooks).
78
+ 3. Datasets of any size, especially when holding more than 3,000 geometries, can be analyzed with Whisp through the [python package on pip](https://pypi.org/project/openforis-whisp/). See example [Colab Notebook](https://github.com/forestdatapartnership/whisp/blob/main/notebooks/Colab_whisp_geojson_to_csv.ipynb) for implementation with a geojson input. For further notebooks processing options see [Whisp notebooks](#whisp_notebooks).
77
79
 
78
80
 
79
81
  ## Whisp datasets <a name="whisp_datasets"></a>
@@ -96,7 +98,7 @@ Additional categories are specific for the timber commodity, considering a harve
96
98
 
97
99
  There are multiple datasets for each category. Find the full current [list of datasets used in Whisp here](https://github.com/forestdatapartnership/whisp/blob/main/layers_description.md).
98
100
 
99
- ### Whisp risk assessment <a name="whisp_risk"></a>
101
+ ### Whisp risk assessment <a name="whisp_risk"></a>
100
102
 
101
103
  Whisp checks the plots provided by the user by running zonal statistics on them to answer the following questions:
102
104
 
@@ -153,24 +155,24 @@ The **relevant risk assessment column depends on the commodity** in question:
153
155
 
154
156
  *The Whisp algorithm for **Perennial Crops** visualized:*
155
157
  ![CoE_Graphic 5](https://github.com/user-attachments/assets/007b5f50-3939-4707-95fa-98be4d56745f)
156
-
158
+
157
159
  If no treecover dataset indicates any tree cover for a plot by the end of 2020, **Whisp will categorize the deforestation risk as low.**
158
160
 
159
161
  If one or more treecover datasets indicate tree cover on a plot by the end of 2020, but a commodity dataset indicates agricultural use by the end of 2020, **Whisp will categorize the deforestation risk as low.**
160
162
 
161
- If treecover datasets indicate tree cover on a plot by late 2020, no commodity datasets indicate agricultural use, but a disturbance dataset indicates disturbances before the end of 2020, **Whisp will categorize the deforestation risk as <u>low</u>.** Such deforestation has happened before 2020, which aligns with the cutoff date for legislation such as EUDR, and is therefore not considered high risk.
163
+ If treecover datasets indicate tree cover on a plot by late 2020, no commodity datasets indicate agricultural use, but a disturbance dataset indicates disturbances before the end of 2020, **Whisp will categorize the deforestation risk as <u>low</u>.** Such deforestation has happened before 2020, which aligns with the cutoff date for legislation, such as EUDR (European Union Deforestation Risk), and is therefore not considered high risk.
162
164
 
163
165
  Now, if the datasets under 1., 2. & 3. indicate that there was tree cover, but no agriculture and no disturbances before or by the end of 2020, the Whisp algorithm checks whether degradation or deforestation have been reported in a disturbance dataset after 2020-12-31. If they have, **Whisp will categorize the deforestation risk as <u>high</u>.** <br>
164
166
  However, under the same circumstances but with <u>no</u> disturbances reported after 2020-12-31 there is insufficient evidence and the **Whisp output will be "More info needed".** Such can be the case for, e.g., cocoa or coffee grown under the shade of treecover or agroforestry.
165
167
 
166
168
 
167
169
  ## Run Whisp python package from a notebook <a name="whisp_notebooks"></a>
168
-
170
+
169
171
  For most users we suggest using the Whisp App to process their plot data. But for some, using the python package directly will fit their workflow.
170
172
 
171
- A simple example of the package functionality can be seen in this [Colab Notebook](https://github.com/forestdatapartnership/whisp/blob/main/notebooks/Colab_whisp_geojson_to_csv.ipynb)
173
+ An example of the package functionality can be seen in this [Colab Notebook](https://github.com/forestdatapartnership/whisp/blob/main/notebooks/Colab_whisp_geojson_to_csv.ipynb)
172
174
 
173
- For an example notebook adapted for running locally (or in Sepal), see: [whisp_geojson_to_csv.ipynb](https://github.com/forestdatapartnership/whisp/blob/main/notebooks/whisp_geojson_to_csv.ipynb) or if datasets are very large, see [whisp_geojson_to_drive.ipynb](https://github.com/forestdatapartnership/whisp/blob/main/notebooks/whisp_geojson_to_drive.ipynb)
175
+ For running locally (or in Sepal), see: [whisp_geojson_to_csv.ipynb](https://github.com/forestdatapartnership/whisp/blob/main/notebooks/whisp_geojson_to_csv.ipynb) or if datasets are very large (e.g., >100,000 features), see [whisp_ee_asset_to_drive.ipynb](https://github.com/forestdatapartnership/whisp/blob/main/notebooks/whisp_ee_asset_to_drive.ipynb)
174
176
 
175
177
  ### Requirements for running the package
176
178
 
@@ -178,8 +180,6 @@ The **relevant risk assessment column depends on the commodity** in question:
178
180
  - A registered cloud GEE project.
179
181
  - Some experience in Python or a similar language.
180
182
 
181
- More info on Whisp can be found in [here](https://openknowledge.fao.org/items/e9284dc7-4b19-4f9c-b3e1-e6c142585865)
182
-
183
183
 
184
184
  ### Python package installation
185
185
 
@@ -193,7 +193,6 @@ The **relevant risk assessment column depends on the commodity** in question:
193
193
  pip install --pre openforis-whisp
194
194
  ```
195
195
 
196
- If running the package locally we recommend a [virtual environment](https://docs.python.org/3/library/venv.html) to keep your main python installation clean. For users running the package in Sepal see [here](https://docs.sepal.io/en/latest/cli/python.html#virtual-environment).
197
196
 
198
197
  The package relies upon the google earth engine api being setup correctly using a registered cloud project.
199
198
 
@@ -240,128 +239,46 @@ Before submitting a request, consider the following:
240
239
  ---
241
240
 
242
241
 
243
-
244
242
  ### Adding your own data directly
245
243
 
244
+ The python notebooks allow the user to add custom data layers. You can edit the Prepare layers section to do this in the [Colab Notebook](https://github.com/forestdatapartnership/whisp/blob/main/notebooks/Colab_whisp_geojson_to_csv.ipynb)
245
+ To add your own data directly you will need some coding experience as well as familiarity with Google Earth Engine.
246
246
 
247
- To add your own data you will need some coding experience as well as familiarity with GitHub and Google Earth Engine.
248
-
249
- This approach is for those who want to run a bespoke analysis combining their own data with those already in Whisp.
250
-
251
- Firstly follow the steps below to install the package in editable mode.
252
-
253
- As with the regular pip installation, we recommend a separate [virtual environment](https://docs.python.org/3/library/venv.html) for running in editable mode. For Sepal users see [here](https://docs.sepal.io/en/latest/cli/python.html#virtual-environment).
254
-
255
- ```bash
256
-
257
- git clone https://github.com/forestdatapartnership/whisp.git
258
-
259
- cd whisp/
260
-
261
- pip install -e .[dev]
262
-
263
- ```
264
- Once in editable mode you are running the Whisp package locally based on a cloned version of the code.
265
-
266
-
267
-
268
- There are two files to edit to add your own data:
269
-
270
- - `src/openforis_whisp/datasets.py`
271
-
272
- - `src/openforis_whisp/parameters/lookup_gee_datasets.csv`
273
-
274
-
275
-
276
- The `datasets.py` file is a Python script that defines functions which return GEE images composed of one or more bands.
277
-
278
-
279
-
280
- #### To add your own dataset:
281
-
282
- 1. Add code to `datasets.py` in the form of a function that returns a **single-band binary image** for your dataset. See notes at the top of the file and example functions for formatting.
283
-
284
- 2. Edit the `lookup_gee_datasets.csv` and add a row for your dataset.
285
-
286
-
287
-
288
- **NB:** You need to know what the dataset represents and define how it will be used in the different risk decision trees (if at all).
289
-
290
- For example, if it is a dataset for tree cover in 2000, then add `'treecover'` under the `Theme` column.
291
-
292
-
293
-
294
- #### Example function in `datasets.py`:
295
-
296
-
297
-
298
- ```python
299
-
300
- def my_custom_dataset_prep():
301
-
302
- image = ee.Image("MY/GEE/DATASET")
303
-
304
- binary = image.gt(10) # Example threshold
305
-
306
- return binary.rename("My_custom_dataset")
307
-
308
- ```
309
-
310
-
311
-
312
- ---
313
-
314
-
315
- We are working on ways to make this process smoother. However, in the meantime do contact us through the [issues page on GitHub](https://github.com/forestdatapartnership/whisp/issues), or via the Open Foris email, if this functionality is useful to you or you need help.
316
-
317
-
318
-
319
- ---
320
-
321
-
322
-
323
- ## Contributing to the Whisp code base <a name="whisp_contribute"></a>
324
-
325
- Contributions to the Whisp code in GitHub are welcome. These could be additional functionality, datasets or just cleaner code! Contributions can be made by forking the repository, making and pushing the required changes, then making a pull request to the Whisp repository. After briefly reviewing the request, we can make a branch for which to make a new pull request to. After final checks, we can then incorporate the code into the main branch. If in doubt, get in contact first or log as an issue [here](https://github.com/forestdatapartnership/whisp/issues/).
326
-
327
-
328
- Install the package in editable mode (see Adding your own data directly above):
329
-
330
- Then add additional dependencies required for testing and running pre-commit hooks:
331
-
332
-
333
- ```bash
334
247
 
335
- pre-commit install
248
+ ## Contributing <a name="whisp_contribute"></a>
336
249
 
337
- ```
250
+ Contributions are welcome!
251
+ - Fork the repo, make changes, and open a pull request.
252
+ - For adding new datasets to the codebase and for project-specific coding standards see [.github/copilot-instructions.md](.github/copilot-instructions.md)
338
253
 
254
+ ## Code of Conduct <a name="whisp_conduct"></a>
339
255
 
340
- You should be able to run the Pytest suite by simply running the `pytest` command from the repo's root folder.
256
+ **Purpose**
257
+ We are dedicated to maintaining a safe and respectful environment for all users. Harassment or abusive behavior will not be tolerated. <br>
341
258
 
259
+ **Scope**
260
+ This Code applies to all interactions on the repository and on the app.
342
261
 
343
- Please read the [contributing guidelines](contributing_guidelines.md) for good practice recommendations
262
+ **Expectations** <br>
263
+ *- Respect others:* Treat all contributors and users with courtesy and kindness. <br>
264
+ *- Constructive communication:* Engage respectfully, even in disagreements. <br>
265
+ *- Protect privacy:* Do not share personal information without consent.
344
266
 
267
+ **Prohibited Conduct** <br>
268
+ *- Harassment:* Unwanted or abusive communication, stalking, threats, or bullying.<br>
269
+ *- Discrimination:* Any form of hate speech or exclusion based on race, gender, orientation, or other identities.<br>
270
+ *- Inappropriate Content:* Posting offensive, harmful, or explicit material.
345
271
 
346
- ## Code of Conduct <a name="whisp_conduct"></a>
272
+ **Reporting** <br>
273
+ Users can report violations of this Code of Conduct confidentially by contacting the Open Foris team at
274
+ [open-foris@fao.org](mailto:open-foris@fao.org).
347
275
 
348
- **Purpose**
349
- We are dedicated to maintaining a safe and respectful environment for all users. Harassment or abusive behavior will not be tolerated. <br>
350
276
 
351
- **Scope**
352
- This Code applies to all interactions on the repository and on the app.
277
+ ## Feedback <a name="whisp_feedback"></a>
278
+ - For issues or feature requests [open a GitHub issue](https://github.com/forestdatapartnership/whisp/issues).
279
+ - For general questions, feedback or support, email [open-foris@fao.org](mailto:open-foris@fao.org).
353
280
 
354
- **Expectations** <br>
355
- *- Respect others:* Treat all contributors and users with courtesy and kindness. <br>
356
- *- Constructive communication:* Engage respectfully, even in disagreements. <br>
357
- *- Protect privacy:* Do not share personal information without consent.
281
+ We welcome all feedback and contributions!
358
282
 
359
- **Prohibited Conduct** <br>
360
- *- Harassment:* Unwanted or abusive communication, stalking, threats, or bullying.<br>
361
- *- Discrimination:* Any form of hate speech or exclusion based on race, gender, orientation, or other identities.<br>
362
- *- Inappropriate Content:* Posting offensive, harmful, or explicit material.
363
283
 
364
- **Reporting**
365
- Users can report violations directly to us by emailing the address listed in the "Contact Us" section of the website:
366
- https://openforis.org/solutions/whisp/
367
284
 
@@ -1,8 +1,8 @@
1
- openforis_whisp/__init__.py,sha256=5zJK84LYnlslxSajdCz6ZIYxRS4xgN3sGxSD6_GXEHs,3547
2
- openforis_whisp/advanced_stats.py,sha256=9YOGCkPAPKAS02kUVpJLl8Npr0yMYbFgAKakiqg9dow,105038
3
- openforis_whisp/data_checks.py,sha256=ErIKGbCa3R8eYP0sVoAl-ZUl607W1QrG0Jr2SIVgm2I,34056
1
+ openforis_whisp/__init__.py,sha256=YihdNrybfFygwcwa2Bis59V7sYpNR9aAxL-VNO4dqEI,3659
2
+ openforis_whisp/advanced_stats.py,sha256=yXwPIimbHZV3jxRL-mLMQoWZk9_UEec30I-0flNsOx8,99055
3
+ openforis_whisp/data_checks.py,sha256=jxShBiihtX0rel__Vkzu1bZfqgVQIx_l-uPP1OeCaKY,37015
4
4
  openforis_whisp/data_conversion.py,sha256=L2IsiUyQUt3aHgSYGbIhgPGwM7eyS3nLVEoNO9YqQeM,21888
5
- openforis_whisp/datasets.py,sha256=F1WxXc93mxxmN-WHa0bf-XX-FloSQyEBJKmnrQEHYn8,53855
5
+ openforis_whisp/datasets.py,sha256=fAGj1jaeoPszWm60p8N00x2qrw398-iDklX-4nkC6mI,53855
6
6
  openforis_whisp/logger.py,sha256=gFkRTwJDJKIBWcHDOK74Uln3JM7fAybURo7pQpGL790,3395
7
7
  openforis_whisp/parameters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  openforis_whisp/parameters/config_runtime.py,sha256=NOo39MAi60XCwEx5pwkS0EHKJBh0XY1q06y4j0HAABg,1421
@@ -10,11 +10,11 @@ openforis_whisp/parameters/lookup_context_and_metadata.csv,sha256=KgK0ik_Gd4t_Nq
10
10
  openforis_whisp/parameters/lookup_gaul1_admin.py,sha256=cQr5liRdXi85QieTxrz4VAkn0COvRCp82ZV0dYFWOio,474980
11
11
  openforis_whisp/parameters/lookup_gee_datasets.csv,sha256=7KdnFocEgbZO5m8JmWQchzZTurg9rJ96y17z8UyLtI0,17537
12
12
  openforis_whisp/pd_schemas.py,sha256=0z-oPmYIDUIn7mNY41W_uUpmTwjoR7e254mOCoHVsOg,2878
13
- openforis_whisp/reformat.py,sha256=gvhIa-_kTT5BSO8LuVmJ1TQcf_NwheskXboFM9e0KJY,32758
14
- openforis_whisp/risk.py,sha256=d_Di5XB8BnHdVXG56xdHTcpB4-CIF5vo2ZRMQRG7Pek,34420
15
- openforis_whisp/stats.py,sha256=pTSYs77ISRBOIglRpq4SUx3lKRkrUZOKROLRX5IP9IY,63941
13
+ openforis_whisp/reformat.py,sha256=i_ckmxuOirrfRHbeY05_5JajrJ00T5MoZ_jgzj_h0wA,32939
14
+ openforis_whisp/risk.py,sha256=tVkgVdRpdxaCBtyCjw8Z8MQt7EV9lGy34Bz8r_1Qb8Y,37135
15
+ openforis_whisp/stats.py,sha256=RJ_PJSXyvz9FnoHeQ3tqrfhhWibXjz9AlX27suSKiO4,63319
16
16
  openforis_whisp/utils.py,sha256=AISWF-MpfFdYkhd6bei4BViw2Iag20mmq61ykrF9YTk,31287
17
- openforis_whisp-3.0.0a6.dist-info/LICENSE,sha256=nqyqICO95iw_iwzP1t_IIAf7ZX3DPbL_M9WyQfh2q1k,1085
18
- openforis_whisp-3.0.0a6.dist-info/METADATA,sha256=MHbnrfjkEo-wcvu4G9k7Gqat_KSZ4UaitFuoRahT6no,16684
19
- openforis_whisp-3.0.0a6.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
20
- openforis_whisp-3.0.0a6.dist-info/RECORD,,
17
+ openforis_whisp-3.0.0a8.dist-info/LICENSE,sha256=nqyqICO95iw_iwzP1t_IIAf7ZX3DPbL_M9WyQfh2q1k,1085
18
+ openforis_whisp-3.0.0a8.dist-info/METADATA,sha256=2kDHgW5mjXMry11nvYsX7auboQMf4Mzj6BVgVa8TIsI,14173
19
+ openforis_whisp-3.0.0a8.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
20
+ openforis_whisp-3.0.0a8.dist-info/RECORD,,