openforis-whisp 2.0.0b2__py3-none-any.whl → 3.0.0a1__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 +35 -4
- openforis_whisp/advanced_stats.py +2070 -0
- openforis_whisp/data_checks.py +642 -0
- openforis_whisp/data_conversion.py +86 -44
- openforis_whisp/datasets.py +298 -225
- openforis_whisp/logger.py +26 -0
- openforis_whisp/parameters/__init__.py +0 -0
- openforis_whisp/parameters/lookup_gaul1_admin.py +18663 -0
- openforis_whisp/reformat.py +198 -2
- openforis_whisp/stats.py +488 -68
- {openforis_whisp-2.0.0b2.dist-info → openforis_whisp-3.0.0a1.dist-info}/METADATA +1 -1
- openforis_whisp-3.0.0a1.dist-info/RECORD +20 -0
- openforis_whisp-2.0.0b2.dist-info/RECORD +0 -16
- {openforis_whisp-2.0.0b2.dist-info → openforis_whisp-3.0.0a1.dist-info}/LICENSE +0 -0
- {openforis_whisp-2.0.0b2.dist-info → openforis_whisp-3.0.0a1.dist-info}/WHEEL +0 -0
|
@@ -4,7 +4,7 @@ from shapely.geometry import shape
|
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
|
|
6
6
|
# Existing imports
|
|
7
|
-
from typing import List, Any
|
|
7
|
+
from typing import List, Any, Union
|
|
8
8
|
from geojson import Feature, FeatureCollection, Polygon, Point
|
|
9
9
|
import json
|
|
10
10
|
import os
|
|
@@ -13,32 +13,32 @@ import ee
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
def convert_geojson_to_ee(
|
|
16
|
-
geojson_filepath:
|
|
16
|
+
geojson_filepath: Union[str, Path, dict],
|
|
17
|
+
enforce_wgs84: bool = True,
|
|
18
|
+
strip_z_coords: bool = True,
|
|
17
19
|
) -> ee.FeatureCollection:
|
|
18
20
|
"""
|
|
19
|
-
|
|
21
|
+
Converts GeoJSON data to an Earth Engine FeatureCollection.
|
|
22
|
+
Accepts either a file path or a GeoJSON dictionary object.
|
|
20
23
|
Optionally checks and converts the CRS to WGS 84 (EPSG:4326) if needed.
|
|
21
24
|
Automatically handles 3D coordinates by stripping Z values when necessary.
|
|
22
25
|
|
|
23
26
|
Args:
|
|
24
|
-
geojson_filepath (
|
|
27
|
+
geojson_filepath (Union[str, Path, dict]): The filepath to the GeoJSON file (str or Path)
|
|
28
|
+
or a GeoJSON dictionary object.
|
|
25
29
|
enforce_wgs84 (bool): Whether to enforce WGS 84 projection (EPSG:4326). Defaults to True.
|
|
30
|
+
Only applies when input is a file path (dicts are assumed to be in WGS84).
|
|
26
31
|
strip_z_coords (bool): Whether to automatically strip Z coordinates from 3D geometries. Defaults to True.
|
|
27
32
|
|
|
28
33
|
Returns:
|
|
29
34
|
ee.FeatureCollection: Earth Engine FeatureCollection created from the GeoJSON.
|
|
30
35
|
"""
|
|
31
|
-
if isinstance(geojson_filepath,
|
|
36
|
+
if isinstance(geojson_filepath, dict):
|
|
37
|
+
# Input is already a GeoJSON dictionary - skip file reading
|
|
38
|
+
geojson_data = geojson_filepath
|
|
39
|
+
elif isinstance(geojson_filepath, (str, Path)):
|
|
32
40
|
file_path = os.path.abspath(geojson_filepath)
|
|
33
41
|
|
|
34
|
-
# Apply print_once deduplication for file reading message
|
|
35
|
-
if not hasattr(convert_geojson_to_ee, "_printed_file_messages"):
|
|
36
|
-
convert_geojson_to_ee._printed_file_messages = set()
|
|
37
|
-
|
|
38
|
-
if file_path not in convert_geojson_to_ee._printed_file_messages:
|
|
39
|
-
print(f"Reading GeoJSON file from: {file_path}")
|
|
40
|
-
convert_geojson_to_ee._printed_file_messages.add(file_path)
|
|
41
|
-
|
|
42
42
|
# Use GeoPandas to read the file and handle CRS
|
|
43
43
|
gdf = gpd.read_file(file_path)
|
|
44
44
|
|
|
@@ -56,15 +56,17 @@ def convert_geojson_to_ee(
|
|
|
56
56
|
# Check and convert CRS if needed
|
|
57
57
|
if enforce_wgs84:
|
|
58
58
|
if gdf.crs is None:
|
|
59
|
-
|
|
59
|
+
# Assuming WGS 84 if no CRS defined
|
|
60
|
+
pass
|
|
60
61
|
elif gdf.crs != "EPSG:4326":
|
|
61
|
-
print(f"Converting CRS from {gdf.crs} to WGS 84 (EPSG:4326)")
|
|
62
62
|
gdf = gdf.to_crs("EPSG:4326")
|
|
63
63
|
|
|
64
64
|
# Convert to GeoJSON
|
|
65
65
|
geojson_data = json.loads(gdf.to_json())
|
|
66
66
|
else:
|
|
67
|
-
raise ValueError(
|
|
67
|
+
raise ValueError(
|
|
68
|
+
"Input must be a file path (str or Path) or a GeoJSON dictionary object (dict)"
|
|
69
|
+
)
|
|
68
70
|
|
|
69
71
|
validation_errors = validate_geojson(geojson_data)
|
|
70
72
|
if validation_errors:
|
|
@@ -101,7 +103,7 @@ def convert_geojson_to_ee(
|
|
|
101
103
|
|
|
102
104
|
success_message_key = f"z_coords_success_{file_path}"
|
|
103
105
|
if success_message_key not in convert_geojson_to_ee._printed_z_messages:
|
|
104
|
-
print("
|
|
106
|
+
print("Successfully converted after stripping Z coordinates")
|
|
105
107
|
convert_geojson_to_ee._printed_z_messages.add(success_message_key)
|
|
106
108
|
|
|
107
109
|
return feature_collection
|
|
@@ -250,6 +252,58 @@ def convert_shapefile_to_ee(shapefile_path):
|
|
|
250
252
|
return roi
|
|
251
253
|
|
|
252
254
|
|
|
255
|
+
# def convert_ee_to_df(
|
|
256
|
+
# ee_object,
|
|
257
|
+
# columns=None,
|
|
258
|
+
# remove_geom=False,
|
|
259
|
+
# **kwargs,
|
|
260
|
+
# ):
|
|
261
|
+
# """Converts an ee.FeatureCollection to pandas dataframe.
|
|
262
|
+
|
|
263
|
+
# Args:
|
|
264
|
+
# ee_object (ee.FeatureCollection): ee.FeatureCollection.
|
|
265
|
+
# columns (list): List of column names. Defaults to None.
|
|
266
|
+
# remove_geom (bool): Whether to remove the geometry column. Defaults to True.
|
|
267
|
+
# kwargs: Additional arguments passed to ee.data.computeFeature.
|
|
268
|
+
|
|
269
|
+
# Raises:
|
|
270
|
+
# TypeError: ee_object must be an ee.FeatureCollection
|
|
271
|
+
|
|
272
|
+
# Returns:
|
|
273
|
+
# pd.DataFrame: pandas DataFrame
|
|
274
|
+
# """
|
|
275
|
+
# if isinstance(ee_object, ee.Feature):
|
|
276
|
+
# ee_object = ee.FeatureCollection([ee_object])
|
|
277
|
+
|
|
278
|
+
# if not isinstance(ee_object, ee.FeatureCollection):
|
|
279
|
+
# raise TypeError("ee_object must be an ee.FeatureCollection")
|
|
280
|
+
|
|
281
|
+
# try:
|
|
282
|
+
# if remove_geom:
|
|
283
|
+
# data = ee_object.map(
|
|
284
|
+
# lambda f: ee.Feature(None, f.toDictionary(f.propertyNames().sort()))
|
|
285
|
+
# )
|
|
286
|
+
# else:
|
|
287
|
+
# data = ee_object
|
|
288
|
+
|
|
289
|
+
# kwargs["expression"] = data
|
|
290
|
+
# kwargs["fileFormat"] = "PANDAS_DATAFRAME"
|
|
291
|
+
|
|
292
|
+
# df = ee.data.computeFeatures(kwargs)
|
|
293
|
+
|
|
294
|
+
# if isinstance(columns, list):
|
|
295
|
+
# df = df[columns]
|
|
296
|
+
|
|
297
|
+
# if remove_geom and ("geometry" in df.columns):
|
|
298
|
+
# df = df.drop(columns=["geometry"], axis=1)
|
|
299
|
+
|
|
300
|
+
# # Sorting columns is not supported server-side and is removed from this function.
|
|
301
|
+
|
|
302
|
+
# return df
|
|
303
|
+
# except Exception as e:
|
|
304
|
+
# raise Exception(e)
|
|
305
|
+
|
|
306
|
+
|
|
253
307
|
def convert_ee_to_df(
|
|
254
308
|
ee_object,
|
|
255
309
|
columns=None,
|
|
@@ -257,49 +311,37 @@ def convert_ee_to_df(
|
|
|
257
311
|
sort_columns=False,
|
|
258
312
|
**kwargs,
|
|
259
313
|
):
|
|
260
|
-
"""
|
|
314
|
+
"""
|
|
315
|
+
Converts an ee.FeatureCollection to pandas DataFrame, maximizing server-side operations.
|
|
261
316
|
|
|
262
317
|
Args:
|
|
263
318
|
ee_object (ee.FeatureCollection): ee.FeatureCollection.
|
|
264
|
-
columns (list): List of column names
|
|
265
|
-
remove_geom (bool):
|
|
266
|
-
|
|
267
|
-
kwargs: Additional arguments passed to ee.data.computeFeature.
|
|
268
|
-
|
|
269
|
-
Raises:
|
|
270
|
-
TypeError: ee_object must be an ee.FeatureCollection
|
|
319
|
+
columns (list): List of column names to select (server-side if possible).
|
|
320
|
+
remove_geom (bool): Remove geometry column server-side.
|
|
321
|
+
kwargs: Additional arguments for ee.data.computeFeatures.
|
|
271
322
|
|
|
272
323
|
Returns:
|
|
273
324
|
pd.DataFrame: pandas DataFrame
|
|
274
325
|
"""
|
|
326
|
+
import ee
|
|
327
|
+
|
|
275
328
|
if isinstance(ee_object, ee.Feature):
|
|
276
329
|
ee_object = ee.FeatureCollection([ee_object])
|
|
277
330
|
|
|
278
331
|
if not isinstance(ee_object, ee.FeatureCollection):
|
|
279
332
|
raise TypeError("ee_object must be an ee.FeatureCollection")
|
|
280
333
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
else:
|
|
287
|
-
data = ee_object
|
|
334
|
+
# Server-side: select columns and remove geometry
|
|
335
|
+
if columns is not None:
|
|
336
|
+
ee_object = ee_object.select(columns)
|
|
337
|
+
if remove_geom:
|
|
338
|
+
ee_object = ee_object.map(lambda f: ee.Feature(None, f.toDictionary()))
|
|
288
339
|
|
|
289
|
-
|
|
340
|
+
try:
|
|
341
|
+
kwargs["expression"] = ee_object
|
|
290
342
|
kwargs["fileFormat"] = "PANDAS_DATAFRAME"
|
|
291
|
-
|
|
292
343
|
df = ee.data.computeFeatures(kwargs)
|
|
293
344
|
|
|
294
|
-
if isinstance(columns, list):
|
|
295
|
-
df = df[columns]
|
|
296
|
-
|
|
297
|
-
if remove_geom and ("geometry" in df.columns):
|
|
298
|
-
df = df.drop(columns=["geometry"], axis=1)
|
|
299
|
-
|
|
300
|
-
if sort_columns:
|
|
301
|
-
df = df.reindex(sorted(df.columns), axis=1)
|
|
302
|
-
|
|
303
345
|
return df
|
|
304
346
|
except Exception as e:
|
|
305
347
|
raise Exception(e)
|
|
@@ -443,7 +485,7 @@ def convert_csv_to_geojson(
|
|
|
443
485
|
try:
|
|
444
486
|
df = pd.read_csv(csv_filepath)
|
|
445
487
|
|
|
446
|
-
|
|
488
|
+
convert_df_to_geojson(df, geojson_filepath, geo_column)
|
|
447
489
|
|
|
448
490
|
except Exception as e:
|
|
449
491
|
print(f"An error occurred while converting CSV to GeoJSON: {e}")
|