core-lens 0.1.dev136__tar.gz → 0.1.dev138__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.dev136 → core_lens-0.1.dev138}/PKG-INFO +1 -1
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/docs/source/export.md +8 -2
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/docs/source/intro.md +3 -1
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/docs/source/queries.md +3 -2
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/docs/source/quickstart.md +4 -4
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/src/core_lens/_version.py +2 -2
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/src/core_lens/schema/detection.py +8 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/src/core_lens/utils/spatial.py +17 -4
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/.github/ISSUE_TEMPLATE/blank-proposal.yaml +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/.github/ISSUE_TEMPLATE/bug-report.yaml +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/.github/ISSUE_TEMPLATE/feature-request.yaml +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/.github/pull_request_template.md +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/.github/workflows/ci.yml +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/.github/workflows/gh-pages.yml +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/.github/workflows/pre-release.yml +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/.github/workflows/release.yml +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/.gitignore +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/.gitmessage +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/.pre-commit-config.yaml +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/.python-version +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/CONTRIBUTING.md +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/LICENSE +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/README.md +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/SKILLS.md +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/benchmarks/README.md +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/benchmarks/bench_aoi.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/benchmarks/bench_export.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/benchmarks/bench_polars_utils.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/benchmarks/bench_result.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/benchmarks/bench_schema.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/benchmarks/bench_season.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/benchmarks/bench_spatial.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/benchmarks/bench_view.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/benchmarks/run_all.sh +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/docs/Makefile +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/docs/make.bat +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/docs/source/concepts.md +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/docs/source/conf.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/docs/source/index.rst +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/docs/source/logging.md +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/docs/source/plots.md +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/docs/source/plugins.md +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/docs/source/stats.md +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/examples/demo_mws.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/examples/demo_tehsil.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/hooks/mypy.sh +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/hooks/no-parquet-outside-fixtures.sh +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/hooks/pytest.sh +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/pyproject.toml +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/src/core_lens/__init__.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/src/core_lens/__main__.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/src/core_lens/aoi.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/src/core_lens/base/__init__.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/src/core_lens/base/entity.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/src/core_lens/base/namespaces/__init__.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/src/core_lens/base/namespaces/plot.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/src/core_lens/base/namespaces/stats.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/src/core_lens/base/result.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/src/core_lens/base/view.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/src/core_lens/entities/__init__.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/src/core_lens/entities/mws.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/src/core_lens/entities/tehsil.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/src/core_lens/entities/waterbody.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/src/core_lens/export/__init__.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/src/core_lens/export/formats.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/src/core_lens/py.typed +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/src/core_lens/schema/__init__.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/src/core_lens/schema/profile.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/src/core_lens/utils/__init__.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/src/core_lens/utils/paths.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/src/core_lens/utils/polars_utils.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/src/core_lens/utils/season.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/tests/fixtures/generate_fixtures.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/tests/unit/conftest.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/tests/unit/test_aoi.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/tests/unit/test_entities.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/tests/unit/test_entity.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/tests/unit/test_export.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/tests/unit/test_main.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/tests/unit/test_plot.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/tests/unit/test_polars_utils.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/tests/unit/test_profile.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/tests/unit/test_result.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/tests/unit/test_schema_detection.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/tests/unit/test_schema_profile.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/tests/unit/test_season.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/tests/unit/test_season_config.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/tests/unit/test_spatial.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/tests/unit/test_stats.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/tests/unit/test_view.py +0 -0
- {core_lens-0.1.dev136 → core_lens-0.1.dev138}/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.dev138
|
|
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
|
|
@@ -41,7 +41,13 @@ geoparquet(
|
|
|
41
41
|
|
|
42
42
|
# Export to GeoJSON
|
|
43
43
|
geojson(spatial_res, "output.json")
|
|
44
|
+
|
|
45
|
+
# Export to newline-delimited GeoJSON (GeoJSONSeq)
|
|
46
|
+
geojson(spatial_res, "output.ndjson", driver="GeoJSONSeq")
|
|
44
47
|
```
|
|
45
48
|
|
|
46
|
-
|
|
47
|
-
|
|
49
|
+
```{note}
|
|
50
|
+
Exporting to **GeoParquet** 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.
|
|
51
|
+
|
|
52
|
+
Exporting to **GeoJSON** is fully natively streamed directly from Polars and Shapely without invoking GDAL or DuckDB, making it extremely fast for large datasets. Driver-specific kwargs for GeoJSON are ignored.
|
|
53
|
+
```
|
|
@@ -13,4 +13,6 @@ CoreLens provides a unified interface over microwatersheds, administrative bound
|
|
|
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
15
|
- **Interactive Visualisation**: Generate interactive maps using Lonboard with zero-copy GeoArrow rendering directly from Polars, and timeseries/scatter plots using Bokeh.
|
|
16
|
-
- **
|
|
16
|
+
- **Cloud & Local Data**: Native support for reading Parquet data from local filesystems or directly from cloud storage (e.g., `s3://`).
|
|
17
|
+
- **High-Performance Exports**: Export results directly to Parquet, JSON, CSV, or spatially-enabled GeoParquet and GeoJSON (with a fast streaming writer).
|
|
18
|
+
- **Advanced Caching**: Transparently caches boundaries and pre-computes spatial indices (via on-disk sidecars) to achieve sub-second query initialisation times.
|
|
@@ -58,5 +58,6 @@ joined_view = aoi.mws.spatial_join(
|
|
|
58
58
|
# res = joined_view.annual
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
```{note}
|
|
62
|
+
Cross-entity spatial join execution (materialisation) is currently under development and will be added in a subsequent release. Calling materialisation methods (like `.annual`, `.static`, or `.fortnightly`) on a joined view will raise a `NotImplementedError` in the current version.
|
|
63
|
+
```
|
|
@@ -25,18 +25,18 @@ AoI.register(MWSEntity)
|
|
|
25
25
|
AoI.register(TehsilEntity)
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
Create an `AoI` (Area of Interest) by specifying the `data_root` and your boundary (either by name, bounding box, or Shapely geometry):
|
|
28
|
+
Create an `AoI` (Area of Interest) by specifying the `data_root` (which can be a local path or a cloud URI like `s3://bucket/data`) and your boundary (either by name, bounding box, or Shapely geometry):
|
|
29
29
|
|
|
30
30
|
```python
|
|
31
|
-
# Create an AoI scoped to a specific Tehsil
|
|
31
|
+
# Create an AoI scoped to a specific Tehsil using a local path
|
|
32
32
|
aoi = AoI(
|
|
33
33
|
data_root="/path/to/data",
|
|
34
34
|
tehsil="Pangi"
|
|
35
35
|
)
|
|
36
36
|
|
|
37
|
-
# Or scope it directly to a specific list of entity IDs
|
|
37
|
+
# Or scope it directly to a specific list of entity IDs using an S3 bucket
|
|
38
38
|
aoi_specific = AoI(
|
|
39
|
-
data_root="/
|
|
39
|
+
data_root="s3://my-cloud-bucket/core-lens-data",
|
|
40
40
|
mws_id=["13_001", "13_002"]
|
|
41
41
|
)
|
|
42
42
|
|
|
@@ -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.dev138'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 1, 'dev138')
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -178,6 +178,14 @@ def _infer_bbox_cols(schema: pl.Schema) -> tuple[str, str, str, str] | None:
|
|
|
178
178
|
for pattern in _BBOX_PATTERNS:
|
|
179
179
|
if all(col in schema for col in pattern):
|
|
180
180
|
return pattern
|
|
181
|
+
|
|
182
|
+
for col_name, dtype in schema.items():
|
|
183
|
+
if isinstance(dtype, pl.Struct):
|
|
184
|
+
struct_fields = [f.name for f in dtype.fields]
|
|
185
|
+
for pattern in _BBOX_PATTERNS:
|
|
186
|
+
if all(f in struct_fields for f in pattern):
|
|
187
|
+
return tuple(f"{col_name}.{f}" for f in pattern) # type: ignore
|
|
188
|
+
|
|
181
189
|
return None
|
|
182
190
|
|
|
183
191
|
|
|
@@ -173,14 +173,27 @@ def build_bbox_index(
|
|
|
173
173
|
_so = storage_options or {}
|
|
174
174
|
if bbox_cols is not None:
|
|
175
175
|
logger.debug("Using pre-computed bbox columns: {}", bbox_cols)
|
|
176
|
-
|
|
176
|
+
base_bbox_cols = list(dict.fromkeys(c.split(".")[0] for c in bbox_cols))
|
|
177
|
+
cols_to_read = key_cols + base_bbox_cols
|
|
177
178
|
df = pl.read_parquet(
|
|
178
179
|
static_path, columns=cols_to_read, storage_options=_so or None
|
|
179
180
|
)
|
|
180
181
|
minx_col, miny_col, maxx_col, maxy_col = bbox_cols
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
182
|
+
|
|
183
|
+
for alias, col_path in zip(
|
|
184
|
+
["minx", "miny", "maxx", "maxy"],
|
|
185
|
+
[minx_col, miny_col, maxx_col, maxy_col],
|
|
186
|
+
):
|
|
187
|
+
parts = col_path.split(".")
|
|
188
|
+
if len(parts) == 1:
|
|
189
|
+
df = df.rename({col_path: alias})
|
|
190
|
+
else:
|
|
191
|
+
expr = pl.col(parts[0])
|
|
192
|
+
for p in parts[1:]:
|
|
193
|
+
expr = expr.struct.field(p)
|
|
194
|
+
df = df.with_columns(expr.alias(alias))
|
|
195
|
+
|
|
196
|
+
return df.select(key_cols + ["minx", "miny", "maxx", "maxy"])
|
|
184
197
|
|
|
185
198
|
cols_to_read = key_cols + [geometry_col]
|
|
186
199
|
if geometry_type == "latlon":
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|