openforis-whisp 3.0.0a3__py3-none-any.whl → 3.0.0a5__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.
@@ -750,23 +750,43 @@ def validate_geojson_constraints(
750
750
  return results
751
751
 
752
752
 
753
- def suggest_method(polygon_count, mean_area_ha, mean_vertices=None, verbose=True):
753
+ def suggest_processing_mode(
754
+ feature_count,
755
+ mean_area_ha=None,
756
+ mean_vertices=None,
757
+ feature_type="polygon",
758
+ verbose=True,
759
+ ):
754
760
  """
755
- Suggest processing method based on polygon characteristics.
761
+ Suggest processing mode based on feature characteristics.
762
+
763
+ Decision thresholds from comprehensive benchmark data (Nov 2025):
756
764
 
757
- Decision thresholds from benchmark data (area per polygon × polygon count):
758
- - Small polygons (10 ha): need 250+ polygons for concurrent
759
- - Medium polygons (100 ha): breakeven at ~100 polygons
760
- - Large polygons (500 ha): concurrent wins at 50+ polygons
765
+ POINTS:
766
+ - Break-even: 750-1000 features
767
+ - Sequential faster: < 750 features
768
+ - Concurrent faster: >= 750 features
769
+
770
+ POLYGONS (area-based thresholds):
771
+ - Tiny (< 1 ha): break-even ~500 features
772
+ - Small (1-5 ha, simple): break-even ~500 features
773
+ - Small (1-5 ha, complex 20-50v): break-even ~500 features
774
+ - Medium (5-20 ha): break-even ~250 features
775
+ - Large (20-100 ha): break-even ~250 features
776
+ - Very large (50-200 ha): break-even ~250 features
777
+
778
+ Vertex complexity adjustment: High vertex counts (>50) favor concurrent at lower thresholds
761
779
 
762
780
  Parameters:
763
781
  -----------
764
- polygon_count : int
765
- Number of polygons
766
- mean_area_ha : float
767
- Mean area per polygon in hectares
782
+ feature_count : int
783
+ Number of features (polygons or points)
784
+ mean_area_ha : float, optional
785
+ Mean area per polygon in hectares (required for polygons, ignored for points)
768
786
  mean_vertices : float, optional
769
- Mean number of vertices per polygon (can influence decision for complex geometries)
787
+ Mean number of vertices per polygon (influences decision for complex geometries)
788
+ feature_type : str
789
+ 'polygon', 'multipolygon', or 'point' (default: 'polygon')
770
790
  verbose : bool
771
791
  Print recommendation explanation
772
792
 
@@ -775,31 +795,63 @@ def suggest_method(polygon_count, mean_area_ha, mean_vertices=None, verbose=True
775
795
  str: 'concurrent' or 'sequential'
776
796
  """
777
797
 
778
- # Primary decision based on area
779
- if mean_area_ha >= 300: # Large polygons
780
- breakeven = 50
781
- method = "concurrent" if polygon_count >= breakeven else "sequential"
782
- elif mean_area_ha >= 50: # Medium polygons
783
- breakeven = 100
784
- method = "concurrent" if polygon_count >= breakeven else "sequential"
785
- else: # Small polygons
798
+ # Points: simple threshold-based decision
799
+ if feature_type == "point":
800
+ breakeven = 750
801
+ method = "concurrent" if feature_count >= breakeven else "sequential"
802
+
803
+ if verbose:
804
+ print(f"\nMETHOD RECOMMENDATION (Points)")
805
+ print(f" Features: {feature_count} points")
806
+ print(f" Break-even: {breakeven} features | Method: {method.upper()}")
807
+
808
+ return method
809
+
810
+ # Polygons and MultiPolygons: area and complexity-based decision
811
+ # MultiPolygons use same breakpoints as Polygons
812
+ if mean_area_ha is None:
813
+ # Default to conservative threshold if area unknown
814
+ breakeven = 500
815
+ method = "concurrent" if feature_count >= breakeven else "sequential"
816
+
817
+ if verbose:
818
+ print(f"\nMETHOD RECOMMENDATION (Polygons - area unknown)")
819
+ print(f" Features: {feature_count} polygons")
820
+ print(
821
+ f" Break-even: {breakeven} (conservative) | Method: {method.upper()}"
822
+ )
823
+
824
+ return method
825
+
826
+ # Area-based thresholds from benchmark data
827
+ if mean_area_ha >= 20: # Large to very large polygons
828
+ breakeven = 250
829
+ elif mean_area_ha >= 5: # Medium polygons
786
830
  breakeven = 250
787
- method = "concurrent" if polygon_count >= breakeven else "sequential"
831
+ elif mean_area_ha >= 1: # Small polygons
832
+ # Vertex complexity matters more for small polygons
833
+ if mean_vertices is not None and mean_vertices >= 30:
834
+ breakeven = 500 # Complex small polygons
835
+ else:
836
+ breakeven = 500 # Simple small polygons
837
+ else: # Tiny polygons (< 1 ha)
838
+ breakeven = 500
839
+
840
+ # Vertex complexity adjustment for high-complexity geometries
841
+ if mean_vertices is not None and mean_vertices >= 50:
842
+ # High complexity: reduce breakeven by 20% (concurrent beneficial sooner)
843
+ breakeven = int(breakeven * 0.8)
788
844
 
789
- # Optional adjustment based on vertex complexity (very high complexity favors concurrent)
790
- if mean_vertices is not None and mean_vertices > 500:
791
- # Reduce breakeven by 25% for very complex geometries
792
- adjusted_breakeven = int(breakeven * 0.75)
793
- method = "concurrent" if polygon_count >= adjusted_breakeven else "sequential"
845
+ method = "concurrent" if feature_count >= breakeven else "sequential"
794
846
 
795
847
  if verbose:
796
- print(f"\nMETHOD RECOMMENDATION")
848
+ print(f"\nMETHOD RECOMMENDATION (Polygons)")
797
849
  print(
798
- f" Polygons: {polygon_count} | Mean Area: {mean_area_ha:.1f} ha", end=""
850
+ f" Features: {feature_count} | Mean Area: {mean_area_ha:.1f} ha", end=""
799
851
  )
800
852
  if mean_vertices is not None:
801
853
  print(f" | Mean Vertices: {mean_vertices:.1f}", end="")
802
854
  print()
803
- print(f" Breakeven: {breakeven} polygons | Method: {method.upper()}")
855
+ print(f" Break-even: {breakeven} features | Method: {method.upper()}")
804
856
 
805
857
  return method
@@ -1160,6 +1160,20 @@ def nci_ocs2020_prep():
1160
1160
  ).selfMask() # cocoa from national land cover map for Côte d'Ivoire
1161
1161
 
1162
1162
 
1163
+ # nCM - Cameroon
1164
+ # data from Aurelie Shapiro (FAO) working directly with country experts - info on methods and accuracy assessment to follow
1165
+
1166
+
1167
+ def ncm_treecover_2020_prep():
1168
+ return (
1169
+ ee.Image("projects/ee-cocoacmr/assets/land_cover/CMR_TNTMMU_2020")
1170
+ .select("FNF_2020")
1171
+ .eq(1)
1172
+ .rename("nCM_Treecover_2020")
1173
+ .selfMask()
1174
+ )
1175
+
1176
+
1163
1177
  # ============================================================================
1164
1178
  # CONTEXT BANDS (Administrative boundaries and water mask)
1165
1179
  # ============================================================================
openforis_whisp/logger.py CHANGED
@@ -8,9 +8,21 @@ BASE_MSG_FORMAT = (
8
8
 
9
9
  class StdoutLogger:
10
10
  def __init__(self, name: str, msg_format: str = BASE_MSG_FORMAT) -> None:
11
- self.handler = logging.StreamHandler(sys.stdout)
12
- self.handler.setFormatter(logging.Formatter(msg_format))
13
- self.handler.setLevel(logging.DEBUG)
11
+ # Create handler that auto-flushes for Colab/notebook visibility
12
+ handler = logging.StreamHandler(sys.stdout)
13
+ handler.setFormatter(logging.Formatter(msg_format))
14
+ handler.setLevel(logging.DEBUG)
15
+
16
+ # Override emit to force flush after each message
17
+ original_emit = handler.emit
18
+
19
+ def emit_with_flush(record):
20
+ original_emit(record)
21
+ sys.stdout.flush()
22
+
23
+ handler.emit = emit_with_flush
24
+
25
+ self.handler = handler
14
26
  self.logger = logging.getLogger(name)
15
27
  self.logger.addHandler(self.handler)
16
28
  self.logger.propagate = False
@@ -1,5 +1,5 @@
1
1
  name,order,ISO2_code,theme,theme_timber,use_for_risk,use_for_risk_timber,exclude_from_output,col_type,is_nullable,is_required,corresponding_variable
2
- plotId,-10,,context_and_metadata,context_and_metadata,NA,NA,0,string,1,0,plot_id_column
2
+ plotId,-10,,context_and_metadata,context_and_metadata,NA,NA,0,int64,1,0,plot_id_column
3
3
  external_id,-9,,context_and_metadata,context_and_metadata,NA,NA,0,string,1,0,external_id_column
4
4
  Area,-8,,context_and_metadata,context_and_metadata,NA,NA,0,float32,1,1,geometry_area_column
5
5
  Geometry_type,-7,,context_and_metadata,context_and_metadata,NA,NA,0,string,1,1,geometry_type_column
@@ -2,9 +2,9 @@ name,order,ISO2_code,theme,theme_timber,use_for_risk,use_for_risk_timber,exclude
2
2
  EUFO_2020,10,,treecover,naturally_reg_2020,1,1,0,float32,1,0,g_jrc_gfc_2020_prep
3
3
  GLAD_Primary,20,,treecover,primary,1,1,0,float32,1,0,g_glad_pht_prep
4
4
  TMF_undist,30,,treecover,primary,1,1,0,float32,1,0,g_jrc_tmf_undisturbed_prep
5
- GFC_TC_2020,50,,treecover,naturally_reg_2020,1,1,0,float32,1,0,g_glad_gfc_10pc_prep
5
+ GFC_TC_2020,50,,treecover,naturally_reg_2020,0,0,0,float32,1,0,g_glad_gfc_10pc_prep
6
6
  Forest_FDaP,60,,treecover,naturally_reg_2020,1,1,0,float32,1,0,g_glad_gfc_10pc_prep
7
- ESA_TC_2020,70,,treecover,naturally_reg_2020,1,1,0,float32,1,0,g_esa_worldcover_trees_prep
7
+ ESA_TC_2020,70,,treecover,naturally_reg_2020,0,0,0,float32,1,0,g_esa_worldcover_trees_prep
8
8
  TMF_plant,80,,commodities,NA,1,1,0,float32,1,0,g_jrc_tmf_plantation_prep
9
9
  Oil_palm_Descals,90,,commodities,NA,1,1,0,float32,1,0,g_creaf_descals_palm_prep
10
10
  Oil_palm_FDaP,100,,commodities,NA,1,1,0,float32,1,0,g_fdap_palm_prep
@@ -197,3 +197,4 @@ nBR_INPE_TCamz_pasture_2020,2422,BR,commodities,NA,1,1,0,float32,1,0,nbr_terracl
197
197
  nBR_INPE_TCcer_pasture_2020,2423,BR,commodities,NA,1,1,0,float32,1,0,nbr_terraclass_cer20_ac_prep
198
198
  nBR_MapBiomas_col9_pasture_2020,2424,BR,commodities,NA,1,1,0,float32,1,0,nbr_mapbiomasc9_pasture_prep
199
199
  nCI_Cocoa_bnetd,3000,CI,commodities,NA,1,1,0,float32,1,0,nci_ocs2020_prep
200
+ nCM_Treecover_2020,3100,CM,treecover,NA,1,0,0,float32,1,0,ncm_treecover_2020_prep
@@ -1,5 +1,10 @@
1
- import pandera as pa
2
- from pandera.typing import DataFrame, Series
1
+ # Support both old and new pandera import paths
2
+ try:
3
+ import pandera.pandas as pa
4
+ from pandera.typing.pandas import DataFrame, Series
5
+ except (ImportError, ModuleNotFoundError):
6
+ import pandera as pa
7
+ from pandera.typing import DataFrame, Series
3
8
 
4
9
  # Define a schema for validating a DataFrame related to GEE (Google Earth Engine) datasets.
5
10
  class DataLookupSchema(pa.DataFrameModel):
@@ -1,5 +1,10 @@
1
1
  # !pip install pandera[io] # special version used
2
- import pandera as pa
2
+ # Support both old and new pandera import paths
3
+ try:
4
+ import pandera.pandas as pa
5
+ except (ImportError, ModuleNotFoundError):
6
+ import pandera as pa
7
+
3
8
  import pandas as pd
4
9
  import os
5
10
  import logging
openforis_whisp/stats.py CHANGED
@@ -88,7 +88,6 @@ def get_admin_boundaries_fc():
88
88
  def whisp_formatted_stats_geojson_to_df_legacy(
89
89
  input_geojson_filepath: Path | str,
90
90
  external_id_column=None,
91
- remove_geom=False,
92
91
  national_codes=None,
93
92
  unit_type="ha",
94
93
  whisp_image=None,
@@ -147,7 +146,6 @@ def whisp_formatted_stats_geojson_to_df_legacy(
147
146
  return whisp_formatted_stats_ee_to_df(
148
147
  feature_collection,
149
148
  external_id_column,
150
- remove_geom,
151
149
  national_codes=national_codes,
152
150
  unit_type=unit_type,
153
151
  whisp_image=whisp_image,
@@ -167,6 +165,7 @@ def whisp_formatted_stats_geojson_to_df(
167
165
  batch_size: int = 10,
168
166
  max_concurrent: int = 20,
169
167
  geometry_audit_trail: bool = False,
168
+ status_file: str = None,
170
169
  ) -> pd.DataFrame:
171
170
  """
172
171
  Main entry point for converting GeoJSON to Whisp statistics.
@@ -188,11 +187,7 @@ def whisp_formatted_stats_geojson_to_df(
188
187
  The column in the GeoJSON containing external IDs to be preserved in the output DataFrame.
189
188
  This column must exist as a property in ALL features of the GeoJSON file.
190
189
  Use debug_feature_collection_properties() to inspect available properties if you encounter errors.
191
- remove_geom : bool, default=False
192
- If True, the geometry of the GeoJSON is removed from the output DataFrame.
193
190
  national_codes : list, optional
194
- List of ISO2 country codes to include national datasets.
195
- unit_type: str, optional
196
191
  Whether to use hectares ("ha") or percentage ("percent"), by default "ha".
197
192
  whisp_image : ee.Image, optional
198
193
  Pre-combined multiband Earth Engine Image containing all Whisp datasets.
@@ -224,6 +219,13 @@ def whisp_formatted_stats_geojson_to_df(
224
219
 
225
220
  Processing metadata stored in df.attrs['processing_metadata'].
226
221
  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.
227
229
 
228
230
  Returns
229
231
  -------
@@ -283,7 +285,6 @@ def whisp_formatted_stats_geojson_to_df(
283
285
  return whisp_formatted_stats_geojson_to_df_legacy(
284
286
  input_geojson_filepath=input_geojson_filepath,
285
287
  external_id_column=external_id_column,
286
- remove_geom=remove_geom,
287
288
  national_codes=national_codes,
288
289
  unit_type=unit_type,
289
290
  whisp_image=whisp_image,
@@ -306,7 +307,6 @@ def whisp_formatted_stats_geojson_to_df(
306
307
  return whisp_formatted_stats_geojson_to_df_fast(
307
308
  input_geojson_filepath=input_geojson_filepath,
308
309
  external_id_column=external_id_column,
309
- remove_geom=remove_geom,
310
310
  national_codes=national_codes,
311
311
  unit_type=unit_type,
312
312
  whisp_image=whisp_image,
@@ -315,6 +315,7 @@ def whisp_formatted_stats_geojson_to_df(
315
315
  batch_size=batch_size,
316
316
  max_concurrent=max_concurrent,
317
317
  geometry_audit_trail=geometry_audit_trail,
318
+ status_file=status_file,
318
319
  )
319
320
  else:
320
321
  raise ValueError(
@@ -473,7 +474,6 @@ def whisp_formatted_stats_ee_to_df(
473
474
  def whisp_stats_geojson_to_df(
474
475
  input_geojson_filepath: Path | str,
475
476
  external_id_column=None,
476
- remove_geom=False,
477
477
  national_codes=None,
478
478
  unit_type="ha",
479
479
  whisp_image=None, # New parameter
@@ -506,7 +506,6 @@ def whisp_stats_geojson_to_df(
506
506
  return whisp_stats_ee_to_df(
507
507
  feature_collection,
508
508
  external_id_column,
509
- remove_geom,
510
509
  national_codes=national_codes,
511
510
  unit_type=unit_type,
512
511
  whisp_image=whisp_image, # Pass through
@@ -990,7 +989,7 @@ def whisp_stats_ee_to_drive(
990
989
  )
991
990
  task.start()
992
991
  print(
993
- "Exporting to Google Drive: 'whisp_results/whisp_output_table.csv'. To track progress: https://code.earthengine.google.com/tasks"
992
+ "Exporting to Google Drive: 'whisp_output_table.csv'. To track progress: https://code.earthengine.google.com/tasks"
994
993
  )
995
994
  except Exception as e:
996
995
  print(f"An error occurred during the export: {e}")
openforis_whisp/utils.py CHANGED
@@ -5,6 +5,8 @@ import os
5
5
  import pandas as pd
6
6
  import random
7
7
  import numpy as np
8
+ import logging
9
+ import sys
8
10
 
9
11
  import urllib.request
10
12
  import os
@@ -19,6 +21,23 @@ from shapely.validation import make_valid
19
21
 
20
22
  from .logger import StdoutLogger
21
23
 
24
+ # Configure the "whisp" logger with auto-flush handler for Colab visibility
25
+ _whisp_logger = logging.getLogger("whisp")
26
+ if not _whisp_logger.handlers:
27
+ _handler = logging.StreamHandler(sys.stdout)
28
+ _handler.setLevel(logging.DEBUG)
29
+ _handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
30
+ # Override emit to force flush after each message for Colab
31
+ _original_emit = _handler.emit
32
+
33
+ def _emit_with_flush(record):
34
+ _original_emit(record)
35
+ sys.stdout.flush()
36
+
37
+ _handler.emit = _emit_with_flush
38
+ _whisp_logger.addHandler(_handler)
39
+ _whisp_logger.setLevel(logging.INFO)
40
+ _whisp_logger.propagate = False # Don't propagate to root to avoid duplicates
22
41
 
23
42
  logger = StdoutLogger(__name__)
24
43
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: openforis-whisp
3
- Version: 3.0.0a3
3
+ Version: 3.0.0a5
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
@@ -0,0 +1,20 @@
1
+ openforis_whisp/__init__.py,sha256=5zJK84LYnlslxSajdCz6ZIYxRS4xgN3sGxSD6_GXEHs,3547
2
+ openforis_whisp/advanced_stats.py,sha256=qg5Xsx9B3rAIDOsVTeHL-viRrY2KjS5f7CRlLK9WQt8,105329
3
+ openforis_whisp/data_checks.py,sha256=ErIKGbCa3R8eYP0sVoAl-ZUl607W1QrG0Jr2SIVgm2I,34056
4
+ openforis_whisp/data_conversion.py,sha256=L2IsiUyQUt3aHgSYGbIhgPGwM7eyS3nLVEoNO9YqQeM,21888
5
+ openforis_whisp/datasets.py,sha256=F1WxXc93mxxmN-WHa0bf-XX-FloSQyEBJKmnrQEHYn8,53855
6
+ openforis_whisp/logger.py,sha256=gFkRTwJDJKIBWcHDOK74Uln3JM7fAybURo7pQpGL790,3395
7
+ openforis_whisp/parameters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ openforis_whisp/parameters/config_runtime.py,sha256=NOo39MAi60XCwEx5pwkS0EHKJBh0XY1q06y4j0HAABg,1421
9
+ openforis_whisp/parameters/lookup_context_and_metadata.csv,sha256=57Nz7t8GPMYpx81IY5RWiJGVMbIT7_0jIgZWkyih7no,1297
10
+ openforis_whisp/parameters/lookup_gaul1_admin.py,sha256=cQr5liRdXi85QieTxrz4VAkn0COvRCp82ZV0dYFWOio,474980
11
+ openforis_whisp/parameters/lookup_gee_datasets.csv,sha256=7KdnFocEgbZO5m8JmWQchzZTurg9rJ96y17z8UyLtI0,17537
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
16
+ openforis_whisp/utils.py,sha256=AISWF-MpfFdYkhd6bei4BViw2Iag20mmq61ykrF9YTk,31287
17
+ openforis_whisp-3.0.0a5.dist-info/LICENSE,sha256=nqyqICO95iw_iwzP1t_IIAf7ZX3DPbL_M9WyQfh2q1k,1085
18
+ openforis_whisp-3.0.0a5.dist-info/METADATA,sha256=mYugV2a00b1X9D88x5MF7S6CEq86FlW6EjaCY1L1piA,16684
19
+ openforis_whisp-3.0.0a5.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
20
+ openforis_whisp-3.0.0a5.dist-info/RECORD,,
@@ -1,20 +0,0 @@
1
- openforis_whisp/__init__.py,sha256=s42Q0VJdzm8mgnxfYg1hUEJPM2VLWIva2h-mdKyr444,3538
2
- openforis_whisp/advanced_stats.py,sha256=tvhgNTCGlT3aYecUPP6QCTO0FRrjk0qjs95NoVZvIt4,90935
3
- openforis_whisp/data_checks.py,sha256=KwgD72FA_n7joiJadGRpzntd2sLo0aqGNbOjRkB8iQI,32293
4
- openforis_whisp/data_conversion.py,sha256=L2IsiUyQUt3aHgSYGbIhgPGwM7eyS3nLVEoNO9YqQeM,21888
5
- openforis_whisp/datasets.py,sha256=aGJy0OYN4d0nsH3_IOYlHl-WCB7KFwZwMJ-dBi5Hc5Y,53470
6
- openforis_whisp/logger.py,sha256=9M6_3mdpoiWfC-pDwM9vKmB2l5Gul6Rb5rNTNh-_nzs,3054
7
- openforis_whisp/parameters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- openforis_whisp/parameters/config_runtime.py,sha256=NOo39MAi60XCwEx5pwkS0EHKJBh0XY1q06y4j0HAABg,1421
9
- openforis_whisp/parameters/lookup_context_and_metadata.csv,sha256=KgK0ik_Gd4t_Nq5cUkGPT4ZFZVO93HWSG82jRrOukt4,1298
10
- openforis_whisp/parameters/lookup_gaul1_admin.py,sha256=cQr5liRdXi85QieTxrz4VAkn0COvRCp82ZV0dYFWOio,474980
11
- openforis_whisp/parameters/lookup_gee_datasets.csv,sha256=UDvZrQsL5rXJn6CW6P3wofUrPLRmUFZWt6ETbXaxBMs,17454
12
- openforis_whisp/pd_schemas.py,sha256=W_ocS773LHfc05dJqvWRa-bRdX0wKFoNp0lMxgFx94Y,2681
13
- openforis_whisp/reformat.py,sha256=MPjP5lb218GTcTpd_Qvbj5ER_8EY4JjLDteQaS5OZCQ,32620
14
- openforis_whisp/risk.py,sha256=d_Di5XB8BnHdVXG56xdHTcpB4-CIF5vo2ZRMQRG7Pek,34420
15
- openforis_whisp/stats.py,sha256=nVzQpSu7BoSb2S6HheLeoK_pmguZ9Lyw0ZfbTTMVq4Q,63720
16
- openforis_whisp/utils.py,sha256=Q-EwhUaohk63WCx7Rr5VuR3X-oGtgILZDc8JsjbWhgg,30538
17
- openforis_whisp-3.0.0a3.dist-info/LICENSE,sha256=nqyqICO95iw_iwzP1t_IIAf7ZX3DPbL_M9WyQfh2q1k,1085
18
- openforis_whisp-3.0.0a3.dist-info/METADATA,sha256=6xuNhUpQWyzKU3m13FnJ7SX39jAVry1YEKNAdH0D2to,16684
19
- openforis_whisp-3.0.0a3.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
20
- openforis_whisp-3.0.0a3.dist-info/RECORD,,