rasterix 0.1a3__tar.gz → 0.1.1__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.
- {rasterix-0.1a3 → rasterix-0.1.1}/PKG-INFO +7 -42
- rasterix-0.1.1/README.md +24 -0
- {rasterix-0.1a3 → rasterix-0.1.1}/pyproject.toml +20 -15
- {rasterix-0.1a3 → rasterix-0.1.1}/src/rasterix/_version.py +16 -3
- rasterix-0.1.1/src/rasterix/lib.py +106 -0
- rasterix-0.1.1/src/rasterix/raster_index.py +1031 -0
- {rasterix-0.1a3 → rasterix-0.1.1}/src/rasterix/rasterize/rasterio.py +4 -3
- rasterix-0.1.1/src/rasterix/strategies.py +165 -0
- rasterix-0.1.1/src/rasterix/utils.py +108 -0
- {rasterix-0.1a3 → rasterix-0.1.1}/tests/geometry_mask_snapshot.nc +0 -0
- rasterix-0.1.1/tests/rasterize_snapshot.nc +0 -0
- {rasterix-0.1a3 → rasterix-0.1.1}/tests/test_exact.py +2 -1
- rasterix-0.1.1/tests/test_indexing.py +178 -0
- rasterix-0.1.1/tests/test_raster_index.py +708 -0
- {rasterix-0.1a3 → rasterix-0.1.1}/tests/test_rasterize.py +18 -14
- rasterix-0.1a3/README.md +0 -50
- rasterix-0.1a3/src/rasterix/raster_index.py +0 -707
- rasterix-0.1a3/tests/rasterize_snapshot.nc +0 -0
- rasterix-0.1a3/tests/test_raster_index.py +0 -255
- {rasterix-0.1a3 → rasterix-0.1.1}/.gitignore +0 -0
- {rasterix-0.1a3 → rasterix-0.1.1}/.pre-commit-config.yaml +0 -0
- {rasterix-0.1a3 → rasterix-0.1.1}/.readthedocs.yml +0 -0
- {rasterix-0.1a3 → rasterix-0.1.1}/LICENSE +0 -0
- {rasterix-0.1a3 → rasterix-0.1.1/_static}/rasterix.png +0 -0
- {rasterix-0.1a3 → rasterix-0.1.1}/design_notes/raster_index.md +0 -0
- {rasterix-0.1a3 → rasterix-0.1.1}/src/rasterix/__init__.py +0 -0
- {rasterix-0.1a3 → rasterix-0.1.1}/src/rasterix/odc_compat.py +0 -0
- {rasterix-0.1a3 → rasterix-0.1.1}/src/rasterix/rasterize/__init__.py +0 -0
- {rasterix-0.1a3 → rasterix-0.1.1}/src/rasterix/rasterize/exact.py +0 -0
- {rasterix-0.1a3 → rasterix-0.1.1}/src/rasterix/rasterize/utils.py +0 -0
- {rasterix-0.1a3 → rasterix-0.1.1}/src/rasterix/rioxarray_compat.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rasterix
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: Raster extensions for Xarray
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
License-File: LICENSE
|
|
@@ -17,6 +17,7 @@ Requires-Dist: affine
|
|
|
17
17
|
Requires-Dist: numpy>=2
|
|
18
18
|
Requires-Dist: pandas>=2
|
|
19
19
|
Requires-Dist: xarray>=2025
|
|
20
|
+
Requires-Dist: xproj>=0.2.0
|
|
20
21
|
Provides-Extra: dask
|
|
21
22
|
Requires-Dist: dask-geopandas; extra == 'dask'
|
|
22
23
|
Provides-Extra: docs
|
|
@@ -44,65 +45,29 @@ Requires-Dist: exactextract; extra == 'exactextract'
|
|
|
44
45
|
Requires-Dist: sparse; extra == 'exactextract'
|
|
45
46
|
Provides-Extra: rasterize
|
|
46
47
|
Requires-Dist: rasterio; extra == 'rasterize'
|
|
47
|
-
Provides-Extra: test
|
|
48
|
-
Requires-Dist: dask-geopandas; extra == 'test'
|
|
49
|
-
Requires-Dist: exactextract; extra == 'test'
|
|
50
|
-
Requires-Dist: geodatasets; extra == 'test'
|
|
51
|
-
Requires-Dist: hypothesis; extra == 'test'
|
|
52
|
-
Requires-Dist: netcdf4; extra == 'test'
|
|
53
|
-
Requires-Dist: pooch; extra == 'test'
|
|
54
|
-
Requires-Dist: rasterio; extra == 'test'
|
|
55
|
-
Requires-Dist: rioxarray; extra == 'test'
|
|
56
|
-
Requires-Dist: sparse; extra == 'test'
|
|
57
48
|
Description-Content-Type: text/markdown
|
|
58
49
|
|
|
59
50
|
# rasterix: Raster tricks for Xarray
|
|
60
51
|
|
|
61
|
-
[](https://github.com/xarray-contrib/rasterix/actions)
|
|
62
53
|
[](https://rasterix.readthedocs.io/en/latest/?badge=latest)
|
|
63
54
|
[](https://pypi.org/project/rasterix/)
|
|
64
55
|
[](https://anaconda.org/conda-forge/rasterix)
|
|
65
56
|
|
|
66
|
-
<img src="rasterix.png" width="300">
|
|
57
|
+
<img src="_static/rasterix.png" width="300">
|
|
67
58
|
|
|
68
59
|
This WIP project contains tools to make it easier to analyze raster data with Xarray.
|
|
69
|
-
|
|
70
|
-
The intent is to provide reusable building blocks for the many sub-ecosystems around: e.g. rioxarray, odc-geo, etc.
|
|
71
|
-
|
|
72
|
-
## Contents
|
|
73
|
-
|
|
74
60
|
It currently has two pieces.
|
|
75
61
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
See `src/ rasterix/raster_index.py` and `notebooks/raster_index.ipynb` for a brief demo.
|
|
79
|
-
|
|
80
|
-
### 2. Dask-aware rasterization wrappers
|
|
62
|
+
1. `RasterIndex` for indexing using the affine transform recorded in GeoTIFFs.
|
|
63
|
+
1. Dask-aware rasterization wrappers around `exactextract`, `rasterio.features.rasterize`, and `rasterio.features.geometry_mask`.
|
|
81
64
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
This code is likely to move elsewhere!
|
|
65
|
+
Our intent is to provide reusable building blocks for the many sub-ecosystems around: e.g. `rioxarray`, `odc.geo`, etc.
|
|
85
66
|
|
|
86
67
|
## Installing
|
|
87
68
|
|
|
88
|
-
### PyPI
|
|
89
|
-
|
|
90
69
|
`rasterix` alpha releases are available on pypi
|
|
91
70
|
|
|
92
71
|
```
|
|
93
72
|
pip install rasterix
|
|
94
73
|
```
|
|
95
|
-
|
|
96
|
-
## Developing
|
|
97
|
-
|
|
98
|
-
1. Clone the repo
|
|
99
|
-
```
|
|
100
|
-
git remote add upstream git@github.com:dcherian/rasterix.git
|
|
101
|
-
cd rasterix
|
|
102
|
-
```
|
|
103
|
-
1. [Install hatch](https://hatch.pypa.io/1.12/install/)
|
|
104
|
-
1. Run the tests
|
|
105
|
-
```
|
|
106
|
-
hatch env run --env test.py3.13 run-pytest # Run the tests without coverage reports
|
|
107
|
-
hatch env run --env test.py3.13 run-coverage-html # Run the tests with an html coverage report
|
|
108
|
-
```
|
rasterix-0.1.1/README.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# rasterix: Raster tricks for Xarray
|
|
2
|
+
|
|
3
|
+
[](https://github.com/xarray-contrib/rasterix/actions)
|
|
4
|
+
[](https://rasterix.readthedocs.io/en/latest/?badge=latest)
|
|
5
|
+
[](https://pypi.org/project/rasterix/)
|
|
6
|
+
[](https://anaconda.org/conda-forge/rasterix)
|
|
7
|
+
|
|
8
|
+
<img src="_static/rasterix.png" width="300">
|
|
9
|
+
|
|
10
|
+
This WIP project contains tools to make it easier to analyze raster data with Xarray.
|
|
11
|
+
It currently has two pieces.
|
|
12
|
+
|
|
13
|
+
1. `RasterIndex` for indexing using the affine transform recorded in GeoTIFFs.
|
|
14
|
+
1. Dask-aware rasterization wrappers around `exactextract`, `rasterio.features.rasterize`, and `rasterio.features.geometry_mask`.
|
|
15
|
+
|
|
16
|
+
Our intent is to provide reusable building blocks for the many sub-ecosystems around: e.g. `rioxarray`, `odc.geo`, etc.
|
|
17
|
+
|
|
18
|
+
## Installing
|
|
19
|
+
|
|
20
|
+
`rasterix` alpha releases are available on pypi
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
pip install rasterix
|
|
24
|
+
```
|
|
@@ -29,6 +29,7 @@ dependencies = [
|
|
|
29
29
|
"affine",
|
|
30
30
|
"pandas>=2",
|
|
31
31
|
"numpy>=2",
|
|
32
|
+
"xproj>=0.2.0",
|
|
32
33
|
"xarray>=2025",
|
|
33
34
|
]
|
|
34
35
|
dynamic=["version"]
|
|
@@ -37,17 +38,6 @@ dynamic=["version"]
|
|
|
37
38
|
dask = ["dask-geopandas"]
|
|
38
39
|
rasterize = ["rasterio"]
|
|
39
40
|
exactextract = ["exactextract", "sparse"]
|
|
40
|
-
test = [
|
|
41
|
-
"geodatasets",
|
|
42
|
-
"pooch",
|
|
43
|
-
"dask-geopandas",
|
|
44
|
-
"rasterio",
|
|
45
|
-
"rioxarray",
|
|
46
|
-
"exactextract",
|
|
47
|
-
"sparse",
|
|
48
|
-
"netCDF4",
|
|
49
|
-
"hypothesis",
|
|
50
|
-
]
|
|
51
41
|
docs = [
|
|
52
42
|
"geodatasets",
|
|
53
43
|
"pooch",
|
|
@@ -75,6 +65,9 @@ docs = [
|
|
|
75
65
|
[tool.hatch]
|
|
76
66
|
version.source = "vcs"
|
|
77
67
|
|
|
68
|
+
[tool.hatch.metadata]
|
|
69
|
+
allow-direct-references = true
|
|
70
|
+
|
|
78
71
|
[tool.hatch.build]
|
|
79
72
|
hooks.vcs.version-file = "src/rasterix/_version.py"
|
|
80
73
|
|
|
@@ -87,14 +80,26 @@ exclude = [
|
|
|
87
80
|
"doc",
|
|
88
81
|
]
|
|
89
82
|
|
|
90
|
-
[
|
|
91
|
-
|
|
83
|
+
[dependency-groups]
|
|
84
|
+
test = [
|
|
92
85
|
"coverage",
|
|
86
|
+
"dask-geopandas",
|
|
87
|
+
"exactextract",
|
|
88
|
+
"geodatasets",
|
|
89
|
+
"hypothesis",
|
|
90
|
+
"netCDF4",
|
|
91
|
+
"pooch",
|
|
92
|
+
"pytest",
|
|
93
93
|
"pytest",
|
|
94
94
|
"pytest-cov",
|
|
95
|
-
"pytest-xdist"
|
|
95
|
+
"pytest-xdist",
|
|
96
|
+
"rasterio",
|
|
97
|
+
"sparse",
|
|
98
|
+
"xarray @ git+https://github.com/pydata/xarray.git@26ccc7f8f014f29c551fd566a04d6e9f878c0b0b", # https://github.com/pydata/xarray/pull/10980
|
|
96
99
|
]
|
|
97
|
-
|
|
100
|
+
|
|
101
|
+
[tool.hatch.envs.test]
|
|
102
|
+
dependency-groups = ["test"]
|
|
98
103
|
|
|
99
104
|
[[tool.hatch.envs.test.matrix]]
|
|
100
105
|
python = ["3.11", "3.13"]
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
# file generated by setuptools-scm
|
|
2
2
|
# don't change, don't track in version control
|
|
3
3
|
|
|
4
|
-
__all__ = [
|
|
4
|
+
__all__ = [
|
|
5
|
+
"__version__",
|
|
6
|
+
"__version_tuple__",
|
|
7
|
+
"version",
|
|
8
|
+
"version_tuple",
|
|
9
|
+
"__commit_id__",
|
|
10
|
+
"commit_id",
|
|
11
|
+
]
|
|
5
12
|
|
|
6
13
|
TYPE_CHECKING = False
|
|
7
14
|
if TYPE_CHECKING:
|
|
@@ -9,13 +16,19 @@ if TYPE_CHECKING:
|
|
|
9
16
|
from typing import Union
|
|
10
17
|
|
|
11
18
|
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
19
|
+
COMMIT_ID = Union[str, None]
|
|
12
20
|
else:
|
|
13
21
|
VERSION_TUPLE = object
|
|
22
|
+
COMMIT_ID = object
|
|
14
23
|
|
|
15
24
|
version: str
|
|
16
25
|
__version__: str
|
|
17
26
|
__version_tuple__: VERSION_TUPLE
|
|
18
27
|
version_tuple: VERSION_TUPLE
|
|
28
|
+
commit_id: COMMIT_ID
|
|
29
|
+
__commit_id__: COMMIT_ID
|
|
19
30
|
|
|
20
|
-
__version__ = version = '0.
|
|
21
|
-
__version_tuple__ = version_tuple = (0, 1,
|
|
31
|
+
__version__ = version = '0.1.1'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 1, 1)
|
|
33
|
+
|
|
34
|
+
__commit_id__ = commit_id = None
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""Shared library utilities for rasterix."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
from affine import Affine
|
|
6
|
+
|
|
7
|
+
# Define TRACE level (lower than DEBUG)
|
|
8
|
+
TRACE = 5
|
|
9
|
+
logging.addLevelName(TRACE, "TRACE")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class TraceLogger(logging.Logger):
|
|
13
|
+
"""Logger with trace level support."""
|
|
14
|
+
|
|
15
|
+
def trace(self, message, *args, **kwargs):
|
|
16
|
+
"""Log a message with severity 'TRACE'."""
|
|
17
|
+
if self.isEnabledFor(TRACE):
|
|
18
|
+
self._log(TRACE, message, args, **kwargs)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# Set the custom logger class
|
|
22
|
+
logging.setLoggerClass(TraceLogger)
|
|
23
|
+
|
|
24
|
+
# Create logger for the rasterix package
|
|
25
|
+
logger = logging.getLogger("rasterix")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def affine_from_tiepoint_and_scale(
|
|
29
|
+
tiepoint: list[float] | tuple[float, ...],
|
|
30
|
+
scale: list[float] | tuple[float, ...],
|
|
31
|
+
) -> Affine:
|
|
32
|
+
"""Create an Affine transform from GeoTIFF tiepoint and pixel scale.
|
|
33
|
+
|
|
34
|
+
Parameters
|
|
35
|
+
----------
|
|
36
|
+
tiepoint : list or tuple
|
|
37
|
+
GeoTIFF model tiepoint in format [I, J, K, X, Y, Z]
|
|
38
|
+
where (I, J, K) are pixel coords and (X, Y, Z) are world coords.
|
|
39
|
+
scale : list or tuple
|
|
40
|
+
GeoTIFF model pixel scale in format [ScaleX, ScaleY, ScaleZ].
|
|
41
|
+
|
|
42
|
+
Returns
|
|
43
|
+
-------
|
|
44
|
+
Affine
|
|
45
|
+
Affine transformation matrix.
|
|
46
|
+
|
|
47
|
+
Raises
|
|
48
|
+
------
|
|
49
|
+
AssertionError
|
|
50
|
+
If ScaleZ is not 0 (only 2D rasters are supported).
|
|
51
|
+
|
|
52
|
+
Examples
|
|
53
|
+
--------
|
|
54
|
+
>>> tiepoint = [0.0, 0.0, 0.0, 323400.0, 4265400.0, 0.0]
|
|
55
|
+
>>> scale = [30.0, 30.0, 0.0]
|
|
56
|
+
>>> affine = affine_from_tiepoint_and_scale(tiepoint, scale)
|
|
57
|
+
"""
|
|
58
|
+
if len(tiepoint) < 6:
|
|
59
|
+
raise ValueError(f"tiepoint must have at least 6 elements, got {len(tiepoint)}")
|
|
60
|
+
if len(scale) < 3:
|
|
61
|
+
raise ValueError(f"scale must have at least 3 elements, got {len(scale)}")
|
|
62
|
+
|
|
63
|
+
i, j, k, x, y, z = tiepoint[:6]
|
|
64
|
+
scale_x, scale_y, scale_z = scale[:3]
|
|
65
|
+
|
|
66
|
+
# We only support 2D rasters
|
|
67
|
+
assert scale_z == 0, f"Z pixel scale must be 0 for 2D rasters, got {scale_z}"
|
|
68
|
+
|
|
69
|
+
# The tiepoint gives us the world coordinates at pixel (I, J)
|
|
70
|
+
# Affine transform: x_world = c + i * a, y_world = f + j * e
|
|
71
|
+
# So: c = x - i * scale_x, f = y - j * scale_y
|
|
72
|
+
c = x - i * scale_x
|
|
73
|
+
f = y - j * scale_y
|
|
74
|
+
|
|
75
|
+
return Affine.translation(c, f) * Affine.scale(scale_x, scale_y)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def affine_from_stac_proj_metadata(metadata: dict) -> Affine | None:
|
|
79
|
+
"""Extract Affine transform from STAC projection metadata.
|
|
80
|
+
|
|
81
|
+
Parameters
|
|
82
|
+
----------
|
|
83
|
+
metadata : dict
|
|
84
|
+
Dictionary containing STAC metadata. Should contain a 'proj:transform' key.
|
|
85
|
+
|
|
86
|
+
Returns
|
|
87
|
+
-------
|
|
88
|
+
Affine or None
|
|
89
|
+
Affine transformation matrix if 'proj:transform' is found, None otherwise.
|
|
90
|
+
|
|
91
|
+
Examples
|
|
92
|
+
--------
|
|
93
|
+
>>> metadata = {"proj:transform": [30.0, 0.0, 323400.0, 0.0, 30.0, 4268400.0]}
|
|
94
|
+
>>> affine = affine_from_stac_proj_metadata(metadata)
|
|
95
|
+
"""
|
|
96
|
+
if "proj:transform" not in metadata:
|
|
97
|
+
return None
|
|
98
|
+
|
|
99
|
+
transform = metadata["proj:transform"]
|
|
100
|
+
# proj:transform is a 3x3 matrix in row-major order, but typically only 6 elements
|
|
101
|
+
# [a, b, c, d, e, f, 0, 0, 1] where the affine is constructed from first 6 elements
|
|
102
|
+
if len(transform) < 6:
|
|
103
|
+
raise ValueError(f"proj:transform must have at least 6 elements, got {len(transform)}")
|
|
104
|
+
|
|
105
|
+
a, b, c, d, e, f = transform[:6]
|
|
106
|
+
return Affine(a, b, c, d, e, f)
|