edmt 1.0.6.dev1__tar.gz → 1.0.7.dev1__tar.gz
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.
- {edmt-1.0.6.dev1 → edmt-1.0.7.dev1}/PKG-INFO +42 -27
- edmt-1.0.7.dev1/README.md +70 -0
- {edmt-1.0.6.dev1 → edmt-1.0.7.dev1}/edmt/base/base.py +13 -8
- {edmt-1.0.6.dev1 → edmt-1.0.7.dev1}/edmt/contrib/utils.py +11 -6
- {edmt-1.0.6.dev1 → edmt-1.0.7.dev1}/edmt/conversion/__init__.py +7 -4
- {edmt-1.0.6.dev1 → edmt-1.0.7.dev1}/edmt/conversion/conversion.py +5 -7
- {edmt-1.0.6.dev1 → edmt-1.0.7.dev1}/edmt/models/drones.py +18 -343
- {edmt-1.0.6.dev1 → edmt-1.0.7.dev1}/edmt/workflow/__init__.py +4 -5
- edmt-1.0.7.dev1/edmt/workflow/builder.py +644 -0
- edmt-1.0.7.dev1/edmt/workflow/connector.py +611 -0
- {edmt-1.0.6.dev1 → edmt-1.0.7.dev1}/edmt/workflow/workflow.py +25 -47
- {edmt-1.0.6.dev1 → edmt-1.0.7.dev1}/edmt.egg-info/PKG-INFO +42 -27
- {edmt-1.0.6.dev1 → edmt-1.0.7.dev1}/edmt.egg-info/requires.txt +0 -1
- {edmt-1.0.6.dev1 → edmt-1.0.7.dev1}/pyproject.toml +3 -4
- edmt-1.0.7.dev1/tests/test_conversion.py +161 -0
- edmt-1.0.7.dev1/tests/test_models.py +240 -0
- edmt-1.0.6.dev1/README.md +0 -54
- edmt-1.0.6.dev1/edmt/workflow/builder.py +0 -895
- edmt-1.0.6.dev1/edmt/workflow/connector.py +0 -535
- edmt-1.0.6.dev1/tests/test_conversion.py +0 -68
- edmt-1.0.6.dev1/tests/test_models.py +0 -0
- {edmt-1.0.6.dev1 → edmt-1.0.7.dev1}/LICENSE +0 -0
- {edmt-1.0.6.dev1 → edmt-1.0.7.dev1}/edmt/__init__.py +0 -0
- {edmt-1.0.6.dev1 → edmt-1.0.7.dev1}/edmt/_edmt.py +0 -0
- {edmt-1.0.6.dev1 → edmt-1.0.7.dev1}/edmt/analysis/__init__.py +0 -0
- {edmt-1.0.6.dev1 → edmt-1.0.7.dev1}/edmt/base/__init__.py +0 -0
- {edmt-1.0.6.dev1 → edmt-1.0.7.dev1}/edmt/contrib/__init__.py +0 -0
- {edmt-1.0.6.dev1 → edmt-1.0.7.dev1}/edmt/mapping/__init__.py +0 -0
- {edmt-1.0.6.dev1 → edmt-1.0.7.dev1}/edmt/models/__init__.py +0 -0
- {edmt-1.0.6.dev1 → edmt-1.0.7.dev1}/edmt/plotting/__init__.py +0 -0
- {edmt-1.0.6.dev1 → edmt-1.0.7.dev1}/edmt.egg-info/SOURCES.txt +0 -0
- {edmt-1.0.6.dev1 → edmt-1.0.7.dev1}/edmt.egg-info/dependency_links.txt +0 -0
- {edmt-1.0.6.dev1 → edmt-1.0.7.dev1}/edmt.egg-info/entry_points.txt +0 -0
- {edmt-1.0.6.dev1 → edmt-1.0.7.dev1}/edmt.egg-info/top_level.txt +0 -0
- {edmt-1.0.6.dev1 → edmt-1.0.7.dev1}/setup.cfg +0 -0
- {edmt-1.0.6.dev1 → edmt-1.0.7.dev1}/tests/test_analysis.py +0 -0
- {edmt-1.0.6.dev1 → edmt-1.0.7.dev1}/tests/test_base.py +0 -0
- {edmt-1.0.6.dev1 → edmt-1.0.7.dev1}/tests/test_mapping.py +0 -0
- {edmt-1.0.6.dev1 → edmt-1.0.7.dev1}/tests/test_plotting.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: edmt
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.7.dev1
|
|
4
4
|
Summary: Environmental Data Management Toolbox
|
|
5
5
|
Author-email: "Odero, Kuloba & musasia" <francisodero10@gmail.com>
|
|
6
6
|
License: MIT License
|
|
@@ -26,8 +26,8 @@ License: MIT License
|
|
|
26
26
|
SOFTWARE.
|
|
27
27
|
|
|
28
28
|
Project-URL: Homepage, https://github.com/envdmt/EDMT/
|
|
29
|
+
Project-URL: Documentation, https://envdmt.github.io/EDMT/
|
|
29
30
|
Keywords: geospatial,gis,earth-engine,remote-sensing,conservation,spatial-analysis,geopandas
|
|
30
|
-
Classifier: Development Status :: 4 - Beta
|
|
31
31
|
Classifier: Intended Audience :: Developers
|
|
32
32
|
Classifier: Intended Audience :: Science/Research
|
|
33
33
|
Classifier: Intended Audience :: Education
|
|
@@ -53,7 +53,6 @@ Requires-Dist: fiona<1.10.1,>=1.9.6
|
|
|
53
53
|
Requires-Dist: tqdm>=4
|
|
54
54
|
Requires-Dist: requests<3,>=2.28
|
|
55
55
|
Requires-Dist: matplotlib>=3.9
|
|
56
|
-
Requires-Dist: mapclassify>=2.7
|
|
57
56
|
Dynamic: license-file
|
|
58
57
|
|
|
59
58
|
<h1 align="center">EDMT — Environmental Data Management Toolbox</h1>
|
|
@@ -63,18 +62,16 @@ Dynamic: license-file
|
|
|
63
62
|
<a href="https://pypi.org/project/edmt/">
|
|
64
63
|
<img src="https://img.shields.io/pypi/v/edmt.svg" alt="PyPI version" />
|
|
65
64
|
</a>
|
|
66
|
-
|
|
67
|
-
<!-- Codecov -->
|
|
68
|
-
<!-- <a href="https://codecov.io/gh/envdmt/EDMT">
|
|
69
|
-
<img src="https://codecov.io/gh/envdmt/EDMT/branch/main/graph/badge.svg" alt="codecov" />
|
|
70
|
-
</a> -->
|
|
71
|
-
|
|
72
|
-
|
|
73
65
|
<!-- Docs -->
|
|
74
66
|
<a href="https://envdmt.github.io/EDMT/">
|
|
75
67
|
<img src="https://img.shields.io/badge/docs-passing-brightgreen.svg" alt="docs" />
|
|
76
68
|
</a>
|
|
77
69
|
|
|
70
|
+
<!-- Tests -->
|
|
71
|
+
<a href="https://github.com/envdmt/EDMT/actions?query=workflow%3ATests">
|
|
72
|
+
<img src="https://github.com/envdmt/EDMT/workflows/Tests/badge.svg" alt="tests" />
|
|
73
|
+
</a>
|
|
74
|
+
|
|
78
75
|
<!-- Jupyter -->
|
|
79
76
|
<img src="https://img.shields.io/badge/Jupyter-Lab-orange.svg" alt="Jupyter Lab" />
|
|
80
77
|
|
|
@@ -83,30 +80,48 @@ Dynamic: license-file
|
|
|
83
80
|
</p>
|
|
84
81
|
|
|
85
82
|
|
|
86
|
-
|
|
83
|
+
------------------------------------------------------------------------
|
|
87
84
|
|
|
88
|
-
|
|
85
|
+
# Overview
|
|
89
86
|
|
|
90
|
-
It provides
|
|
87
|
+
EDMT (Environmental Data Management Toolbox) is a lightweight Python library for working with environmental and geospatial datasets. It provides practical utilities for data ingestion, cleaning, transformation, and exploratory analysis, helping researchers and analysts build reproducible data workflows.
|
|
91
88
|
|
|
92
|
-
|
|
93
|
-
- Cleaning & quality control
|
|
94
|
-
- Time-series handling
|
|
95
|
-
- Spatial & temporal transformations
|
|
96
|
-
- Basic analytics & summaries
|
|
97
|
-
- Reusable, reproducible workflows
|
|
89
|
+
EDMT integrates well with the Python scientific stack and is particularly useful when working with time-series environmental data, spatial datasets, and monitoring data pipelines.
|
|
98
90
|
|
|
99
|
-
|
|
91
|
+
It is designed for:
|
|
100
92
|
|
|
101
|
-
Environmental
|
|
93
|
+
- Environmental scientists
|
|
94
|
+
- Conservation and wildlife monitoring teams
|
|
95
|
+
- GIS and geospatial developers
|
|
96
|
+
- Data analysts working with environmental datasets
|
|
102
97
|
|
|
103
|
-
|
|
104
|
-
- Standardize procedures across different projects
|
|
105
|
-
- Improve reproducibility and traceability of results
|
|
98
|
+
------------------------------------------------------------------------
|
|
106
99
|
|
|
107
|
-
|
|
100
|
+
# Installation
|
|
108
101
|
|
|
109
|
-
|
|
102
|
+
Install directly from PyPI:
|
|
110
103
|
|
|
111
|
-
```bash
|
|
104
|
+
``` bash
|
|
112
105
|
pip install edmt
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
------------------------------------------------------------------------
|
|
109
|
+
|
|
110
|
+
# Typical Use Cases
|
|
111
|
+
|
|
112
|
+
EDMT can support workflows such as:
|
|
113
|
+
|
|
114
|
+
- Environmental monitoring pipelines
|
|
115
|
+
- Remote sensing preprocessing
|
|
116
|
+
- Field data quality control
|
|
117
|
+
- Environmental research and reporting
|
|
118
|
+
|
|
119
|
+
------------------------------------------------------------------------
|
|
120
|
+
|
|
121
|
+
# Documentation
|
|
122
|
+
|
|
123
|
+
Full documentation is available here:
|
|
124
|
+
|
|
125
|
+
https://envdmt.github.io/EDMT/
|
|
126
|
+
|
|
127
|
+
------------------------------------------------------------------------
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
<h1 align="center">EDMT — Environmental Data Management Toolbox</h1>
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<!-- PyPI -->
|
|
5
|
+
<a href="https://pypi.org/project/edmt/">
|
|
6
|
+
<img src="https://img.shields.io/pypi/v/edmt.svg" alt="PyPI version" />
|
|
7
|
+
</a>
|
|
8
|
+
<!-- Docs -->
|
|
9
|
+
<a href="https://envdmt.github.io/EDMT/">
|
|
10
|
+
<img src="https://img.shields.io/badge/docs-passing-brightgreen.svg" alt="docs" />
|
|
11
|
+
</a>
|
|
12
|
+
|
|
13
|
+
<!-- Tests -->
|
|
14
|
+
<a href="https://github.com/envdmt/EDMT/actions?query=workflow%3ATests">
|
|
15
|
+
<img src="https://github.com/envdmt/EDMT/workflows/Tests/badge.svg" alt="tests" />
|
|
16
|
+
</a>
|
|
17
|
+
|
|
18
|
+
<!-- Jupyter -->
|
|
19
|
+
<img src="https://img.shields.io/badge/Jupyter-Lab-orange.svg" alt="Jupyter Lab" />
|
|
20
|
+
|
|
21
|
+
<!-- License -->
|
|
22
|
+
<img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="license" />
|
|
23
|
+
</p>
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
------------------------------------------------------------------------
|
|
27
|
+
|
|
28
|
+
# Overview
|
|
29
|
+
|
|
30
|
+
EDMT (Environmental Data Management Toolbox) is a lightweight Python library for working with environmental and geospatial datasets. It provides practical utilities for data ingestion, cleaning, transformation, and exploratory analysis, helping researchers and analysts build reproducible data workflows.
|
|
31
|
+
|
|
32
|
+
EDMT integrates well with the Python scientific stack and is particularly useful when working with time-series environmental data, spatial datasets, and monitoring data pipelines.
|
|
33
|
+
|
|
34
|
+
It is designed for:
|
|
35
|
+
|
|
36
|
+
- Environmental scientists
|
|
37
|
+
- Conservation and wildlife monitoring teams
|
|
38
|
+
- GIS and geospatial developers
|
|
39
|
+
- Data analysts working with environmental datasets
|
|
40
|
+
|
|
41
|
+
------------------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
# Installation
|
|
44
|
+
|
|
45
|
+
Install directly from PyPI:
|
|
46
|
+
|
|
47
|
+
``` bash
|
|
48
|
+
pip install edmt
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
------------------------------------------------------------------------
|
|
52
|
+
|
|
53
|
+
# Typical Use Cases
|
|
54
|
+
|
|
55
|
+
EDMT can support workflows such as:
|
|
56
|
+
|
|
57
|
+
- Environmental monitoring pipelines
|
|
58
|
+
- Remote sensing preprocessing
|
|
59
|
+
- Field data quality control
|
|
60
|
+
- Environmental research and reporting
|
|
61
|
+
|
|
62
|
+
------------------------------------------------------------------------
|
|
63
|
+
|
|
64
|
+
# Documentation
|
|
65
|
+
|
|
66
|
+
Full documentation is available here:
|
|
67
|
+
|
|
68
|
+
https://envdmt.github.io/EDMT/
|
|
69
|
+
|
|
70
|
+
------------------------------------------------------------------------
|
|
@@ -1,22 +1,27 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
logger = logging.getLogger(__name__)
|
|
3
2
|
import base64
|
|
4
3
|
import http.client
|
|
4
|
+
from typing import Optional, Union
|
|
5
5
|
import requests
|
|
6
6
|
import pandas as pd
|
|
7
7
|
from io import StringIO
|
|
8
8
|
import time
|
|
9
9
|
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
10
11
|
logging.basicConfig(level=logging.WARNING)
|
|
11
12
|
|
|
12
13
|
class AirdataBaseClass:
|
|
13
|
-
def __init__(self, api_key):
|
|
14
|
+
def __init__(self, api_key: str, skip_auth: bool = False):
|
|
14
15
|
self.api_key = api_key
|
|
15
16
|
self.base_url = "api.airdata.com"
|
|
16
17
|
self.authenticated = False
|
|
17
18
|
self.auth_header = self._get_auth_header()
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
if not skip_auth:
|
|
21
|
+
self.authenticate(validate=True)
|
|
22
|
+
else:
|
|
23
|
+
self.authenticated = True
|
|
24
|
+
self.auth_header = {"Authorization": "Bearer fake_token"}
|
|
20
25
|
|
|
21
26
|
def _get_auth_header(self):
|
|
22
27
|
key_with_colon = self.api_key + ":"
|
|
@@ -62,11 +67,11 @@ class AirdataBaseClass:
|
|
|
62
67
|
|
|
63
68
|
|
|
64
69
|
def ExtractCSV(
|
|
65
|
-
row,
|
|
66
|
-
col
|
|
67
|
-
max_retries
|
|
68
|
-
timeout
|
|
69
|
-
) -> pd.DataFrame:
|
|
70
|
+
row: Union[dict, pd.Series],
|
|
71
|
+
col: str,
|
|
72
|
+
max_retries: int = 3,
|
|
73
|
+
timeout: int = 15
|
|
74
|
+
) -> Optional[pd.DataFrame]:
|
|
70
75
|
"""
|
|
71
76
|
Fetches a CSV file from a URL specified in a given column of a metadata record.
|
|
72
77
|
|
|
@@ -12,7 +12,6 @@ def clean_vars(addl_kwargs={}, **kwargs):
|
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
def normalize_column(df, col):
|
|
15
|
-
# print(col)
|
|
16
15
|
for k, v in pd.json_normalize(df.pop(col), sep="__").add_prefix(f"{col}__").items():
|
|
17
16
|
df[k] = v.values
|
|
18
17
|
|
|
@@ -30,10 +29,17 @@ def clean_time_cols(df,columns = []):
|
|
|
30
29
|
|
|
31
30
|
def format_iso_time(date_string: str) -> str:
|
|
32
31
|
try:
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
dt = pd.to_datetime(date_string)
|
|
33
|
+
if isinstance(dt, (pd.DatetimeIndex, pd.Series)):
|
|
34
|
+
if len(dt) == 0:
|
|
35
|
+
raise ValueError("Empty datetime collection")
|
|
36
|
+
dt = dt[0]
|
|
37
|
+
if pd.isna(dt):
|
|
38
|
+
raise ValueError("Invalid timestamp (NaT)")
|
|
39
|
+
return dt.isoformat()
|
|
40
|
+
except (ValueError, TypeError, AttributeError):
|
|
41
|
+
raise ValueError(f"Failed to parse timestamp '{date_string}'")
|
|
42
|
+
|
|
37
43
|
|
|
38
44
|
def norm_exp(df: pd.DataFrame, cols : Union[str, list]) -> pd.DataFrame:
|
|
39
45
|
"""
|
|
@@ -97,7 +103,6 @@ def append_cols(df: pd.DataFrame, cols: Union[str, list]):
|
|
|
97
103
|
return df[remaining_cols + cols]
|
|
98
104
|
|
|
99
105
|
|
|
100
|
-
|
|
101
106
|
def dict_expand(data,cols):
|
|
102
107
|
dfs_to_join = []
|
|
103
108
|
df_processed = data.copy()
|
|
@@ -3,19 +3,22 @@ from .conversion import (
|
|
|
3
3
|
generate_uuid,
|
|
4
4
|
generate_cmap,
|
|
5
5
|
get_utm_epsg,
|
|
6
|
-
convert_distance,
|
|
7
6
|
convert_time,
|
|
8
7
|
convert_speed,
|
|
9
|
-
|
|
8
|
+
convert_distance,
|
|
9
|
+
convert_temperature,
|
|
10
|
+
format_temperature
|
|
10
11
|
)
|
|
11
12
|
|
|
13
|
+
|
|
12
14
|
__all__ = [
|
|
13
15
|
'sdf_to_gdf',
|
|
14
16
|
'generate_uuid',
|
|
15
17
|
'generate_cmap',
|
|
16
18
|
'get_utm_epsg',
|
|
17
|
-
'convert_distance',
|
|
18
19
|
'convert_time',
|
|
19
20
|
'convert_speed',
|
|
20
|
-
'
|
|
21
|
+
'convert_distance',
|
|
22
|
+
'convert_temperature',
|
|
23
|
+
'format_temperature'
|
|
21
24
|
]
|
|
@@ -158,6 +158,7 @@ def sdf_to_gdf(sdf, crs=None):
|
|
|
158
158
|
|
|
159
159
|
return gdf
|
|
160
160
|
|
|
161
|
+
|
|
161
162
|
def _is_valid_uuid(val) -> bool:
|
|
162
163
|
if pd.isna(val):
|
|
163
164
|
return False
|
|
@@ -551,14 +552,13 @@ def convert_temperature(value: float, unit_from: str, unit_to: str) -> float:
|
|
|
551
552
|
return round(out, 3)
|
|
552
553
|
|
|
553
554
|
|
|
554
|
-
def format_temperature(value: float, unit: str,
|
|
555
|
+
def format_temperature(value: float, unit: str, symbol: bool = True) -> str:
|
|
555
556
|
"""
|
|
556
557
|
Formats a temperature value with unit, e.g. '23.5 °C' or '296.6 K'.
|
|
557
558
|
|
|
558
559
|
Args:
|
|
559
560
|
value (float): Temperature value.
|
|
560
561
|
unit (str): Unit to display (C, F, K).
|
|
561
|
-
decimals (int): Decimal places.
|
|
562
562
|
symbol (bool): If True, uses °C/°F, and K without degree symbol.
|
|
563
563
|
|
|
564
564
|
Returns:
|
|
@@ -568,14 +568,12 @@ def format_temperature(value: float, unit: str, decimals: int = 1, symbol: bool
|
|
|
568
568
|
if u not in temp_units:
|
|
569
569
|
raise ValueError(f"Unsupported temperature unit: {unit!r}. Valid: {', '.join(temp_units)}")
|
|
570
570
|
|
|
571
|
-
val_str = f"{float(value):.{int(decimals)}f}"
|
|
572
|
-
|
|
573
571
|
if not symbol:
|
|
574
|
-
return f"{
|
|
572
|
+
return f"{value} {u}"
|
|
575
573
|
|
|
576
574
|
if u in ("C", "F"):
|
|
577
|
-
return f"{
|
|
578
|
-
return f"{
|
|
575
|
+
return f"{value} °{u}"
|
|
576
|
+
return f"{value} K"
|
|
579
577
|
|
|
580
578
|
|
|
581
579
|
|