core-lens 0.1.dev113__tar.gz → 0.1.dev117__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.
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/PKG-INFO +1 -1
- core_lens-0.1.dev117/docs/source/export.md +47 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/docs/source/index.rst +1 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/docs/source/intro.md +2 -1
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/docs/source/plots.md +1 -1
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/src/core_lens/_version.py +2 -2
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/src/core_lens/aoi.py +16 -16
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/src/core_lens/base/entity.py +18 -18
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/src/core_lens/base/namespaces/plot.py +25 -25
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/src/core_lens/base/namespaces/stats.py +25 -25
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/src/core_lens/base/result.py +16 -10
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/src/core_lens/base/view.py +39 -19
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/src/core_lens/entities/mws.py +15 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/src/core_lens/entities/tehsil.py +12 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/src/core_lens/entities/waterbody.py +12 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/src/core_lens/export/formats.py +15 -15
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/src/core_lens/schema/detection.py +6 -6
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/src/core_lens/schema/profile.py +2 -2
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/src/core_lens/utils/polars_utils.py +10 -7
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/src/core_lens/utils/season.py +117 -47
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/src/core_lens/utils/spatial.py +28 -28
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/tests/unit/test_entity.py +65 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/tests/unit/test_plot.py +35 -0
- core_lens-0.1.dev117/tests/unit/test_polars_utils.py +87 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/tests/unit/test_spatial.py +104 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/tests/unit/test_stats.py +219 -11
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/tests/unit/test_view.py +76 -0
- core_lens-0.1.dev113/tests/unit/test_polars_utils.py +0 -14
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/.github/pull_request_template.md +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/.github/workflows/ci.yml +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/.github/workflows/gh-pages.yml +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/.github/workflows/pre-release.yml +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/.github/workflows/release.yml +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/.gitignore +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/.gitmessage +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/.pre-commit-config.yaml +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/.python-version +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/CONTRIBUTING.md +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/LICENSE +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/README.md +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/SKILLS.md +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/docs/Makefile +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/docs/make.bat +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/docs/source/concepts.md +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/docs/source/conf.py +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/docs/source/plugins.md +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/docs/source/queries.md +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/docs/source/quickstart.md +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/docs/source/stats.md +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/examples/demo_mws.py +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/examples/demo_tehsil.py +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/hooks/mypy.sh +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/hooks/no-parquet-outside-fixtures.sh +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/hooks/pytest.sh +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/pyproject.toml +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/src/core_lens/__init__.py +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/src/core_lens/__main__.py +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/src/core_lens/base/__init__.py +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/src/core_lens/base/namespaces/__init__.py +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/src/core_lens/entities/__init__.py +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/src/core_lens/export/__init__.py +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/src/core_lens/py.typed +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/src/core_lens/schema/__init__.py +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/src/core_lens/utils/__init__.py +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/tests/fixtures/generate_fixtures.py +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/tests/unit/conftest.py +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/tests/unit/test_aoi.py +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/tests/unit/test_entities.py +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/tests/unit/test_export.py +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/tests/unit/test_main.py +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/tests/unit/test_profile.py +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/tests/unit/test_result.py +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/tests/unit/test_schema_detection.py +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/tests/unit/test_schema_profile.py +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/tests/unit/test_season.py +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/tests/unit/test_season_config.py +0 -0
- {core_lens-0.1.dev113 → core_lens-0.1.dev117}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: core-lens
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.dev117
|
|
4
4
|
Summary: Query, analyse, and visualise CoreStack's microwatershed and Earth science data through a clean, composable Python API.
|
|
5
5
|
Project-URL: Homepage, https://github.com/ApoorvaKashyap/core-lens
|
|
6
6
|
Project-URL: Issues, https://github.com/ApoorvaKashyap/core-lens/issues
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Data Export
|
|
2
|
+
|
|
3
|
+
CoreLens provides a unified `core_lens.export` module for saving `Result` objects to various file formats. Standard tabular formats use Polars for high-speed writes, while geospatial formats leverage DuckDB's spatial extensions for robust geometry encoding.
|
|
4
|
+
|
|
5
|
+
## Standard Formats
|
|
6
|
+
|
|
7
|
+
Export non-spatial results to standard formats. Note that these formats cannot encode geometry columns; if your `Result` has geometry, these functions will raise a `TypeError`.
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
from core_lens.export import parquet, csv, json
|
|
11
|
+
|
|
12
|
+
res = aoi.mws.annual
|
|
13
|
+
|
|
14
|
+
# Export to Parquet with ZSTD compression
|
|
15
|
+
parquet(res, "output.parquet", compression="zstd")
|
|
16
|
+
|
|
17
|
+
# Export to CSV
|
|
18
|
+
csv(res, "output.csv", separator=",")
|
|
19
|
+
|
|
20
|
+
# Export to JSON
|
|
21
|
+
json(res, "output.json", pretty=True)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Geospatial Formats
|
|
25
|
+
|
|
26
|
+
Export spatial data to GeoParquet and GeoJSON. The result must have geometry attached (e.g., by calling `.with_geometry()`).
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from core_lens.export import geoparquet, geojson
|
|
30
|
+
|
|
31
|
+
# Make sure geometry is attached!
|
|
32
|
+
spatial_res = aoi.mws.annual.with_geometry()
|
|
33
|
+
|
|
34
|
+
# Export to GeoParquet with DuckDB COPY options (e.g., partitioning)
|
|
35
|
+
geoparquet(
|
|
36
|
+
spatial_res,
|
|
37
|
+
"output.geoparquet",
|
|
38
|
+
compression="ZSTD",
|
|
39
|
+
partition_by="year"
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
# Export to GeoJSON
|
|
43
|
+
geojson(spatial_res, "output.json")
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
> [!NOTE]
|
|
47
|
+
> Exporting to geospatial formats automatically uses DuckDB to cast WKB geometries to proper spatial types via the `spatial` extension. CoreLens handles the installation and loading of the extension seamlessly under the hood.
|
|
@@ -12,4 +12,5 @@ CoreLens provides a unified interface over microwatersheds, administrative bound
|
|
|
12
12
|
- **Pluggable Entities**: Built-in support for standard units (MWS, Tehsil) with a simple plugin architecture for adding new domain entities.
|
|
13
13
|
- **Temporal & Seasonal Awareness**: Native support for agronomic seasons (Kharif, Rabi, Zaid) and time-range filtering.
|
|
14
14
|
- **Spatial Statistics & Analysis**: Built-in methods for anomaly detection, spatial similarity, temporal correlation, and hypothesis testing.
|
|
15
|
-
- **Interactive Visualisation**: Generate interactive maps using Lonboard and timeseries/scatter plots using Bokeh
|
|
15
|
+
- **Interactive Visualisation**: Generate interactive maps using Lonboard with zero-copy GeoArrow rendering directly from Polars, and timeseries/scatter plots using Bokeh.
|
|
16
|
+
- **High-Performance Exports**: Export results directly to Parquet, JSON, CSV, or spatially-enabled GeoParquet and GeoJSON using integrated DuckDB spatial extensions.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Visualisation and Plots
|
|
2
2
|
|
|
3
|
-
The `result.plot` namespace provides integrated plotting capabilities. Spatial plots use **Lonboard** for high-performance interactive maps, while charts and timeseries use **Bokeh**.
|
|
3
|
+
The `result.plot` namespace provides integrated plotting capabilities. Spatial plots use **Lonboard** for high-performance interactive maps (achieved via zero-copy GeoArrow memory mapping directly from Polars, bypassing GeoPandas), while charts and timeseries use **Bokeh**.
|
|
4
4
|
|
|
5
5
|
Plot methods return plot objects (like a Bokeh Figure or Lonboard Map) which can be displayed using `bokeh.io.show` or exported via `bokeh.io.save`.
|
|
6
6
|
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.1.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 1, '
|
|
21
|
+
__version__ = version = '0.1.dev117'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 1, 'dev117')
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -67,10 +67,10 @@ class SeasonConfig:
|
|
|
67
67
|
"""Return the season name for a given date.
|
|
68
68
|
|
|
69
69
|
Args:
|
|
70
|
-
d: The date to classify.
|
|
70
|
+
d (date): The date to classify.
|
|
71
71
|
|
|
72
72
|
Returns:
|
|
73
|
-
``"kharif"``, ``"rabi"``, or ``"zaid"``.
|
|
73
|
+
str: ``"kharif"``, ``"rabi"``, or ``"zaid"``.
|
|
74
74
|
"""
|
|
75
75
|
md = f"{d.month:02d}-{d.day:02d}"
|
|
76
76
|
for name in ("kharif", "rabi", "zaid"):
|
|
@@ -155,16 +155,16 @@ class AoI:
|
|
|
155
155
|
"""Resolve the AoI boundary and scope all registered entities.
|
|
156
156
|
|
|
157
157
|
Args:
|
|
158
|
-
data_root: Path to the root data directory. Prepended to every
|
|
158
|
+
data_root (str): Path to the root data directory. Prepended to every
|
|
159
159
|
relative entity path that does not start with ``/`` or a URI
|
|
160
160
|
scheme.
|
|
161
|
-
bbox: Bounding box as ``(minx, miny, maxx, maxy)`` in WGS-84.
|
|
161
|
+
bbox (tuple[float, float, float, float] | None, optional): Bounding box as ``(minx, miny, maxx, maxy)`` in WGS-84.
|
|
162
162
|
Mutually exclusive with ``geometry`` and ``entity_kwargs``.
|
|
163
|
-
geometry: Arbitrary Shapely geometry. Used as-is. Mutually
|
|
163
|
+
geometry (shapely.Geometry | None, optional): Arbitrary Shapely geometry. Used as-is. Mutually
|
|
164
164
|
exclusive with ``bbox`` and ``entity_kwargs``.
|
|
165
|
-
seasons: :class:`SeasonConfig` override. Defaults to the library
|
|
165
|
+
seasons (SeasonConfig | None, optional): :class:`SeasonConfig` override. Defaults to the library
|
|
166
166
|
agronomic defaults.
|
|
167
|
-
**entity_kwargs: Named filter pairs that identify the boundary,
|
|
167
|
+
**entity_kwargs (str | list[str]): Named filter pairs that identify the boundary,
|
|
168
168
|
e.g. ``tehsil="Pangi"``, ``district="Chamba"``,
|
|
169
169
|
``state="Himachal Pradesh"``, ``mws_id="13_551"``.
|
|
170
170
|
Mutually exclusive with ``bbox`` and ``geometry``.
|
|
@@ -219,7 +219,7 @@ class AoI:
|
|
|
219
219
|
"""The season name for today's date under the AoI's SeasonConfig.
|
|
220
220
|
|
|
221
221
|
Returns:
|
|
222
|
-
``"kharif"``, ``"rabi"``, or ``"zaid"``.
|
|
222
|
+
str: ``"kharif"``, ``"rabi"``, or ``"zaid"``.
|
|
223
223
|
"""
|
|
224
224
|
return self.seasons.season_for(date.today())
|
|
225
225
|
|
|
@@ -228,7 +228,7 @@ class AoI:
|
|
|
228
228
|
"""The current calendar year.
|
|
229
229
|
|
|
230
230
|
Returns:
|
|
231
|
-
Current year as an integer.
|
|
231
|
+
int: Current year as an integer.
|
|
232
232
|
"""
|
|
233
233
|
return date.today().year
|
|
234
234
|
|
|
@@ -236,11 +236,11 @@ class AoI:
|
|
|
236
236
|
"""Render an interactive Lonboard map of the AoI and its entity layers.
|
|
237
237
|
|
|
238
238
|
Args:
|
|
239
|
-
overlay: An optional :class:`~core_lens.base.result.Result` to
|
|
239
|
+
overlay (Result | None, optional): An optional :class:`~core_lens.base.result.Result` to
|
|
240
240
|
overlay on the map.
|
|
241
241
|
|
|
242
242
|
Returns:
|
|
243
|
-
A Lonboard Map object.
|
|
243
|
+
Any: A Lonboard Map object.
|
|
244
244
|
"""
|
|
245
245
|
import lonboard
|
|
246
246
|
import geopandas as gpd
|
|
@@ -309,10 +309,10 @@ class AoI:
|
|
|
309
309
|
the unique matching row).
|
|
310
310
|
|
|
311
311
|
Args:
|
|
312
|
-
entity_kwargs: Column–value pairs used to identify the boundary.
|
|
312
|
+
entity_kwargs (dict[str, str | list[str]]): Column–value pairs used to identify the boundary.
|
|
313
313
|
|
|
314
314
|
Returns:
|
|
315
|
-
The union of all matching entity geometries as a Shapely object.
|
|
315
|
+
shapely.Geometry: The union of all matching entity geometries as a Shapely object.
|
|
316
316
|
|
|
317
317
|
Raises:
|
|
318
318
|
:class:`~core_lens.base.EntityValidationError`: If no registered entity can satisfy the filters.
|
|
@@ -391,7 +391,7 @@ class AoI:
|
|
|
391
391
|
:class:`AoI` is instantiated (when ``data_root`` is known).
|
|
392
392
|
|
|
393
393
|
Args:
|
|
394
|
-
entity_cls: A concrete subclass of
|
|
394
|
+
entity_cls (type[BaseEntity]): A concrete subclass of
|
|
395
395
|
:class:`~core_lens.base.entity.BaseEntity`.
|
|
396
396
|
|
|
397
397
|
Raises:
|
|
@@ -417,7 +417,7 @@ class AoI:
|
|
|
417
417
|
Primarily useful in tests where a clean registry is needed between runs.
|
|
418
418
|
|
|
419
419
|
Args:
|
|
420
|
-
entity_cls: The entity class to remove.
|
|
420
|
+
entity_cls (type[BaseEntity]): The entity class to remove.
|
|
421
421
|
"""
|
|
422
422
|
name = _entity_name(entity_cls)
|
|
423
423
|
_REGISTRY.pop(name, None)
|
|
@@ -427,7 +427,7 @@ class AoI:
|
|
|
427
427
|
"""Return the names of all currently registered entities.
|
|
428
428
|
|
|
429
429
|
Returns:
|
|
430
|
-
A sorted list of entity name strings.
|
|
430
|
+
list[str]: A sorted list of entity name strings.
|
|
431
431
|
"""
|
|
432
432
|
return sorted(_REGISTRY)
|
|
433
433
|
|
|
@@ -84,7 +84,7 @@ class BaseEntity(ABC):
|
|
|
84
84
|
"""Initialise the entity with an optional data root directory.
|
|
85
85
|
|
|
86
86
|
Args:
|
|
87
|
-
data_root: Absolute path to the root data directory. When
|
|
87
|
+
data_root (pathlib.Path | None, optional): Absolute path to the root data directory. When
|
|
88
88
|
supplied, relative :attr:`static_path`, :attr:`annual_path`,
|
|
89
89
|
and :attr:`fortnightly_path` values are resolved against this
|
|
90
90
|
directory. Defaults to ``None``, in which case relative paths
|
|
@@ -100,10 +100,10 @@ class BaseEntity(ABC):
|
|
|
100
100
|
otherwise against the current working directory.
|
|
101
101
|
|
|
102
102
|
Args:
|
|
103
|
-
path: A filesystem path, absolute or relative.
|
|
103
|
+
path (str): A filesystem path, absolute or relative.
|
|
104
104
|
|
|
105
105
|
Returns:
|
|
106
|
-
An absolute path string.
|
|
106
|
+
str: An absolute path string.
|
|
107
107
|
|
|
108
108
|
Raises:
|
|
109
109
|
FileNotFoundError: If the resolved path does not exist.
|
|
@@ -131,7 +131,7 @@ class BaseEntity(ABC):
|
|
|
131
131
|
``[\"mws_id\"]``), but the contract allows composite keys for plugins.
|
|
132
132
|
|
|
133
133
|
Returns:
|
|
134
|
-
A list of column name strings present in the static file.
|
|
134
|
+
list[str]: A list of column name strings present in the static file.
|
|
135
135
|
"""
|
|
136
136
|
|
|
137
137
|
@property
|
|
@@ -143,7 +143,7 @@ class BaseEntity(ABC):
|
|
|
143
143
|
(WKB bytes, WKT string, or a native geometry column).
|
|
144
144
|
|
|
145
145
|
Returns:
|
|
146
|
-
The column name as a string.
|
|
146
|
+
str: The column name as a string.
|
|
147
147
|
"""
|
|
148
148
|
|
|
149
149
|
@property
|
|
@@ -156,7 +156,7 @@ class BaseEntity(ABC):
|
|
|
156
156
|
``FileNotFoundError`` is raised if the file does not exist.
|
|
157
157
|
|
|
158
158
|
Returns:
|
|
159
|
-
A path string.
|
|
159
|
+
str: A path string.
|
|
160
160
|
"""
|
|
161
161
|
|
|
162
162
|
@property
|
|
@@ -168,7 +168,7 @@ class BaseEntity(ABC):
|
|
|
168
168
|
:class:`EntityValidationError` is raised.
|
|
169
169
|
|
|
170
170
|
Returns:
|
|
171
|
-
A path string, or ``None`` if the entity has no annual data.
|
|
171
|
+
str | None: A path string, or ``None`` if the entity has no annual data.
|
|
172
172
|
"""
|
|
173
173
|
return None
|
|
174
174
|
|
|
@@ -181,7 +181,7 @@ class BaseEntity(ABC):
|
|
|
181
181
|
:class:`EntityValidationError` is raised.
|
|
182
182
|
|
|
183
183
|
Returns:
|
|
184
|
-
A path string, or ``None`` if the entity has no fortnightly data.
|
|
184
|
+
str | None: A path string, or ``None`` if the entity has no fortnightly data.
|
|
185
185
|
"""
|
|
186
186
|
return None
|
|
187
187
|
|
|
@@ -194,7 +194,7 @@ class BaseEntity(ABC):
|
|
|
194
194
|
instead of relying on detection.
|
|
195
195
|
|
|
196
196
|
Returns:
|
|
197
|
-
A fully-validated :class:`~core_lens.schema.profile.SchemaProfile`.
|
|
197
|
+
SchemaProfile: A fully-validated :class:`~core_lens.schema.profile.SchemaProfile`.
|
|
198
198
|
"""
|
|
199
199
|
if not hasattr(self, "_schema_profile"):
|
|
200
200
|
from core_lens.schema.detection import detect
|
|
@@ -247,7 +247,7 @@ class BaseEntity(ABC):
|
|
|
247
247
|
are resolved as entity-name lookups.
|
|
248
248
|
|
|
249
249
|
Returns:
|
|
250
|
-
A lazy :class:`~core_lens.base.view.View` with resolved key pairs.
|
|
250
|
+
View: A lazy :class:`~core_lens.base.view.View` with resolved key pairs.
|
|
251
251
|
|
|
252
252
|
Raises:
|
|
253
253
|
ValueError: If a kwarg cannot be resolved as either an attribute
|
|
@@ -354,21 +354,21 @@ class BaseEntity(ABC):
|
|
|
354
354
|
refines with a Shapely STRtree exact-relationship check.
|
|
355
355
|
|
|
356
356
|
Args:
|
|
357
|
-
geometry: A Shapely geometry representing the spatial extent.
|
|
358
|
-
bbox: Bounding box as ``(minx, miny, maxx, maxy)`` in WGS-84.
|
|
357
|
+
geometry (shapely.Geometry | None, optional): A Shapely geometry representing the spatial extent.
|
|
358
|
+
bbox (tuple[float, float, float, float] | None, optional): Bounding box as ``(minx, miny, maxx, maxy)`` in WGS-84.
|
|
359
359
|
Converted to a ``shapely.geometry.box`` internally.
|
|
360
|
-
relationship: Spatial relationship mode.
|
|
360
|
+
relationship (str, optional): Spatial relationship mode.
|
|
361
361
|
|
|
362
362
|
* ``"centroid"`` (default) — entity centroid must lie within
|
|
363
363
|
the geometry.
|
|
364
364
|
* ``"area"`` — intersection area / entity area must exceed
|
|
365
365
|
``threshold``.
|
|
366
366
|
|
|
367
|
-
threshold: Area coverage threshold for ``"area"`` mode (0–1).
|
|
367
|
+
threshold (float, optional): Area coverage threshold for ``"area"`` mode (0–1).
|
|
368
368
|
Default 0.5.
|
|
369
369
|
|
|
370
370
|
Returns:
|
|
371
|
-
A lazy :class:`~core_lens.base.view.View` scoped to the given
|
|
371
|
+
View: A lazy :class:`~core_lens.base.view.View` scoped to the given
|
|
372
372
|
spatial extent.
|
|
373
373
|
|
|
374
374
|
Raises:
|
|
@@ -411,15 +411,15 @@ class BaseEntity(ABC):
|
|
|
411
411
|
Joined columns are namespaced as ``{entity_name}_{column_name}``.
|
|
412
412
|
|
|
413
413
|
Args:
|
|
414
|
-
other: The secondary :class:`BaseEntity` whose columns will be
|
|
414
|
+
other (BaseEntity): The secondary :class:`BaseEntity` whose columns will be
|
|
415
415
|
joined and aggregated onto ``self``.
|
|
416
|
-
agg: Mapping of ``{column: aggregation}`` specifying which columns
|
|
416
|
+
agg (dict[str, str]): Mapping of ``{column: aggregation}`` specifying which columns
|
|
417
417
|
from ``other`` to bring in and how to aggregate them. Valid
|
|
418
418
|
aggregation strings are ``\"area\"``, ``\"count\"``, ``\"mean\"``,
|
|
419
419
|
``\"sum\"``, ``\"min\"``, and ``\"max\"``.
|
|
420
420
|
|
|
421
421
|
Returns:
|
|
422
|
-
A lazy :class:`~core_lens.base.view.View` with the join spec
|
|
422
|
+
View: A lazy :class:`~core_lens.base.view.View` with the join spec
|
|
423
423
|
recorded for deferred execution.
|
|
424
424
|
"""
|
|
425
425
|
from core_lens.base.view import View
|
|
@@ -220,13 +220,13 @@ class PlotNamespace:
|
|
|
220
220
|
automatically via :meth:`~core_lens.base.result.Result.with_geometry`.
|
|
221
221
|
|
|
222
222
|
Args:
|
|
223
|
-
column: The column to use for colour mapping.
|
|
224
|
-
subplot_on: Optional temporal dimension to split data across.
|
|
223
|
+
column (str): The column to use for colour mapping.
|
|
224
|
+
subplot_on (SubplotOn | None, optional): Optional temporal dimension to split data across.
|
|
225
225
|
A :class:`~core_lens.base.namespaces.plot.SubplotOn` enum value. When set, one layer is rendered per unique
|
|
226
226
|
value of ``subplot_on`` in the data.
|
|
227
227
|
|
|
228
228
|
Returns:
|
|
229
|
-
A Lonboard Map object.
|
|
229
|
+
lonboard.Map: A Lonboard Map object.
|
|
230
230
|
|
|
231
231
|
Raises:
|
|
232
232
|
ValueError: If ``column`` or ``subplot_on`` column not found in data.
|
|
@@ -311,16 +311,16 @@ class PlotNamespace:
|
|
|
311
311
|
plain :class:`bokeh.plotting.figure`.
|
|
312
312
|
|
|
313
313
|
Args:
|
|
314
|
-
x: The temporal column to plot on the x-axis.
|
|
315
|
-
y: The value column(s) to plot on the y-axis.
|
|
314
|
+
x (str | None, optional): The temporal column to plot on the x-axis.
|
|
315
|
+
y (str | list[str] | None, optional): The value column(s) to plot on the y-axis.
|
|
316
316
|
If ``None``, all numeric columns (except ``x``) are used.
|
|
317
|
-
subplot_on: Optional temporal dimension to split data across.
|
|
317
|
+
subplot_on (SubplotOn | str | None, optional): Optional temporal dimension to split data across.
|
|
318
318
|
A :class:`~core_lens.base.namespaces.plot.SubplotOn` enum value or string.
|
|
319
|
-
top_n: Maximum number of entities rendered in per-entity view.
|
|
320
|
-
aggregate: If ``True``, renders only the aggregated mean view.
|
|
319
|
+
top_n (int, optional): Maximum number of entities rendered in per-entity view.
|
|
320
|
+
aggregate (bool, optional): If ``True``, renders only the aggregated mean view.
|
|
321
321
|
|
|
322
322
|
Returns:
|
|
323
|
-
A Bokeh Tabs object (or a single Figure when ``aggregate=True``).
|
|
323
|
+
Any: A Bokeh Tabs object (or a single Figure when ``aggregate=True``).
|
|
324
324
|
"""
|
|
325
325
|
import polars as pl
|
|
326
326
|
import polars.selectors as cs
|
|
@@ -486,12 +486,12 @@ class PlotNamespace:
|
|
|
486
486
|
"""Render a scatter plot using Bokeh.
|
|
487
487
|
|
|
488
488
|
Args:
|
|
489
|
-
x: The column to plot on the x-axis.
|
|
490
|
-
y: The column(s) to plot on the y-axis. If None, auto-selects all numeric.
|
|
491
|
-
top_n: Maximum number of entities to plot.
|
|
489
|
+
x (str | None, optional): The column to plot on the x-axis.
|
|
490
|
+
y (str | list[str] | None, optional): The column(s) to plot on the y-axis. If None, auto-selects all numeric.
|
|
491
|
+
top_n (int, optional): Maximum number of entities to plot.
|
|
492
492
|
|
|
493
493
|
Returns:
|
|
494
|
-
A Bokeh Figure or Tabs object.
|
|
494
|
+
Any: A Bokeh Figure or Tabs object.
|
|
495
495
|
"""
|
|
496
496
|
import polars as pl
|
|
497
497
|
import polars.selectors as cs
|
|
@@ -562,11 +562,11 @@ class PlotNamespace:
|
|
|
562
562
|
"""Render a distribution (histogram) plot using Bokeh.
|
|
563
563
|
|
|
564
564
|
Args:
|
|
565
|
-
x: The column(s) to plot the distribution for. If None, auto-selects all numeric.
|
|
566
|
-
top_n: Maximum number of entities to include.
|
|
565
|
+
x (str | list[str] | None, optional): The column(s) to plot the distribution for. If None, auto-selects all numeric.
|
|
566
|
+
top_n (int, optional): Maximum number of entities to include.
|
|
567
567
|
|
|
568
568
|
Returns:
|
|
569
|
-
A Bokeh Figure or Tabs object.
|
|
569
|
+
Any: A Bokeh Figure or Tabs object.
|
|
570
570
|
"""
|
|
571
571
|
import numpy as np
|
|
572
572
|
import pandas as pd
|
|
@@ -631,11 +631,11 @@ class PlotNamespace:
|
|
|
631
631
|
"""Render a correlation heatmap using Bokeh.
|
|
632
632
|
|
|
633
633
|
Args:
|
|
634
|
-
columns: Optional list of columns to correlate. Defaults to all numeric.
|
|
635
|
-
top_n: Maximum number of entities to include (currently unused).
|
|
634
|
+
columns (list[str] | None, optional): Optional list of columns to correlate. Defaults to all numeric.
|
|
635
|
+
top_n (int, optional): Maximum number of entities to include (currently unused).
|
|
636
636
|
|
|
637
637
|
Returns:
|
|
638
|
-
A Bokeh Figure object.
|
|
638
|
+
Any: A Bokeh Figure object.
|
|
639
639
|
"""
|
|
640
640
|
import polars.selectors as cs
|
|
641
641
|
from bokeh.models import BasicTicker, ColumnDataSource, LinearColorMapper
|
|
@@ -708,13 +708,13 @@ class PlotNamespace:
|
|
|
708
708
|
"""Render a heatmap using Bokeh.
|
|
709
709
|
|
|
710
710
|
Args:
|
|
711
|
-
x: The column for the x-axis.
|
|
712
|
-
y: The column for the y-axis.
|
|
713
|
-
value: The column for the colour values.
|
|
714
|
-
top_n: Maximum number of entities to include (currently unused).
|
|
711
|
+
x (str | None, optional): The column for the x-axis.
|
|
712
|
+
y (str | None, optional): The column for the y-axis.
|
|
713
|
+
value (str | None, optional): The column for the colour values.
|
|
714
|
+
top_n (int, optional): Maximum number of entities to include (currently unused).
|
|
715
715
|
|
|
716
716
|
Returns:
|
|
717
|
-
A Bokeh Figure object.
|
|
717
|
+
Any: A Bokeh Figure object.
|
|
718
718
|
"""
|
|
719
719
|
from bokeh.models import (
|
|
720
720
|
BasicTicker,
|
|
@@ -789,7 +789,7 @@ class PlotNamespace:
|
|
|
789
789
|
"""Render a scatter matrix (pairs plot) using Bokeh.
|
|
790
790
|
|
|
791
791
|
Returns:
|
|
792
|
-
A Bokeh ``gridplot`` object.
|
|
792
|
+
Any: A Bokeh ``gridplot`` object.
|
|
793
793
|
"""
|
|
794
794
|
import polars.selectors as cs
|
|
795
795
|
from bokeh.layouts import gridplot
|
|
@@ -170,12 +170,12 @@ class StatsNamespace:
|
|
|
170
170
|
"""Per-column or per-entity descriptive statistics.
|
|
171
171
|
|
|
172
172
|
Args:
|
|
173
|
-
columns: Numeric columns to describe. Defaults to all numeric cols.
|
|
174
|
-
by: ``"column"`` (one row per column, design default) or
|
|
173
|
+
columns (list[str] | None, optional): Numeric columns to describe. Defaults to all numeric cols.
|
|
174
|
+
by (str, optional): ``"column"`` (one row per column, design default) or
|
|
175
175
|
``"entity"`` (one row per entity with mean/std per column).
|
|
176
176
|
|
|
177
177
|
Returns:
|
|
178
|
-
New :class:`~core_lens.base.result.Result` with descriptive stats.
|
|
178
|
+
Result: New :class:`~core_lens.base.result.Result` with descriptive stats.
|
|
179
179
|
|
|
180
180
|
Raises:
|
|
181
181
|
ValueError: If ``by`` is not ``\"column\"`` or ``\"entity\"``.
|
|
@@ -227,12 +227,12 @@ class StatsNamespace:
|
|
|
227
227
|
"""Pairwise correlations between columns.
|
|
228
228
|
|
|
229
229
|
Args:
|
|
230
|
-
columns: At least 2 column names.
|
|
231
|
-
method: A :class:`~core_lens.base.namespaces.stats.CorrelateMethod` enum value.
|
|
232
|
-
across: ``"entity"`` or ``"time"`` — recorded in metadata only.
|
|
230
|
+
columns (list[str]): At least 2 column names.
|
|
231
|
+
method (CorrelateMethod, optional): A :class:`~core_lens.base.namespaces.stats.CorrelateMethod` enum value.
|
|
232
|
+
across (str, optional): ``"entity"`` or ``"time"`` — recorded in metadata only.
|
|
233
233
|
|
|
234
234
|
Returns:
|
|
235
|
-
Result whose data has columns
|
|
235
|
+
Result: Result whose data has columns
|
|
236
236
|
``column_a | column_b | correlation | p_value``.
|
|
237
237
|
|
|
238
238
|
Raises:
|
|
@@ -296,16 +296,16 @@ class StatsNamespace:
|
|
|
296
296
|
"""Hypothesis test in three modes: group-based, period-based, single-sample.
|
|
297
297
|
|
|
298
298
|
Args:
|
|
299
|
-
column: Numeric column to test.
|
|
300
|
-
groups: Categorical column to split groups on.
|
|
301
|
-
periods: List of ``(from_year, to_year)`` period tuples.
|
|
302
|
-
against: Reference value for a one-sample test.
|
|
303
|
-
method: A :class:`~core_lens.base.namespaces.stats.TestMethod` enum value.
|
|
299
|
+
column (str): Numeric column to test.
|
|
300
|
+
groups (str | None, optional): Categorical column to split groups on.
|
|
301
|
+
periods (list[tuple[int, int]] | None, optional): List of ``(from_year, to_year)`` period tuples.
|
|
302
|
+
against (float | None, optional): Reference value for a one-sample test.
|
|
303
|
+
method (TestMethod | None, optional): A :class:`~core_lens.base.namespaces.stats.TestMethod` enum value.
|
|
304
304
|
Auto-selected via Shapiro-Wilk if ``None``.
|
|
305
|
-
significance_level: Alpha level for ``significant`` flag (default 0.05).
|
|
305
|
+
significance_level (float, optional): Alpha level for ``significant`` flag (default 0.05).
|
|
306
306
|
|
|
307
307
|
Returns:
|
|
308
|
-
Result whose data has per-group descriptive stats
|
|
308
|
+
Result: Result whose data has per-group descriptive stats
|
|
309
309
|
``group | n | mean | std | median`` and
|
|
310
310
|
``metadata`` with ``statistic``, ``p_value``, ``significant``.
|
|
311
311
|
|
|
@@ -447,13 +447,13 @@ class StatsNamespace:
|
|
|
447
447
|
"""Change between two time periods per entity.
|
|
448
448
|
|
|
449
449
|
Args:
|
|
450
|
-
column: Value column to compute change for.
|
|
451
|
-
from_period: Start year/period integer.
|
|
452
|
-
to_period: End year/period integer.
|
|
453
|
-
method: A :class:`~core_lens.base.namespaces.stats.ChangeMethod` enum value.
|
|
450
|
+
column (str): Value column to compute change for.
|
|
451
|
+
from_period (int): Start year/period integer.
|
|
452
|
+
to_period (int): End year/period integer.
|
|
453
|
+
method (ChangeMethod, optional): A :class:`~core_lens.base.namespaces.stats.ChangeMethod` enum value.
|
|
454
454
|
|
|
455
455
|
Returns:
|
|
456
|
-
For *absolute* / *percentage*: data has
|
|
456
|
+
Result: For *absolute* / *percentage*: data has
|
|
457
457
|
``key_col | value_from | value_to | change | pct_change``.
|
|
458
458
|
For *trend*: ``key_col | slope | r_squared | direction``.
|
|
459
459
|
|
|
@@ -550,15 +550,15 @@ class StatsNamespace:
|
|
|
550
550
|
"""Anomaly detection in cross-sectional or timeseries mode.
|
|
551
551
|
|
|
552
552
|
Args:
|
|
553
|
-
column: Value column to analyse.
|
|
554
|
-
mode: ``"cross_sectional"`` or ``"timeseries"``.
|
|
555
|
-
method: An :class:`~core_lens.base.namespaces.stats.AnomalyCrossMethod` or :class:`~core_lens.base.namespaces.stats.AnomalyTsMethod` enum value.
|
|
556
|
-
baseline: ``(from_year, to_year)`` inclusive. Required for
|
|
553
|
+
column (str): Value column to analyse.
|
|
554
|
+
mode (str): ``"cross_sectional"`` or ``"timeseries"``.
|
|
555
|
+
method (AnomalyCrossMethod | AnomalyTsMethod): An :class:`~core_lens.base.namespaces.stats.AnomalyCrossMethod` or :class:`~core_lens.base.namespaces.stats.AnomalyTsMethod` enum value.
|
|
556
|
+
baseline (tuple[int, int] | None, optional): ``(from_year, to_year)`` inclusive. Required for
|
|
557
557
|
timeseries; optional for cross-sectional.
|
|
558
|
-
threshold: Sigma / score threshold for anomaly flag (default 2.0).
|
|
558
|
+
threshold (float, optional): Sigma / score threshold for anomaly flag (default 2.0).
|
|
559
559
|
|
|
560
560
|
Returns:
|
|
561
|
-
Result whose data has ``key_col | anomaly_score | is_anomaly``
|
|
561
|
+
Result: Result whose data has ``key_col | anomaly_score | is_anomaly``
|
|
562
562
|
(cross-sectional) or ``key_col | year | anomaly_score | is_anomaly``
|
|
563
563
|
(timeseries, baseline period excluded).
|
|
564
564
|
|
|
@@ -78,7 +78,7 @@ class Result:
|
|
|
78
78
|
"""Return the underlying ``pl.DataFrame``.
|
|
79
79
|
|
|
80
80
|
Returns:
|
|
81
|
-
The materialised data frame.
|
|
81
|
+
pl.DataFrame: The materialised data frame.
|
|
82
82
|
"""
|
|
83
83
|
return self.data
|
|
84
84
|
|
|
@@ -89,7 +89,7 @@ class Result:
|
|
|
89
89
|
:meth:`with_geometry` first on non-static results.
|
|
90
90
|
|
|
91
91
|
Returns:
|
|
92
|
-
A ``geopandas.GeoDataFrame`` built from :attr:`data`.
|
|
92
|
+
gpd.GeoDataFrame: A ``geopandas.GeoDataFrame`` built from :attr:`data`.
|
|
93
93
|
|
|
94
94
|
Raises:
|
|
95
95
|
TypeError: If :attr:`has_geometry` is ``False``.
|
|
@@ -118,7 +118,7 @@ class Result:
|
|
|
118
118
|
are responsible for collecting and wrapping the output themselves.
|
|
119
119
|
|
|
120
120
|
Returns:
|
|
121
|
-
A lazy frame backed by :attr:`data`.
|
|
121
|
+
pl.LazyFrame: A lazy frame backed by :attr:`data`.
|
|
122
122
|
"""
|
|
123
123
|
return self.data.lazy()
|
|
124
124
|
|
|
@@ -134,7 +134,7 @@ class Result:
|
|
|
134
134
|
``result.plot.choropleth()``.
|
|
135
135
|
|
|
136
136
|
Returns:
|
|
137
|
-
A new :class:`Result` with the geometry column merged in and
|
|
137
|
+
Result: A new :class:`Result` with the geometry column merged in and
|
|
138
138
|
``has_geometry=True``. If ``has_geometry`` is already ``True``,
|
|
139
139
|
returns ``self`` unchanged.
|
|
140
140
|
"""
|
|
@@ -164,11 +164,11 @@ class Result:
|
|
|
164
164
|
.derive("drought_flag", pl.when(pl.col("rainfall") < 500).then(1).otherwise(0))
|
|
165
165
|
|
|
166
166
|
Args:
|
|
167
|
-
name: Name for the new column.
|
|
168
|
-
expr: A Polars expression that evaluates to the column values.
|
|
167
|
+
name (str): Name for the new column.
|
|
168
|
+
expr (pl.Expr): A Polars expression that evaluates to the column values.
|
|
169
169
|
|
|
170
170
|
Returns:
|
|
171
|
-
A new :class:`Result` with ``name`` appended to :attr:`data`.
|
|
171
|
+
Result: A new :class:`Result` with ``name`` appended to :attr:`data`.
|
|
172
172
|
"""
|
|
173
173
|
new_data = self.data.with_columns(expr.alias(name))
|
|
174
174
|
return self._replace(data=new_data)
|
|
@@ -201,9 +201,9 @@ class Result:
|
|
|
201
201
|
- ✅
|
|
202
202
|
|
|
203
203
|
Args:
|
|
204
|
-
*exprs: One or more Polars aggregation expressions
|
|
204
|
+
*exprs (pl.Expr): One or more Polars aggregation expressions
|
|
205
205
|
(e.g. ``pl.mean("ndvi")``, ``pl.max("rainfall")``).
|
|
206
|
-
by: Grouping dimension. ``None`` collapses all rows to one.
|
|
206
|
+
by (str | None, optional): Grouping dimension. ``None`` collapses all rows to one.
|
|
207
207
|
``"year"`` groups by entity + year and is valid for both
|
|
208
208
|
annual and fortnightly resolution.
|
|
209
209
|
Other temporal groupings (``"month"``, ``"year_month"``,
|
|
@@ -211,7 +211,7 @@ class Result:
|
|
|
211
211
|
``resolution="fortnightly"``.
|
|
212
212
|
|
|
213
213
|
Returns:
|
|
214
|
-
A new :class:`Result` whose ``data`` is the aggregated frame.
|
|
214
|
+
Result: A new :class:`Result` whose ``data`` is the aggregated frame.
|
|
215
215
|
|
|
216
216
|
Raises:
|
|
217
217
|
ValueError: If ``by`` is incompatible with :attr:`resolution`, or
|
|
@@ -257,6 +257,9 @@ class Result:
|
|
|
257
257
|
result.stats.describe()
|
|
258
258
|
result.stats.correlate(["ndvi", "rainfall"], method="spearman")
|
|
259
259
|
result.stats.anomaly("ndvi", mode="cross_sectional", method="zscore")
|
|
260
|
+
|
|
261
|
+
Returns:
|
|
262
|
+
StatsNamespace: The statistical analysis namespace.
|
|
260
263
|
"""
|
|
261
264
|
from core_lens.base.namespaces.stats import StatsNamespace
|
|
262
265
|
|
|
@@ -272,6 +275,9 @@ class Result:
|
|
|
272
275
|
|
|
273
276
|
result.plot.choropleth("ndvi")
|
|
274
277
|
result.plot.timeseries(x="year", y="rainfall")
|
|
278
|
+
|
|
279
|
+
Returns:
|
|
280
|
+
PlotNamespace: The visualisation namespace.
|
|
275
281
|
"""
|
|
276
282
|
from core_lens.base.namespaces.plot import PlotNamespace
|
|
277
283
|
|