rastr 0.3.0__py3-none-any.whl → 0.4.0__py3-none-any.whl

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.
rastr/_version.py CHANGED
@@ -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.3.0'
32
- __version_tuple__ = version_tuple = (0, 3, 0)
31
+ __version__ = version = '0.4.0'
32
+ __version_tuple__ = version_tuple = (0, 4, 0)
33
33
 
34
34
  __commit_id__ = commit_id = None
rastr/raster.py CHANGED
@@ -6,7 +6,7 @@ import importlib.util
6
6
  import warnings
7
7
  from contextlib import contextmanager
8
8
  from pathlib import Path
9
- from typing import TYPE_CHECKING, Any, Literal
9
+ from typing import TYPE_CHECKING, Any, Literal, overload
10
10
 
11
11
  import numpy as np
12
12
  import numpy.ma
@@ -65,6 +65,21 @@ class RasterModel(BaseModel):
65
65
  def meta(self, value: RasterMeta) -> None:
66
66
  self.raster_meta = value
67
67
 
68
+ @property
69
+ def shape(self) -> tuple[int, ...]:
70
+ """Shape of the raster array."""
71
+ return self.arr.shape
72
+
73
+ @property
74
+ def crs(self) -> CRS:
75
+ """Convenience property to access the CRS via meta."""
76
+ return self.meta.crs
77
+
78
+ @crs.setter
79
+ def crs(self, value: CRS) -> None:
80
+ """Set the CRS via meta."""
81
+ self.meta.crs = value
82
+
68
83
  def __init__(
69
84
  self,
70
85
  *,
@@ -193,12 +208,12 @@ class RasterModel(BaseModel):
193
208
  @property
194
209
  def cell_x_coords(self) -> NDArray[np.float64]:
195
210
  """Get the x coordinates of the cell centres in the raster."""
196
- return self.raster_meta.get_cell_x_coords(self.arr.shape[0])
211
+ return self.raster_meta.get_cell_x_coords(self.arr.shape[1])
197
212
 
198
213
  @property
199
214
  def cell_y_coords(self) -> NDArray[np.float64]:
200
215
  """Get the y coordinates of the cell centres in the raster."""
201
- return self.raster_meta.get_cell_y_coords(self.arr.shape[1])
216
+ return self.raster_meta.get_cell_y_coords(self.arr.shape[0])
202
217
 
203
218
  @contextmanager
204
219
  def to_rasterio_dataset(
@@ -573,6 +588,43 @@ class RasterModel(BaseModel):
573
588
  raster_meta = RasterMeta.example()
574
589
  return cls(arr=arr, raster_meta=raster_meta)
575
590
 
591
+ @overload
592
+ def apply(
593
+ self,
594
+ func: Callable[[np.ndarray], np.ndarray],
595
+ *,
596
+ raw: Literal[True],
597
+ ) -> Self: ...
598
+ @overload
599
+ def apply(
600
+ self,
601
+ func: Callable[[float], float] | Callable[[np.ndarray], np.ndarray],
602
+ *,
603
+ raw: Literal[False] = False,
604
+ ) -> Self: ...
605
+ def apply(self, func, *, raw=False) -> Self:
606
+ """Apply a function element-wise to the raster array.
607
+
608
+ Creates a new raster instance with the same metadata (CRS, transform, etc.)
609
+ but with the data array transformed by the provided function. The original
610
+ raster is not modified.
611
+
612
+ Args:
613
+ func: The function to apply to the raster array. If `raw` is True, this
614
+ function should accept and return a NumPy array. If `raw` is False,
615
+ this function should accept and return a single float value.
616
+ raw: If True, the function is applied directly to the entire array at
617
+ once. If False, the function is applied element-wise to each cell
618
+ in the array using `np.vectorize()`. Default is False.
619
+ """
620
+ new_raster = self.model_copy()
621
+ if raw:
622
+ new_arr = func(self.arr)
623
+ else:
624
+ new_arr = np.vectorize(func)(self.arr)
625
+ new_raster.arr = np.asarray(new_arr)
626
+ return new_raster
627
+
576
628
  def fillna(self, value: float) -> Self:
577
629
  """Fill NaN values in the raster with a specified value.
578
630
 
@@ -599,12 +651,14 @@ class RasterModel(BaseModel):
599
651
  return coords[:, :, 0], coords[:, :, 1]
600
652
 
601
653
  def contour(
602
- self, *, levels: list[float] | NDArray, smoothing: bool = True
654
+ self, levels: list[float] | NDArray, *, smoothing: bool = True
603
655
  ) -> gpd.GeoDataFrame:
604
656
  """Create contour lines from the raster data, optionally with smoothing.
605
657
 
606
- The contour lines are returned as a GeoDataFrame with the contours as linestring
607
- geometries and the contour levels as attributes in a column named 'level'.
658
+ The contour lines are returned as a GeoDataFrame with the contours dissolved
659
+ by level, resulting in one row per contour level. Each row contains a
660
+ (Multi)LineString geometry representing all contour lines for that level,
661
+ and the contour level value in a column named 'level'.
608
662
 
609
663
  Consider calling `blur()` before this method to smooth the raster data before
610
664
  contouring, to denoise the contours.
@@ -627,7 +681,7 @@ class RasterModel(BaseModel):
627
681
  level=level,
628
682
  )
629
683
 
630
- # Constructg shapely LineString objects
684
+ # Construct shapely LineString objects
631
685
  # Convert to CRS from array index coordinates to raster CRS
632
686
  geoms = [
633
687
  LineString(
@@ -656,7 +710,8 @@ class RasterModel(BaseModel):
656
710
  crs=self.raster_meta.crs,
657
711
  )
658
712
 
659
- return contour_gdf
713
+ # Dissolve contours by level to merge all contour lines of the same level
714
+ return contour_gdf.dissolve(by="level", as_index=False)
660
715
 
661
716
  def blur(self, sigma: float) -> Self:
662
717
  """Apply a Gaussian blur to the raster data.
@@ -701,7 +756,7 @@ class RasterModel(BaseModel):
701
756
  bounds: tuple[float, float, float, float],
702
757
  strategy: Literal["underflow", "overflow"] = "underflow",
703
758
  ) -> Self:
704
- """Crop the raster to the specified bounds.
759
+ """Crop the raster to the specified bounds as (minx, miny, maxx, maxy).
705
760
 
706
761
  Args:
707
762
  bounds: A tuple of (minx, miny, maxx, maxy) defining the bounds to crop to.
@@ -746,7 +801,7 @@ class RasterModel(BaseModel):
746
801
  raise NotImplementedError(msg)
747
802
 
748
803
  # Crop the array
749
- cropped_arr = arr[np.ix_(x_idx, y_idx)]
804
+ cropped_arr = arr[np.ix_(y_idx, x_idx)]
750
805
 
751
806
  # Check the shape of the cropped array
752
807
  if cropped_arr.size == 0:
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rastr
3
- Version: 0.3.0
3
+ Version: 0.4.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/46f802e7abd275eff61c73c5edc147d92966c886.zip
8
+ Project-URL: Source Archive, https://github.com/tonkintaylor/rastr/archive/336916af169603534dd0728c10401667f263d98a.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
@@ -1,15 +1,15 @@
1
1
  rastr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- rastr/_version.py,sha256=5zTqm8rgXsWYBpB2M3Zw_K1D-aV8wP7NsBLrmMKkrAQ,704
2
+ rastr/_version.py,sha256=2_0GUP7yBCXRus-qiJKxQD62z172WSs1sQ6DVpPsbmM,704
3
3
  rastr/create.py,sha256=6aHpRFRXmpXzuzTt-SxY_BfVc7dXKCBLCArb7DjUrsM,13494
4
4
  rastr/io.py,sha256=RgkiV_emOPjTFeI2a1aCBtfWwrSLH0XmP8rx9tu6PAI,2952
5
5
  rastr/meta.py,sha256=5iDvGkYe8iMMkPV6gSL04jNcLRhuRNFqe9AppUpp55E,2928
6
- rastr/raster.py,sha256=iHN8L91HW-cpDexZYgDnLaOw-N6KktQpXIusvUEiL0o,29931
6
+ rastr/raster.py,sha256=I9CQB2NYUOFvvpdzNsQcDBdgLXDCjB7ONFxDAq_6_SU,31995
7
7
  rastr/arr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  rastr/arr/fill.py,sha256=80ucb36el9s042fDSwK1SZJhp_GNJNMM0fpQTWmJvgE,1001
9
9
  rastr/gis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  rastr/gis/fishnet.py,sha256=Ic-0HV61ST8OxwhyoMyV_ybihs2xuhgAY-3n4CknAt8,2670
11
11
  rastr/gis/smooth.py,sha256=3HQDQHQM5_LeNk21R8Eb8VpF727JcXq21HO9JMvcpW4,4810
12
- rastr-0.3.0.dist-info/METADATA,sha256=pr4zdjI5FPlVynm2W09ErYddJ0Nmvx9wICWzBH2IpNI,4953
13
- rastr-0.3.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
14
- rastr-0.3.0.dist-info/licenses/LICENSE,sha256=7qUsx93G2ATTRLZiSYuQofwAX_uWvrqnAiMK8PzxvNc,1080
15
- rastr-0.3.0.dist-info/RECORD,,
12
+ rastr-0.4.0.dist-info/METADATA,sha256=GjZF16Tmxjz3WUbEFhAB1jW19AecpNkJpk__YNSamQQ,4953
13
+ rastr-0.4.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
14
+ rastr-0.4.0.dist-info/licenses/LICENSE,sha256=7qUsx93G2ATTRLZiSYuQofwAX_uWvrqnAiMK8PzxvNc,1080
15
+ rastr-0.4.0.dist-info/RECORD,,
File without changes