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.
Files changed (31) hide show
  1. {rasterix-0.1a3 → rasterix-0.1.1}/PKG-INFO +7 -42
  2. rasterix-0.1.1/README.md +24 -0
  3. {rasterix-0.1a3 → rasterix-0.1.1}/pyproject.toml +20 -15
  4. {rasterix-0.1a3 → rasterix-0.1.1}/src/rasterix/_version.py +16 -3
  5. rasterix-0.1.1/src/rasterix/lib.py +106 -0
  6. rasterix-0.1.1/src/rasterix/raster_index.py +1031 -0
  7. {rasterix-0.1a3 → rasterix-0.1.1}/src/rasterix/rasterize/rasterio.py +4 -3
  8. rasterix-0.1.1/src/rasterix/strategies.py +165 -0
  9. rasterix-0.1.1/src/rasterix/utils.py +108 -0
  10. {rasterix-0.1a3 → rasterix-0.1.1}/tests/geometry_mask_snapshot.nc +0 -0
  11. rasterix-0.1.1/tests/rasterize_snapshot.nc +0 -0
  12. {rasterix-0.1a3 → rasterix-0.1.1}/tests/test_exact.py +2 -1
  13. rasterix-0.1.1/tests/test_indexing.py +178 -0
  14. rasterix-0.1.1/tests/test_raster_index.py +708 -0
  15. {rasterix-0.1a3 → rasterix-0.1.1}/tests/test_rasterize.py +18 -14
  16. rasterix-0.1a3/README.md +0 -50
  17. rasterix-0.1a3/src/rasterix/raster_index.py +0 -707
  18. rasterix-0.1a3/tests/rasterize_snapshot.nc +0 -0
  19. rasterix-0.1a3/tests/test_raster_index.py +0 -255
  20. {rasterix-0.1a3 → rasterix-0.1.1}/.gitignore +0 -0
  21. {rasterix-0.1a3 → rasterix-0.1.1}/.pre-commit-config.yaml +0 -0
  22. {rasterix-0.1a3 → rasterix-0.1.1}/.readthedocs.yml +0 -0
  23. {rasterix-0.1a3 → rasterix-0.1.1}/LICENSE +0 -0
  24. {rasterix-0.1a3 → rasterix-0.1.1/_static}/rasterix.png +0 -0
  25. {rasterix-0.1a3 → rasterix-0.1.1}/design_notes/raster_index.md +0 -0
  26. {rasterix-0.1a3 → rasterix-0.1.1}/src/rasterix/__init__.py +0 -0
  27. {rasterix-0.1a3 → rasterix-0.1.1}/src/rasterix/odc_compat.py +0 -0
  28. {rasterix-0.1a3 → rasterix-0.1.1}/src/rasterix/rasterize/__init__.py +0 -0
  29. {rasterix-0.1a3 → rasterix-0.1.1}/src/rasterix/rasterize/exact.py +0 -0
  30. {rasterix-0.1a3 → rasterix-0.1.1}/src/rasterix/rasterize/utils.py +0 -0
  31. {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.1a3
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
- [![GitHub Workflow CI Status](https://img.shields.io/github/actions/workflow/status/dcherian/rasterix/test.yml?branch=main&logo=github&style=flat)](https://github.com/dcherian/rasterix/actions)
52
+ [![GitHub Workflow CI Status](https://img.shields.io/github/actions/workflow/status/xarray-contrib/rasterix/test.yml?branch=main&logo=github&style=flat)](https://github.com/xarray-contrib/rasterix/actions)
62
53
  [![Documentation Status](https://readthedocs.org/projects/rasterix/badge/?version=latest)](https://rasterix.readthedocs.io/en/latest/?badge=latest)
63
54
  [![PyPI](https://img.shields.io/pypi/v/rasterix.svg?style=flat)](https://pypi.org/project/rasterix/)
64
55
  [![Conda-forge](https://img.shields.io/conda/vn/conda-forge/rasterix.svg?style=flat)](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
- ### 1. RasterIndex
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
- See `src/rasterix/rasterize.py` for dask-aware wrappers around [`exactextract`](https://github.com/dcherian/rasterix/blob/ec3f51e60e25aa312e6f48c4b22f91bec70413ed/rasterize.py#L165), [`rasterio.features.rasterize`](https://github.com/dcherian/rasterix/blob/ec3f51e60e25aa312e6f48c4b22f91bec70413ed/rasterize.py#L307), and [`rasterio.features.geometry_mask`](https://github.com/dcherian/rasterix/blob/ec3f51e60e25aa312e6f48c4b22f91bec70413ed/rasterize.py#L472).
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
- ```
@@ -0,0 +1,24 @@
1
+ # rasterix: Raster tricks for Xarray
2
+
3
+ [![GitHub Workflow CI Status](https://img.shields.io/github/actions/workflow/status/xarray-contrib/rasterix/test.yml?branch=main&logo=github&style=flat)](https://github.com/xarray-contrib/rasterix/actions)
4
+ [![Documentation Status](https://readthedocs.org/projects/rasterix/badge/?version=latest)](https://rasterix.readthedocs.io/en/latest/?badge=latest)
5
+ [![PyPI](https://img.shields.io/pypi/v/rasterix.svg?style=flat)](https://pypi.org/project/rasterix/)
6
+ [![Conda-forge](https://img.shields.io/conda/vn/conda-forge/rasterix.svg?style=flat)](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
- [tool.hatch.envs.test]
91
- dependencies = [
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
- features = ["test"]
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__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
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.1a3'
21
- __version_tuple__ = version_tuple = (0, 1, 'a3')
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)