rio-tiler 6.4.1__py3-none-any.whl → 6.4.3__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.
rio_tiler/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  """rio-tiler."""
2
2
 
3
- __version__ = "6.4.1"
3
+ __version__ = "6.4.3"
4
4
 
5
5
  from . import ( # noqa
6
6
  colormap,
rio_tiler/io/rasterio.py CHANGED
@@ -266,7 +266,7 @@ class Reader(BaseReader):
266
266
  "height": self.dataset.height,
267
267
  "overviews": self.dataset.overviews(1),
268
268
  }
269
- if self.dataset.scales[0] and self.dataset.offsets[0]:
269
+ if self.dataset.scales[0] != 1.0 or self.dataset.offsets[0] != 0.0:
270
270
  meta.update(
271
271
  {"scale": self.dataset.scales[0], "offset": self.dataset.offsets[0]}
272
272
  )
rio_tiler/utils.py CHANGED
@@ -33,6 +33,27 @@ def _chunks(my_list: Sequence, chuck_size: int) -> Generator[Sequence, None, Non
33
33
  yield my_list[i : i + chuck_size]
34
34
 
35
35
 
36
+ # Ref: https://stackoverflow.com/posts/73905572
37
+ def _weighted_quantiles(
38
+ values: NDArray[numpy.floating],
39
+ weights: NDArray[numpy.floating],
40
+ quantiles: float = 0.5,
41
+ ) -> float:
42
+ i = numpy.argsort(values)
43
+ c = numpy.cumsum(weights[i])
44
+ return float(values[i[numpy.searchsorted(c, numpy.array(quantiles) * c[-1])]])
45
+
46
+
47
+ # Ref: https://stackoverflow.com/questions/2413522
48
+ def _weighted_stdev(
49
+ values: NDArray[numpy.floating],
50
+ weights: NDArray[numpy.floating],
51
+ ) -> float:
52
+ average = numpy.average(values, weights=weights)
53
+ variance = numpy.average((values - average) ** 2, weights=weights)
54
+ return float(math.sqrt(variance))
55
+
56
+
36
57
  def get_array_statistics(
37
58
  data: numpy.ma.MaskedArray,
38
59
  categorical: bool = False,
@@ -85,25 +106,31 @@ def get_array_statistics(
85
106
  percentiles = percentiles or [2, 98]
86
107
 
87
108
  if len(data.shape) < 3:
88
- data = numpy.expand_dims(data, axis=0)
109
+ data = numpy.ma.expand_dims(data, axis=0)
89
110
 
90
111
  output: List[Dict[Any, Any]] = []
91
112
  percentiles_names = [f"percentile_{int(p)}" for p in percentiles]
92
113
 
114
+ if coverage is not None:
115
+ assert coverage.shape == (
116
+ data.shape[1],
117
+ data.shape[2],
118
+ ), f"Invalid shape ({coverage.shape}) for Coverage, expected {(data.shape[1], data.shape[2])}"
119
+
120
+ else:
121
+ coverage = numpy.ones((data.shape[1], data.shape[2]))
122
+
93
123
  # Avoid non masked nan/inf values
94
124
  numpy.ma.fix_invalid(data, copy=False)
95
125
 
96
126
  for b in range(data.shape[0]):
97
- keys, counts = numpy.unique(data[b].compressed(), return_counts=True)
127
+ data_comp = data[b].compressed()
128
+
129
+ keys, counts = numpy.unique(data_comp, return_counts=True)
98
130
 
99
131
  valid_pixels = float(numpy.ma.count(data[b]))
100
132
  masked_pixels = float(numpy.ma.count_masked(data[b]))
101
133
  valid_percent = round((valid_pixels / data[b].size) * 100, 2)
102
- info_px = {
103
- "valid_pixels": valid_pixels,
104
- "masked_pixels": masked_pixels,
105
- "valid_percent": valid_percent,
106
- }
107
134
 
108
135
  if categorical:
109
136
  out_dict = dict(zip(keys.tolist(), counts.tolist()))
@@ -115,28 +142,26 @@ def get_array_statistics(
115
142
  h_keys,
116
143
  ]
117
144
  else:
118
- h_counts, h_keys = numpy.histogram(data[b].compressed(), **kwargs)
145
+ h_counts, h_keys = numpy.histogram(data_comp, **kwargs)
119
146
  histogram = [h_counts.tolist(), h_keys.tolist()]
120
147
 
121
- if valid_pixels:
122
- percentiles_values = numpy.percentile(
123
- data[b].compressed(), percentiles
124
- ).tolist()
125
- else:
126
- percentiles_values = (numpy.nan,) * len(percentiles_names)
127
-
128
- if coverage is not None:
129
- assert coverage.shape == (
130
- data.shape[1],
131
- data.shape[2],
132
- ), f"Invalid shape ({coverage.shape}) for Coverage, expected {(data.shape[1], data.shape[2])}"
133
-
134
- array = data[b] * coverage
148
+ # Data coverage fractions
149
+ data_cov = data[b] * coverage
150
+ # Coverage Array + data mask
151
+ masked_coverage = numpy.ma.MaskedArray(coverage, mask=data_cov.mask)
135
152
 
153
+ if valid_pixels:
154
+ # TODO: when switching to numpy~=2.0
155
+ # percentiles_values = numpy.percentile(
156
+ # data_comp, percentiles, weights=coverage.flatten()
157
+ # ).tolist()
158
+ percentiles_values = [
159
+ _weighted_quantiles(data_comp, masked_coverage.compressed(), pp / 100.0)
160
+ for pp in percentiles
161
+ ]
136
162
  else:
137
- array = data[b]
163
+ percentiles_values = [numpy.nan] * len(percentiles_names)
138
164
 
139
- count = array.count() if coverage is None else coverage.sum()
140
165
  if valid_pixels:
141
166
  majority = float(keys[counts.tolist().index(counts.max())].tolist())
142
167
  minority = float(keys[counts.tolist().index(counts.min())].tolist())
@@ -144,21 +169,40 @@ def get_array_statistics(
144
169
  majority = numpy.nan
145
170
  minority = numpy.nan
146
171
 
172
+ _count = masked_coverage.sum()
173
+ _sum = data_cov.sum()
174
+
147
175
  output.append(
148
176
  {
177
+ # Minimum value, not taking coverage fractions into account.
149
178
  "min": float(data[b].min()),
179
+ # Maximum value, not taking coverage fractions into account.
150
180
  "max": float(data[b].max()),
151
- "mean": float(array.mean()),
152
- "count": float(count),
153
- "sum": float(array.sum()),
154
- "std": float(array.std()),
155
- "median": float(numpy.ma.median(array)),
181
+ # Mean value, weighted by the percent of each cell that is covered.
182
+ "mean": float(_sum / _count),
183
+ # Sum of all non-masked cell coverage fractions.
184
+ "count": float(_count),
185
+ # Sum of values, weighted by their coverage fractions.
186
+ "sum": float(_sum),
187
+ # Population standard deviation of cell values, taking into account coverage fraction.
188
+ "std": _weighted_stdev(data_comp, masked_coverage.compressed()),
189
+ # Median value of cells, weighted by the percent of each cell that is covered.
190
+ "median": _weighted_quantiles(data_comp, masked_coverage.compressed()),
191
+ # The value occupying the greatest number of cells.
156
192
  "majority": majority,
193
+ # The value occupying the least number of cells.
157
194
  "minority": minority,
195
+ # Unique values.
158
196
  "unique": float(counts.size),
197
+ # quantiles
159
198
  **dict(zip(percentiles_names, percentiles_values)),
160
199
  "histogram": histogram,
161
- **info_px,
200
+ # Number of non-masked cells, not taking coverage fractions into account.
201
+ "valid_pixels": valid_pixels,
202
+ # Number of masked cells, not taking coverage fractions into account.
203
+ "masked_pixels": masked_pixels,
204
+ # Percent of valid cells
205
+ "valid_percent": valid_percent,
162
206
  }
163
207
  )
164
208
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: rio-tiler
3
- Version: 6.4.1
3
+ Version: 6.4.3
4
4
  Summary: User friendly Rasterio plugin to read raster datasets.
5
5
  Project-URL: Homepage, https://cogeotiff.github.io/rio-tiler/
6
6
  Project-URL: Documentation, https://cogeotiff.github.io/rio-tiler/
@@ -1,4 +1,4 @@
1
- rio_tiler/__init__.py,sha256=HaxwIqy3HP3MuUeSf0jq4_QjmwhQTXmgjQLxxd9VXVE,192
1
+ rio_tiler/__init__.py,sha256=rx1oh4GVoIrzSnsvVZYRSRTIPaB0IUT6P9mDoAbWRW8,192
2
2
  rio_tiler/colormap.py,sha256=hspVEbnvbRPGPEykWxV_PoqQpltbfSR7_g35mzd1d6s,9755
3
3
  rio_tiler/constants.py,sha256=55i-7JZDupTXZdLgxL03KsgM4lAzuGuIVP1zZKktzp0,426
4
4
  rio_tiler/errors.py,sha256=ag-wNr13JaQ4YcQzWWPFzjegeGdzJIMMrOrbb3coQ40,1733
@@ -10,7 +10,7 @@ rio_tiler/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  rio_tiler/reader.py,sha256=W08HPOfE48BrbsDZgHKBPhJrrZsOLz-r0wq9r27VnAs,21681
11
11
  rio_tiler/tasks.py,sha256=O4laTCr66XHJ-4REWg3SAaA1pre0OMG0NklbKZ2g9Fc,3181
12
12
  rio_tiler/types.py,sha256=508_E5R-nKrAo8TWB-6h7pF6SYwNM8kJPiHjQw-k-tA,1443
13
- rio_tiler/utils.py,sha256=zhfrhjAdaa2eJYVQwjzuy68m6Uj0bIYSaOVWK-dc4ek,24426
13
+ rio_tiler/utils.py,sha256=WHAjsO1C-oW-cMb8Q50D6fCDvLji-eT2oxN9SUjzZxQ,26514
14
14
  rio_tiler/cmap_data/__init__.py,sha256=8FtVmfpTjXlvhxQ5QesN0UC1m_B3MuF3LbGbhMC5Rw4,1039
15
15
  rio_tiler/cmap_data/accent.npy,sha256=Qde1ldOoXghe4L05v1QbVvnMA1ldwNjKWPf5xCBbmI4,1152
16
16
  rio_tiler/cmap_data/accent_r.npy,sha256=ba-GWSMSPRAcm9CGzlXJeNG4ABbBHDCV602hAWV2idc,1152
@@ -225,7 +225,7 @@ rio_tiler/cmap_data/ylorrd.npy,sha256=9ImXljw40oe60w8uV4EMDPY4aFFVkGbyCBi6SlTX83
225
225
  rio_tiler/cmap_data/ylorrd_r.npy,sha256=K5uiHNHbLxV5SizyT09cSVAxldE-BW5GpOXxUp7UsTE,1152
226
226
  rio_tiler/io/__init__.py,sha256=_L4iILm6vSiJ14GEDDOvkuUHRtbWC9oqx6Bu8PxHhvA,270
227
227
  rio_tiler/io/base.py,sha256=r1p9yEnQc3dI9Ey-sg8q0jfD4K1l0T70kKVWUceoGG4,45260
228
- rio_tiler/io/rasterio.py,sha256=FzAMkP2xUNOvHfAcmOwilUFr6j3ao08l1Xm7ZpKX3kk,32171
228
+ rio_tiler/io/rasterio.py,sha256=-JRm-KLUGXB-NQxYCvZPUXH2SvTfZ-lFietzNcvW4pM,32184
229
229
  rio_tiler/io/stac.py,sha256=soHDrWBKp7bgepwVe2dDBgVPp3iEAbTsx7BBHhtLDiE,10182
230
230
  rio_tiler/io/xarray.py,sha256=d8JO45Wv3Jvk0aSbUSUbfOEUzTTefdN8JkrUmDwZFo8,17785
231
231
  rio_tiler/mosaic/__init__.py,sha256=Yj6CKpnFl8PJhLSp-a55wo33hKZ8-6OOBJtWA1HZVy8,118
@@ -233,8 +233,8 @@ rio_tiler/mosaic/reader.py,sha256=_YBwTJwHvXOzKwpNpOmmh0F4yicyxgWo9vHyof3w_Do,96
233
233
  rio_tiler/mosaic/methods/__init__.py,sha256=tgkXM9skaTLXIm5QFoheOEznQXM97KGflcAWHfkrt1g,612
234
234
  rio_tiler/mosaic/methods/base.py,sha256=9YZJWVRwH5Fk9KO9q5CW52Q8Mf60tAJ21oM4ixEDXBo,1424
235
235
  rio_tiler/mosaic/methods/defaults.py,sha256=z34lna2wGXnAPwculjk_6hDrloqS8wzer68FFoIo7pg,6744
236
- rio_tiler-6.4.1.dist-info/METADATA,sha256=sYF6Ga3VhAdIM8-XbJGP986aVknaJggIRJ5sYjhRIWU,11869
237
- rio_tiler-6.4.1.dist-info/WHEEL,sha256=TJPnKdtrSue7xZ_AVGkp9YXcvDrobsjBds1du3Nx6dc,87
238
- rio_tiler-6.4.1.dist-info/licenses/AUTHORS.txt,sha256=FCVd4Tjg-8syl0ZugCunpXER8X2-XonW2ZfllyTnRvE,158
239
- rio_tiler-6.4.1.dist-info/licenses/LICENSE,sha256=vq8Tt4KoYQT9JxAjQ4yXMmmhFYRTsBRgrOj-ao-bC5o,1517
240
- rio_tiler-6.4.1.dist-info/RECORD,,
236
+ rio_tiler-6.4.3.dist-info/METADATA,sha256=fjeMD-0DJ4uGXv0wKufK6f2C9TFMVbEJzoVDivgpwbU,11869
237
+ rio_tiler-6.4.3.dist-info/WHEEL,sha256=bq9SyP5NxIRA9EpQgMCd-9RmPHWvbH-4lTDGwxgIR64,87
238
+ rio_tiler-6.4.3.dist-info/licenses/AUTHORS.txt,sha256=FCVd4Tjg-8syl0ZugCunpXER8X2-XonW2ZfllyTnRvE,158
239
+ rio_tiler-6.4.3.dist-info/licenses/LICENSE,sha256=vq8Tt4KoYQT9JxAjQ4yXMmmhFYRTsBRgrOj-ao-bC5o,1517
240
+ rio_tiler-6.4.3.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.21.1
2
+ Generator: hatchling 1.22.3
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any