rastr 0.4.0__tar.gz → 0.5.0__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.

Potentially problematic release.


This version of rastr might be problematic. Click here for more details.

Files changed (85) hide show
  1. {rastr-0.4.0 → rastr-0.5.0}/.github/copilot-instructions.md +1 -1
  2. {rastr-0.4.0 → rastr-0.5.0}/.github/workflows/ci.yml +19 -22
  3. {rastr-0.4.0 → rastr-0.5.0}/CONTRIBUTING.md +14 -2
  4. {rastr-0.4.0 → rastr-0.5.0}/PKG-INFO +10 -4
  5. {rastr-0.4.0 → rastr-0.5.0}/README.md +8 -2
  6. {rastr-0.4.0 → rastr-0.5.0}/pyproject.toml +1 -3
  7. {rastr-0.4.0 → rastr-0.5.0}/src/rastr/_version.py +2 -2
  8. {rastr-0.4.0 → rastr-0.5.0}/src/rastr/create.py +24 -14
  9. {rastr-0.4.0 → rastr-0.5.0}/src/rastr/io.py +5 -5
  10. {rastr-0.4.0 → rastr-0.5.0}/src/rastr/raster.py +514 -92
  11. rastr-0.5.0/src/scripts/demo_taper_border.py +4 -0
  12. {rastr-0.4.0 → rastr-0.5.0}/tests/rastr/test_create.py +132 -20
  13. {rastr-0.4.0 → rastr-0.5.0}/tests/rastr/test_meta.py +7 -7
  14. {rastr-0.4.0 → rastr-0.5.0}/tests/rastr/test_raster.py +1066 -135
  15. {rastr-0.4.0 → rastr-0.5.0}/uv.lock +23 -22
  16. {rastr-0.4.0 → rastr-0.5.0}/.copier-answers.yml +0 -0
  17. {rastr-0.4.0 → rastr-0.5.0}/.github/ISSUE_TEMPLATE/bug-report.md +0 -0
  18. {rastr-0.4.0 → rastr-0.5.0}/.github/ISSUE_TEMPLATE/enhancement.md +0 -0
  19. {rastr-0.4.0 → rastr-0.5.0}/.github/workflows/release.yml +0 -0
  20. {rastr-0.4.0 → rastr-0.5.0}/.gitignore +0 -0
  21. {rastr-0.4.0 → rastr-0.5.0}/.pre-commit-config.yaml +0 -0
  22. {rastr-0.4.0 → rastr-0.5.0}/.python-version +0 -0
  23. {rastr-0.4.0 → rastr-0.5.0}/LICENSE +0 -0
  24. {rastr-0.4.0 → rastr-0.5.0}/docs/index.md +0 -0
  25. {rastr-0.4.0 → rastr-0.5.0}/docs/logo.svg +0 -0
  26. {rastr-0.4.0 → rastr-0.5.0}/mkdocs.yml +0 -0
  27. {rastr-0.4.0 → rastr-0.5.0}/pyrightconfig.json +0 -0
  28. {rastr-0.4.0 → rastr-0.5.0}/requirements.txt +0 -0
  29. {rastr-0.4.0 → rastr-0.5.0}/src/archive/.gitkeep +0 -0
  30. {rastr-0.4.0 → rastr-0.5.0}/src/notebooks/.gitkeep +0 -0
  31. {rastr-0.4.0 → rastr-0.5.0}/src/rastr/__init__.py +0 -0
  32. {rastr-0.4.0 → rastr-0.5.0}/src/rastr/arr/__init__.py +0 -0
  33. {rastr-0.4.0 → rastr-0.5.0}/src/rastr/arr/fill.py +0 -0
  34. {rastr-0.4.0 → rastr-0.5.0}/src/rastr/gis/__init__.py +0 -0
  35. {rastr-0.4.0 → rastr-0.5.0}/src/rastr/gis/fishnet.py +0 -0
  36. {rastr-0.4.0 → rastr-0.5.0}/src/rastr/gis/smooth.py +0 -0
  37. {rastr-0.4.0 → rastr-0.5.0}/src/rastr/meta.py +0 -0
  38. {rastr-0.4.0 → rastr-0.5.0}/src/scripts/.gitkeep +0 -0
  39. {rastr-0.4.0 → rastr-0.5.0}/src/scripts/demo_point_cloud.py +0 -0
  40. {rastr-0.4.0 → rastr-0.5.0}/tasks/ABOUT_TASKS.md +0 -0
  41. {rastr-0.4.0 → rastr-0.5.0}/tasks/dev_sync.ps1 +0 -0
  42. {rastr-0.4.0 → rastr-0.5.0}/tasks/scripts/activate_venv.sh +0 -0
  43. {rastr-0.4.0 → rastr-0.5.0}/tasks/scripts/configure_project.sh +0 -0
  44. {rastr-0.4.0 → rastr-0.5.0}/tasks/scripts/dev_sync.sh +0 -0
  45. {rastr-0.4.0 → rastr-0.5.0}/tasks/scripts/install_backend.sh +0 -0
  46. {rastr-0.4.0 → rastr-0.5.0}/tasks/scripts/install_venv.sh +0 -0
  47. {rastr-0.4.0 → rastr-0.5.0}/tasks/scripts/recover_corrupt_venv.sh +0 -0
  48. {rastr-0.4.0 → rastr-0.5.0}/tasks/scripts/sh_runner.ps1 +0 -0
  49. {rastr-0.4.0 → rastr-0.5.0}/tasks/scripts/sync_requirements.sh +0 -0
  50. {rastr-0.4.0 → rastr-0.5.0}/tasks/scripts/sync_template.sh +0 -0
  51. {rastr-0.4.0 → rastr-0.5.0}/tasks/shims/activate_venv +0 -0
  52. {rastr-0.4.0 → rastr-0.5.0}/tasks/shims/activate_venv.cmd +0 -0
  53. {rastr-0.4.0 → rastr-0.5.0}/tasks/shims/activate_venv.ps1 +0 -0
  54. {rastr-0.4.0 → rastr-0.5.0}/tasks/shims/configure_project +0 -0
  55. {rastr-0.4.0 → rastr-0.5.0}/tasks/shims/configure_project.cmd +0 -0
  56. {rastr-0.4.0 → rastr-0.5.0}/tasks/shims/configure_project.ps1 +0 -0
  57. {rastr-0.4.0 → rastr-0.5.0}/tasks/shims/dev_sync +0 -0
  58. {rastr-0.4.0 → rastr-0.5.0}/tasks/shims/dev_sync.cmd +0 -0
  59. {rastr-0.4.0 → rastr-0.5.0}/tasks/shims/dev_sync.ps1 +0 -0
  60. {rastr-0.4.0 → rastr-0.5.0}/tasks/shims/install_backend +0 -0
  61. {rastr-0.4.0 → rastr-0.5.0}/tasks/shims/install_backend.cmd +0 -0
  62. {rastr-0.4.0 → rastr-0.5.0}/tasks/shims/install_backend.ps1 +0 -0
  63. {rastr-0.4.0 → rastr-0.5.0}/tasks/shims/install_venv +0 -0
  64. {rastr-0.4.0 → rastr-0.5.0}/tasks/shims/install_venv.cmd +0 -0
  65. {rastr-0.4.0 → rastr-0.5.0}/tasks/shims/install_venv.ps1 +0 -0
  66. {rastr-0.4.0 → rastr-0.5.0}/tasks/shims/recover_corrupt_venv +0 -0
  67. {rastr-0.4.0 → rastr-0.5.0}/tasks/shims/recover_corrupt_venv.cmd +0 -0
  68. {rastr-0.4.0 → rastr-0.5.0}/tasks/shims/recover_corrupt_venv.ps1 +0 -0
  69. {rastr-0.4.0 → rastr-0.5.0}/tasks/shims/sync_requirements +0 -0
  70. {rastr-0.4.0 → rastr-0.5.0}/tasks/shims/sync_requirements.cmd +0 -0
  71. {rastr-0.4.0 → rastr-0.5.0}/tasks/shims/sync_requirements.ps1 +0 -0
  72. {rastr-0.4.0 → rastr-0.5.0}/tasks/shims/sync_template +0 -0
  73. {rastr-0.4.0 → rastr-0.5.0}/tasks/shims/sync_template.cmd +0 -0
  74. {rastr-0.4.0 → rastr-0.5.0}/tasks/shims/sync_template.ps1 +0 -0
  75. {rastr-0.4.0 → rastr-0.5.0}/tasks/sync_template.ps1 +0 -0
  76. {rastr-0.4.0 → rastr-0.5.0}/tests/assets/.gitkeep +0 -0
  77. {rastr-0.4.0 → rastr-0.5.0}/tests/assets/pga_g_clipped.grd +0 -0
  78. {rastr-0.4.0 → rastr-0.5.0}/tests/assets/pga_g_clipped.tif +0 -0
  79. {rastr-0.4.0 → rastr-0.5.0}/tests/conftest.py +0 -0
  80. {rastr-0.4.0 → rastr-0.5.0}/tests/rastr/.gitkeep +0 -0
  81. {rastr-0.4.0 → rastr-0.5.0}/tests/rastr/gis/test_fishnet.py +0 -0
  82. {rastr-0.4.0 → rastr-0.5.0}/tests/rastr/gis/test_smooth.py +0 -0
  83. {rastr-0.4.0 → rastr-0.5.0}/tests/rastr/regression_test_data/test_plot_raster.png +0 -0
  84. {rastr-0.4.0 → rastr-0.5.0}/tests/rastr/regression_test_data/test_write_raster_to_file.tif +0 -0
  85. {rastr-0.4.0 → rastr-0.5.0}/tests/rastr/test_io.py +0 -0
@@ -10,7 +10,7 @@
10
10
  - Write unit tests using `pytest` inside `tests/`, structured based on `src/`.
11
11
  - Example: `src/x/y/z` → `tests/x/y/test_z.py`
12
12
  - Use test fixtures and group tests into classes when appropriate.
13
- - When testing methods on classes, create nested test classes within the test class associated with the overall tested class (e.g., `TestContour` nested within `TestRasterModel` when testing the `contour` method of `RasterModel`).
13
+ - When testing methods on classes, create nested test classes within the test class associated with the overall tested class (e.g., `TestContour` nested within `TestRaster` when testing the `contour` method of `Raster`).
14
14
  - After modifying a function, run its unit tests using pytest.
15
15
  - Run tests in virtual environment: `.\.venv\Scripts\activate; python -m pytest tests/path/to/test_file.py -v`
16
16
 
@@ -5,17 +5,17 @@ permissions:
5
5
  on:
6
6
  workflow_dispatch:
7
7
  push:
8
- branches: ['master', 'develop']
8
+ branches: ["master", "develop"]
9
9
  paths-ignore:
10
- - 'docs/**'
11
- - '**/*.md'
12
- - 'mkdocs.yml'
10
+ - "docs/**"
11
+ - "**/*.md"
12
+ - "mkdocs.yml"
13
13
  pull_request:
14
- branches: ['master', 'develop']
14
+ branches: ["master", "develop"]
15
15
  paths-ignore:
16
- - 'docs/**'
17
- - '**/*.md'
18
- - 'mkdocs.yml'
16
+ - "docs/**"
17
+ - "**/*.md"
18
+ - "mkdocs.yml"
19
19
  concurrency:
20
20
  group: ${{ github.workflow }}-${{ github.ref }}
21
21
  cancel-in-progress: true
@@ -39,21 +39,15 @@ jobs:
39
39
  version: "0.7.13" # Sync with pyproject.toml
40
40
  enable-cache: true
41
41
 
42
- - name: Set up Python
43
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
44
- with:
45
- python-version: ${{ matrix.python-version }}
46
-
47
- - name: Setup dependencies
42
+ - name: Setup Python
48
43
  run: |
49
44
  uv python pin ${{ matrix.python-version }}
50
- uv export --no-managed-python --no-group doc --resolution ${{ matrix.resolution }} > ci-requirements.txt
51
- uv pip install --system -r ci-requirements.txt
45
+ uv python install
52
46
 
53
47
  - name: Run pre-commit
54
48
  if: matrix.checks
55
49
  run: |
56
- uv run --frozen pre-commit run --all-files
50
+ uv run pre-commit run --all-files
57
51
 
58
52
  - name: Run pyright
59
53
  if: matrix.checks
@@ -64,7 +58,10 @@ jobs:
64
58
  uses: pavelzw/pytest-action@510c5e90c360a185039bea56ce8b3e7e51a16507 # v2.2.0
65
59
  if: matrix.pytest
66
60
  with:
61
+ custom-pytest: uv run pytest
67
62
  custom-arguments: --cov --junitxml=junit.xml -o junit_family=legacy --cov-report=xml
63
+ env:
64
+ MPLBACKEND: Agg # https://github.com/orgs/community/discussions/26434
68
65
 
69
66
  - name: Create test reports directory
70
67
  if: matrix.pytest && matrix.os == 'ubuntu-latest' && matrix.python-version == '3.13'
@@ -96,20 +93,20 @@ jobs:
96
93
  runs-on: ubuntu-latest
97
94
  needs: tests
98
95
  if: always() && needs.tests.result == 'success'
99
-
96
+
100
97
  steps:
101
98
  - name: Checkout code
102
99
  uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
103
100
  with:
104
- fetch-depth: 0 # Shallow clones should be disabled for better relevancy of analysis
105
-
101
+ fetch-depth: 0 # Shallow clones should be disabled for better relevancy of analysis
102
+
106
103
  - name: Download coverage reports
107
104
  uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
108
105
  with:
109
106
  name: coverage-reports
110
107
  path: test-reports/
111
108
  continue-on-error: true
112
-
109
+
113
110
  - name: Create SonarQube properties
114
111
  run: |
115
112
  cat > sonar-project.properties << EOF
@@ -122,7 +119,7 @@ jobs:
122
119
  sonar.exclusions=**/Dockerfile,**/notebooks/**,**/scripts/**
123
120
  sonar.verbose=false
124
121
  EOF
125
-
122
+
126
123
  - name: Run SonarQube analysis
127
124
  uses: SonarSource/sonarqube-scan-action@884b79409bbd464b2a59edc326a4b77dc56b2195 # v3.1.0
128
125
  env:
@@ -55,9 +55,21 @@ uv run detect-test-pollution --fuzz --tests ./tests
55
55
 
56
56
  and follow the prompts to bisect the tests.
57
57
 
58
- ### Profiling Test collection speed
58
+ ### Profiling the Test Suite
59
59
 
60
- To profile the speed of test collection (which is mostly related to import times), use `pyinstrument`:
60
+ To profile the test suite, use `pyinstrument`:
61
+
62
+ ```shell
63
+ uv run pyinstrument -m pytest
64
+ ```
65
+
66
+ For more in-depth exploration, try the `-r html` option to generate an HTML report:
67
+
68
+ ```shell
69
+ uv run pyinstrument -r html -m pytest
70
+ ```
71
+
72
+ To profile the speed of test _collection_ (which is mostly related to import times), you can also use `pyinstrument`:
61
73
 
62
74
  ```shell
63
75
  uv run pyinstrument -m pytest --collect-only
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rastr
3
- Version: 0.4.0
3
+ Version: 0.5.0
4
4
  Summary: Geospatial Raster datatype library for Python.
5
5
  Project-URL: Source Code, https://github.com/tonkintaylor/rastr
6
6
  Project-URL: Bug Tracker, https://github.com/tonkintaylor/rastr/issues
7
7
  Project-URL: Releases, https://github.com/tonkintaylor/rastr/releases
8
- Project-URL: Source Archive, https://github.com/tonkintaylor/rastr/archive/336916af169603534dd0728c10401667f263d98a.zip
8
+ Project-URL: Source Archive, https://github.com/tonkintaylor/rastr/archive/fde05e3c098da7ff9e77a37332d55fb7dbacd873.zip
9
9
  Author-email: Tonkin & Taylor Limited <Sub-DisciplineData+AnalyticsStaff@tonkintaylor.co.nz>, Nathan McDougall <nmcdougall@tonkintaylor.co.nz>, Ben Karl <bkarl@tonkintaylor.co.nz>
10
10
  License-Expression: MIT
11
11
  License-File: LICENSE
@@ -75,10 +75,10 @@ from pyproj.crs.crs import CRS
75
75
  from rasterio.transform import from_origin
76
76
  from rastr.create import full_raster
77
77
  from rastr.meta import RasterMeta
78
- from rastr.raster import RasterModel
78
+ from rastr.raster import Raster
79
79
 
80
80
  # Create an example raster
81
- raster = RasterModel.example()
81
+ raster = Raster.example()
82
82
 
83
83
  # Basic arithmetic operations
84
84
  doubled = raster * 2
@@ -131,6 +131,12 @@ Current version limitations:
131
131
  - Square cells only (rectangular cell support planned).
132
132
  - Only float dtypes (integer support planned).
133
133
 
134
+ ## Similar Projects
135
+
136
+ - [rasters](https://github.com/python-rasters/rasters) is a project with similar goals of providing a dedicated raster datatype in Python with higher-level interfaces for GIS operations. Unlike `rastr`, it has support for multi-band rasters, and has some more advanced functionality for Earth Science applications. Both projects are relatively new and under active development.
137
+ - [rasterio](https://rasterio.readthedocs.io/) is a core dependency of `rastr` and provides low-level raster I/O and processing capabilities.
138
+ - [rioxarray](https://corteva.github.io/rioxarray/stable/getting_started/getting_started.html) extends [`xarray`](https://docs.xarray.dev/en/stable/index.html) for raster data with geospatial support via `rasterio`.
139
+
134
140
  ### Contributing
135
141
 
136
142
  See the
@@ -41,10 +41,10 @@ from pyproj.crs.crs import CRS
41
41
  from rasterio.transform import from_origin
42
42
  from rastr.create import full_raster
43
43
  from rastr.meta import RasterMeta
44
- from rastr.raster import RasterModel
44
+ from rastr.raster import Raster
45
45
 
46
46
  # Create an example raster
47
- raster = RasterModel.example()
47
+ raster = Raster.example()
48
48
 
49
49
  # Basic arithmetic operations
50
50
  doubled = raster * 2
@@ -97,6 +97,12 @@ Current version limitations:
97
97
  - Square cells only (rectangular cell support planned).
98
98
  - Only float dtypes (integer support planned).
99
99
 
100
+ ## Similar Projects
101
+
102
+ - [rasters](https://github.com/python-rasters/rasters) is a project with similar goals of providing a dedicated raster datatype in Python with higher-level interfaces for GIS operations. Unlike `rastr`, it has support for multi-band rasters, and has some more advanced functionality for Earth Science applications. Both projects are relatively new and under active development.
103
+ - [rasterio](https://rasterio.readthedocs.io/) is a core dependency of `rastr` and provides low-level raster I/O and processing capabilities.
104
+ - [rioxarray](https://corteva.github.io/rioxarray/stable/getting_started/getting_started.html) extends [`xarray`](https://docs.xarray.dev/en/stable/index.html) for raster data with geospatial support via `rasterio`.
105
+
100
106
  ### Contributing
101
107
 
102
108
  See the
@@ -63,7 +63,7 @@ dev = [
63
63
  "pre-commit-update>=0.8.0",
64
64
  "pyinstrument>=5.1.1",
65
65
  "pyright[nodejs]>=1.1.403",
66
- "ruff>=0.12.5",
66
+ "ruff>=0.13.2",
67
67
  "tqdm>=4.67.1",
68
68
  "usethis>=0.15.2",
69
69
  ]
@@ -123,7 +123,6 @@ lint.ignore = [
123
123
  # In some cases where your code is poorly-performing you might want to enable them again.
124
124
  # ##############################
125
125
  "PD101", # Harms readability for a performance optimization.
126
- "PD901", # We often call variables "df" in functions dealing with pandas DataFrames.
127
126
  "PERF203", # Too many false positives.
128
127
  "PERF401", # This can hurt readability; the performance is not always worth it.
129
128
  "PIE804", # This is controversial, some pandas APIs work better with dict approach.
@@ -182,7 +181,6 @@ lint.per-file-ignores."tests/**/*.py" = [
182
181
  "PLR0913", # When we use fixtures, our test functions can have many arguments
183
182
  "S101", # Using assert is fine in tests
184
183
  "SLF001", # Accessing private members is sometimes necessary in tests
185
- "TID253", # Conditional imports are not banned for tests
186
184
  ]
187
185
  lint.allowed-confusables = [ "ℹ", "–", "σ" ]
188
186
  lint.flake8-tidy-imports.banned-api."pytz".msg = "'zoneinfo' should be preferred to 'pytz' when using Python 3.9 and later, see https://tonkintaylor-sonarqube.azurewebsites.net/coding_rules?open=python%3AS6890&rule_key=python%3AS6890"
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.4.0'
32
- __version_tuple__ = version_tuple = (0, 4, 0)
31
+ __version__ = version = '0.5.0'
32
+ __version_tuple__ = version_tuple = (0, 5, 0)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -13,7 +13,7 @@ from shapely.geometry import Point
13
13
 
14
14
  from rastr.gis.fishnet import create_point_grid, get_point_grid_shape
15
15
  from rastr.meta import RasterMeta
16
- from rastr.raster import RasterModel
16
+ from rastr.raster import Raster
17
17
 
18
18
  if TYPE_CHECKING:
19
19
  from collections.abc import Iterable
@@ -49,9 +49,9 @@ def raster_distance_from_polygon(
49
49
  *,
50
50
  raster_meta: RasterMeta,
51
51
  extent_polygon: Polygon | None = None,
52
- snap_raster: RasterModel | None = None,
52
+ snap_raster: Raster | None = None,
53
53
  show_pbar: bool = False,
54
- ) -> RasterModel:
54
+ ) -> Raster:
55
55
  """Make a raster where each cell's value is its centre's distance to a polygon.
56
56
 
57
57
  The raster should use a projected coordinate system.
@@ -116,7 +116,7 @@ def raster_distance_from_polygon(
116
116
  distances = np.where(mask, np.array([polygon.distance(pt) for pt in _pts]), np.nan)
117
117
  distance_raster = distances.reshape(x.shape)
118
118
 
119
- return RasterModel(arr=distance_raster, raster_meta=raster_meta)
119
+ return Raster(arr=distance_raster, raster_meta=raster_meta)
120
120
 
121
121
 
122
122
  def _pbar(iterable: Iterable[_T], *, desc: str | None = None) -> Iterable[_T]:
@@ -130,11 +130,11 @@ def full_raster(
130
130
  *,
131
131
  bounds: tuple[float, float, float, float],
132
132
  fill_value: float = np.nan,
133
- ) -> RasterModel:
133
+ ) -> Raster:
134
134
  """Create a raster with a specified fill value for all cells."""
135
135
  shape = get_point_grid_shape(bounds=bounds, cell_size=raster_meta.cell_size)
136
136
  arr = np.full(shape, fill_value, dtype=np.float32)
137
- return RasterModel(arr=arr, raster_meta=raster_meta)
137
+ return Raster(arr=arr, raster_meta=raster_meta)
138
138
 
139
139
 
140
140
  def rasterize_gdf(
@@ -142,7 +142,7 @@ def rasterize_gdf(
142
142
  *,
143
143
  raster_meta: RasterMeta,
144
144
  target_cols: list[str],
145
- ) -> list[RasterModel]:
145
+ ) -> list[Raster]:
146
146
  """Rasterize geometries from a GeoDataFrame.
147
147
 
148
148
  Supports polygons, points, linestrings, and other geometry types.
@@ -205,8 +205,8 @@ def rasterize_gdf(
205
205
  dtype=np.float32,
206
206
  )
207
207
 
208
- # Create RasterModel
209
- raster = RasterModel(arr=raster_array, raster_meta=raster_meta)
208
+ # Create Raster
209
+ raster = Raster(arr=raster_array, raster_meta=raster_meta)
210
210
  rasters.append(raster)
211
211
 
212
212
  return rasters
@@ -286,7 +286,7 @@ def raster_from_point_cloud(
286
286
  *,
287
287
  crs: CRS | str,
288
288
  cell_size: float | None = None,
289
- ) -> RasterModel:
289
+ ) -> Raster:
290
290
  """Create a raster from a point cloud via interpolation.
291
291
 
292
292
  Interpolation is only possible within the convex hull of the points. Outside of
@@ -320,8 +320,18 @@ def raster_from_point_cloud(
320
320
  if len(x) != len(y) or len(x) != len(z):
321
321
  msg = "Length of x, y, and z must be equal."
322
322
  raise ValueError(msg)
323
+ xy_finite_mask = np.isfinite(x) & np.isfinite(y)
324
+ if np.any(~xy_finite_mask):
325
+ msg = "Some (x,y) points are NaN-valued or non-finite. These will be ignored."
326
+ warnings.warn(msg, stacklevel=2)
327
+ x = x[xy_finite_mask]
328
+ y = y[xy_finite_mask]
329
+ z = z[xy_finite_mask]
323
330
  if len(x) < 3:
324
- msg = "At least three (x, y, z) points are required to triangulate a surface."
331
+ msg = (
332
+ "At least three valid (x, y, z) points are required to triangulate a "
333
+ "surface."
334
+ )
325
335
  raise ValueError(msg)
326
336
  # Check for duplicate (x, y) points
327
337
  xy_points = np.column_stack((x, y))
@@ -332,8 +342,8 @@ def raster_from_point_cloud(
332
342
  # Heuristic for cell size if not provided
333
343
  if cell_size is None:
334
344
  # Half the 5th percentile of nearest neighbor distances between the (x,y) points
335
- tree = KDTree(np.column_stack((x, y)))
336
- distances, _ = tree.query(np.column_stack((x, y)), k=2)
345
+ tree = KDTree(xy_points)
346
+ distances, _ = tree.query(xy_points, k=2)
337
347
  distances: np.ndarray
338
348
  cell_size = float(np.percentile(distances[distances > 0], 5)) / 2
339
349
 
@@ -378,4 +388,4 @@ def raster_from_point_cloud(
378
388
  crs=crs,
379
389
  transform=transform,
380
390
  )
381
- return RasterModel(arr=arr, raster_meta=raster_meta)
391
+ return Raster(arr=arr, raster_meta=raster_meta)
@@ -9,7 +9,7 @@ import rasterio.merge
9
9
  from pyproj.crs.crs import CRS
10
10
 
11
11
  from rastr.meta import RasterMeta
12
- from rastr.raster import RasterModel
12
+ from rastr.raster import Raster
13
13
 
14
14
  if TYPE_CHECKING:
15
15
  from numpy.typing import NDArray
@@ -17,7 +17,7 @@ if TYPE_CHECKING:
17
17
 
18
18
  def read_raster_inmem(
19
19
  raster_path: Path | str, *, crs: CRS | str | None = None
20
- ) -> RasterModel:
20
+ ) -> Raster:
21
21
  """Read raster data from a file and return an in-memory Raster object."""
22
22
  crs = CRS.from_user_input(crs) if crs is not None else None
23
23
 
@@ -35,13 +35,13 @@ def read_raster_inmem(
35
35
  arr[arr == nodata] = np.nan
36
36
 
37
37
  raster_meta = RasterMeta(cell_size=cell_size, crs=crs, transform=transform)
38
- raster_obj = RasterModel(arr=arr, raster_meta=raster_meta)
38
+ raster_obj = Raster(arr=arr, raster_meta=raster_meta)
39
39
  return raster_obj
40
40
 
41
41
 
42
42
  def read_raster_mosaic_inmem(
43
43
  mosaic_dir: Path | str, *, glob: str = "*.tif", crs: CRS | None = None
44
- ) -> RasterModel:
44
+ ) -> Raster:
45
45
  """Read a raster mosaic from a directory and return an in-memory Raster object.
46
46
 
47
47
  This assumes that all rasters have the same metadata, e.g. coordinate system,
@@ -87,7 +87,7 @@ def read_raster_mosaic_inmem(
87
87
  arr = arr.squeeze().astype(np.float64)
88
88
 
89
89
  raster_meta = RasterMeta(cell_size=cell_size, crs=crs, transform=transform)
90
- raster_obj = RasterModel(arr=arr, raster_meta=raster_meta)
90
+ raster_obj = Raster(arr=arr, raster_meta=raster_meta)
91
91
  return raster_obj
92
92
  finally:
93
93
  for src in sources: