uxarray 2026.9.0__tar.gz → 2026.9.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.
- {uxarray-2026.9.0 → uxarray-2026.9.1}/PKG-INFO +19 -16
- {uxarray-2026.9.0 → uxarray-2026.9.1}/pyproject.toml +31 -16
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/core/dataarray.py +55 -41
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/core/dataset.py +65 -36
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/core/gradient.py +1 -1
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/core/utils.py +20 -5
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/cross_sections/sample.py +3 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/errors.py +7 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/grid/angles.py +1 -1
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/grid/arcs.py +5 -3
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/grid/area.py +6 -2
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/grid/bounds.py +6 -5
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/grid/connectivity.py +5 -5
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/grid/coordinates.py +7 -5
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/grid/dual.py +1 -1
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/grid/geometry.py +42 -9
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/grid/grid.py +108 -49
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/grid/integrate.py +8 -4
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/grid/neighbors.py +61 -67
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/grid/point_in_face.py +1 -1
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/grid/slice.py +6 -2
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/grid/utils.py +5 -2
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/io/_esmf.py +10 -1
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/io/_geopandas.py +2 -1
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/io/_healpix.py +3 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/io/_scrip.py +323 -28
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/io/_ugrid.py +61 -2
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/plot/accessor.py +10 -2
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/plot/matplotlib.py +2 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/plot/utils.py +6 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/remap/bilinear.py +1 -1
- uxarray-2026.9.1/uxarray/utils/coords.py +212 -0
- uxarray-2026.9.1/uxarray/utils/imports.py +366 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray.egg-info/PKG-INFO +19 -16
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray.egg-info/SOURCES.txt +1 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray.egg-info/requires.txt +21 -15
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray.egg-info/scm_file_list.json +10 -0
- uxarray-2026.9.1/uxarray.egg-info/scm_version.json +8 -0
- uxarray-2026.9.0/uxarray/utils/coords.py +0 -86
- uxarray-2026.9.0/uxarray.egg-info/scm_version.json +0 -8
- {uxarray-2026.9.0 → uxarray-2026.9.1}/.codecov.yml +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/.git_archival.txt +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/.gitattributes +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/CITATION.cff +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/CODE_OF_CONDUCT.md +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/CONTRIBUTING.md +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/INSTALLATION.md +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/LICENSE +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/MANIFEST.in +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/README.md +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/build.sh +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/setup.cfg +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/setup.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/__init__.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/constants.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/conventions/__init__.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/conventions/descriptors.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/conventions/ugrid.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/core/__init__.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/core/accessors.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/core/aggregation.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/core/api.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/core/zonal.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/cross_sections/__init__.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/cross_sections/dataarray_accessor.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/cross_sections/grid_accessor.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/formatting_html.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/grid/__init__.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/grid/intersections.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/grid/validation.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/io/__init__.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/io/_delaunay.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/io/_exodus.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/io/_fesom2.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/io/_geos.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/io/_icon.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/io/_mpas.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/io/_structured.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/io/_topology.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/io/_vertices.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/io/_voronoi.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/io/utils.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/plot/__init__.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/plot/constants.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/remap/__init__.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/remap/accessor.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/remap/apply_weights.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/remap/inverse_distance_weighted.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/remap/nearest_neighbor.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/remap/spatial_coords_remap.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/remap/structured.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/remap/utils.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/remap/weights.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/remap/yac.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/subset/__init__.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/subset/dataarray_accessor.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/subset/grid_accessor.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/tutorial/__init__.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/tutorial/registry.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/utils/__init__.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/utils/computing.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/utils/numba_math.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray/utils/warnings.py +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray.egg-info/dependency_links.txt +0 -0
- {uxarray-2026.9.0 → uxarray-2026.9.1}/uxarray.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: uxarray
|
|
3
|
-
Version: 2026.9.
|
|
3
|
+
Version: 2026.9.1
|
|
4
4
|
Summary: Xarray extension for unstructured climate and global weather data analysis and visualization.
|
|
5
5
|
License: Apache License
|
|
6
6
|
Version 2.0, January 2004
|
|
@@ -221,37 +221,40 @@ Requires-Python: >=3.11
|
|
|
221
221
|
Description-Content-Type: text/markdown
|
|
222
222
|
License-File: LICENSE
|
|
223
223
|
Requires-Dist: antimeridian
|
|
224
|
-
Requires-Dist: cartopy
|
|
225
224
|
Requires-Dist: dask[dataframe]
|
|
226
|
-
Requires-Dist: datashader
|
|
227
|
-
Requires-Dist: geoviews
|
|
228
|
-
Requires-Dist: holoviews
|
|
229
|
-
Requires-Dist: matplotlib<3.11
|
|
230
|
-
Requires-Dist: matplotlib-inline
|
|
231
225
|
Requires-Dist: netcdf4
|
|
232
226
|
Requires-Dist: numba>=0.63
|
|
233
227
|
Requires-Dist: numpy
|
|
234
228
|
Requires-Dist: pandas
|
|
235
|
-
Requires-Dist: pyarrow
|
|
236
|
-
Requires-Dist: requests
|
|
237
229
|
Requires-Dist: scikit-learn
|
|
238
230
|
Requires-Dist: scipy
|
|
239
231
|
Requires-Dist: shapely
|
|
240
|
-
Requires-Dist: spatialpandas
|
|
241
|
-
Requires-Dist: geopandas>=1.0
|
|
242
232
|
Requires-Dist: xarray
|
|
243
|
-
Requires-Dist: hvplot
|
|
244
|
-
Requires-Dist: healpix
|
|
245
233
|
Requires-Dist: polars
|
|
246
|
-
|
|
234
|
+
Provides-Extra: all
|
|
235
|
+
Requires-Dist: uxarray[dev,geo,viz]; extra == "all"
|
|
247
236
|
Provides-Extra: complete
|
|
248
|
-
Requires-Dist: uxarray[dev]; extra == "complete"
|
|
237
|
+
Requires-Dist: uxarray[dev,geo,viz]; extra == "complete"
|
|
249
238
|
Provides-Extra: dev
|
|
239
|
+
Requires-Dist: asv; extra == "dev"
|
|
240
|
+
Requires-Dist: pooch; extra == "dev"
|
|
250
241
|
Requires-Dist: pre_commit; extra == "dev"
|
|
251
242
|
Requires-Dist: pytest; extra == "dev"
|
|
252
243
|
Requires-Dist: pytest-cov; extra == "dev"
|
|
253
244
|
Requires-Dist: ruff; extra == "dev"
|
|
254
|
-
|
|
245
|
+
Provides-Extra: geo
|
|
246
|
+
Requires-Dist: cartopy; extra == "geo"
|
|
247
|
+
Requires-Dist: geopandas>=1.0; extra == "geo"
|
|
248
|
+
Requires-Dist: healpix; extra == "geo"
|
|
249
|
+
Requires-Dist: pyproj; extra == "geo"
|
|
250
|
+
Requires-Dist: spatialpandas; extra == "geo"
|
|
251
|
+
Provides-Extra: viz
|
|
252
|
+
Requires-Dist: cartopy<0.26; extra == "viz"
|
|
253
|
+
Requires-Dist: datashader; extra == "viz"
|
|
254
|
+
Requires-Dist: matplotlib<3.11; extra == "viz"
|
|
255
|
+
Requires-Dist: geoviews; extra == "viz"
|
|
256
|
+
Requires-Dist: holoviews; extra == "viz"
|
|
257
|
+
Requires-Dist: hvplot; extra == "viz"
|
|
255
258
|
Dynamic: license-file
|
|
256
259
|
|
|
257
260
|
|
|
@@ -22,41 +22,53 @@ requires-python = ">=3.11"
|
|
|
22
22
|
# minimal dependencies start
|
|
23
23
|
dependencies = [
|
|
24
24
|
"antimeridian",
|
|
25
|
-
"cartopy",
|
|
26
25
|
"dask[dataframe]",
|
|
27
|
-
"datashader",
|
|
28
|
-
"geoviews",
|
|
29
|
-
"holoviews",
|
|
30
|
-
"matplotlib<3.11", # matplotlib 3.11.0 breaks some plots but <3.11 is fine; see issue #1542.
|
|
31
|
-
"matplotlib-inline",
|
|
32
26
|
"netcdf4",
|
|
33
27
|
"numba>=0.63", # 0.63 is the first release supporting Python 3.14 (3.10 <= py < 3.15). See #1561.
|
|
34
28
|
"numpy",
|
|
35
29
|
"pandas",
|
|
36
|
-
"pyarrow",
|
|
37
|
-
"requests",
|
|
38
30
|
"scikit-learn",
|
|
39
31
|
"scipy",
|
|
40
32
|
"shapely",
|
|
41
|
-
"spatialpandas",
|
|
42
|
-
"geopandas>=1.0", # 1.0 is the first release requiring pyogrio, the file-IO backend read_file needs. See #1693.
|
|
43
33
|
"xarray",
|
|
44
|
-
"hvplot",
|
|
45
|
-
"healpix",
|
|
46
34
|
"polars",
|
|
47
|
-
"pyproj"
|
|
48
35
|
]
|
|
49
36
|
# minimal dependencies end
|
|
50
37
|
|
|
51
38
|
[project.optional-dependencies]
|
|
52
|
-
|
|
53
|
-
|
|
39
|
+
all = ["uxarray[dev,geo,viz]"]
|
|
40
|
+
complete = ["uxarray[dev,geo,viz]"] # alias to "all"
|
|
41
|
+
dev = [
|
|
42
|
+
'asv',
|
|
43
|
+
'pooch',
|
|
44
|
+
'pre_commit',
|
|
45
|
+
'pytest',
|
|
46
|
+
'pytest-cov',
|
|
47
|
+
'ruff',
|
|
48
|
+
]
|
|
49
|
+
geo = [
|
|
50
|
+
"cartopy", # in both geo and viz because it is needed by to_geodataframe() and by plotting routines.
|
|
51
|
+
"geopandas>=1.0", # 1.0 is the first release requiring pyogrio, the file-IO backend read_file needs. See #1693.
|
|
52
|
+
"healpix",
|
|
53
|
+
"pyproj",
|
|
54
|
+
"spatialpandas",
|
|
55
|
+
]
|
|
56
|
+
viz = [
|
|
57
|
+
"cartopy<0.26", # cartopy 0.26.0 breaks some geoviews plots; see issue #1780.
|
|
58
|
+
# (cartopy pin intentionally here but not in "geo" extras because geoviews is only in "viz".)
|
|
59
|
+
"datashader",
|
|
60
|
+
"matplotlib<3.11", # matplotlib 3.11.0 breaks some plots but <3.11 is fine; see issue #1542.
|
|
61
|
+
"geoviews", # no version pin; newer should support any cartopy; see holoviz/geoviews#884.
|
|
62
|
+
"holoviews",
|
|
63
|
+
"hvplot",
|
|
64
|
+
]
|
|
54
65
|
|
|
55
66
|
[project.urls]
|
|
56
67
|
Documentation = "https://uxarray.readthedocs.io/"
|
|
57
68
|
Source = "https://github.com/UXARRAY/uxarray"
|
|
58
69
|
Tracker = "https://github.com/UXARRAY/uxarray/issues"
|
|
59
|
-
|
|
70
|
+
# please keep [project.urls] immediately after [project.optional-dependencies],
|
|
71
|
+
# or, if rearranging sections, make sure to edit installation.rst accordingly.
|
|
60
72
|
|
|
61
73
|
[build-system]
|
|
62
74
|
build-backend = "setuptools.build_meta"
|
|
@@ -87,3 +99,6 @@ known-first-party = ["uxarray"]
|
|
|
87
99
|
|
|
88
100
|
[tool.ruff.format]
|
|
89
101
|
docstring-code-format = true
|
|
102
|
+
|
|
103
|
+
[tool.pytest.ini_options]
|
|
104
|
+
testpaths = ["test"] # (intentionally excludes test_optional_deps)
|
|
@@ -11,7 +11,6 @@ from xarray.core import dtypes
|
|
|
11
11
|
from xarray.core.options import OPTIONS
|
|
12
12
|
from xarray.core.utils import UncachedAccessor
|
|
13
13
|
|
|
14
|
-
import uxarray
|
|
15
14
|
from uxarray.constants import GRID_DIMS
|
|
16
15
|
from uxarray.core.aggregation import _uxda_grid_aggregate
|
|
17
16
|
from uxarray.core.gradient import (
|
|
@@ -45,7 +44,13 @@ from uxarray.io._healpix import get_zoom_from_cells
|
|
|
45
44
|
from uxarray.plot.accessor import UxDataArrayPlotAccessor
|
|
46
45
|
from uxarray.remap.accessor import RemapAccessor
|
|
47
46
|
from uxarray.subset import DataArraySubsetAccessor
|
|
48
|
-
from uxarray.utils.coords import
|
|
47
|
+
from uxarray.utils.coords import (
|
|
48
|
+
_assert_grid_dim_coord_consistent_if_in_both,
|
|
49
|
+
_assign_grid_dim_indexer_coords_if_appropriate,
|
|
50
|
+
_crash_if_1d_xarray_indexer_dim_in_uxarray_obj,
|
|
51
|
+
_preserve_valid_coords,
|
|
52
|
+
)
|
|
53
|
+
from uxarray.utils.imports import _raise_hint_if_optional_deps_missing
|
|
49
54
|
|
|
50
55
|
if TYPE_CHECKING:
|
|
51
56
|
import cartopy.crs as ccrs
|
|
@@ -183,26 +188,14 @@ class UxDataArray(xr.DataArray):
|
|
|
183
188
|
|
|
184
189
|
@property
|
|
185
190
|
def data_mapping(self):
|
|
186
|
-
"""Returns which
|
|
187
|
-
if self._face_centered():
|
|
188
|
-
return "faces"
|
|
189
|
-
elif self._edge_centered():
|
|
190
|
-
return "edges"
|
|
191
|
-
elif self._node_centered():
|
|
192
|
-
return "nodes"
|
|
193
|
-
else:
|
|
194
|
-
return None
|
|
195
|
-
|
|
196
|
-
@property
|
|
197
|
-
def data_location(self):
|
|
198
|
-
"""Returns where on the grid the data variable is stored.
|
|
191
|
+
"""Returns which grid element a data variable is mapped to.
|
|
199
192
|
|
|
200
|
-
The
|
|
201
|
-
variable
|
|
193
|
+
The mapping is inferred from the grid dimension present in the data
|
|
194
|
+
variable:
|
|
202
195
|
|
|
203
|
-
- ``"
|
|
204
|
-
- ``"
|
|
205
|
-
- ``"
|
|
196
|
+
- ``"faces"`` if the data contains the ``n_face`` dimension
|
|
197
|
+
- ``"edges"`` if the data contains the ``n_edge`` dimension
|
|
198
|
+
- ``"nodes"`` if the data contains the ``n_node`` dimension
|
|
206
199
|
- ``None`` if the data is not mapped to the grid
|
|
207
200
|
|
|
208
201
|
Notes
|
|
@@ -215,15 +208,14 @@ class UxDataArray(xr.DataArray):
|
|
|
215
208
|
Returns
|
|
216
209
|
-------
|
|
217
210
|
str or None
|
|
218
|
-
One of ``"
|
|
219
|
-
``"edge_centered"``, or ``None``.
|
|
211
|
+
One of ``"faces"``, ``"edges"``, ``"nodes"``, or ``None``.
|
|
220
212
|
"""
|
|
221
213
|
if self._face_centered():
|
|
222
|
-
return "
|
|
223
|
-
elif self._node_centered():
|
|
224
|
-
return "node_centered"
|
|
214
|
+
return "faces"
|
|
225
215
|
elif self._edge_centered():
|
|
226
|
-
return "
|
|
216
|
+
return "edges"
|
|
217
|
+
elif self._node_centered():
|
|
218
|
+
return "nodes"
|
|
227
219
|
else:
|
|
228
220
|
return None
|
|
229
221
|
|
|
@@ -320,7 +312,7 @@ class UxDataArray(xr.DataArray):
|
|
|
320
312
|
|
|
321
313
|
else:
|
|
322
314
|
raise DataCenteringError(
|
|
323
|
-
f"to_geodataframe() expects
|
|
315
|
+
f"to_geodataframe() expects data mapped to faces; got data_mapping={self.data_mapping!r} "
|
|
324
316
|
f"(with sizes={dict(**self.sizes)}). Consider running "
|
|
325
317
|
"``UxDataArray.topological_mean(destination='face')`` to aggregate the data onto faces."
|
|
326
318
|
)
|
|
@@ -480,6 +472,7 @@ class UxDataArray(xr.DataArray):
|
|
|
480
472
|
>>> ax.imshow(raster, origin="lower", extent=ax.get_xlim() + ax.get_ylim())
|
|
481
473
|
|
|
482
474
|
"""
|
|
475
|
+
_raise_hint_if_optional_deps_missing("cartopy")
|
|
483
476
|
from cartopy.mpl.geoaxes import GeoAxes
|
|
484
477
|
|
|
485
478
|
from uxarray.constants import INT_DTYPE
|
|
@@ -524,6 +517,7 @@ class UxDataArray(xr.DataArray):
|
|
|
524
517
|
|
|
525
518
|
if _is_default_extent():
|
|
526
519
|
try:
|
|
520
|
+
_raise_hint_if_optional_deps_missing("cartopy")
|
|
527
521
|
import cartopy.crs as ccrs
|
|
528
522
|
|
|
529
523
|
lon_min = float(self.uxgrid.node_lon.min(skipna=True).values)
|
|
@@ -596,8 +590,10 @@ class UxDataArray(xr.DataArray):
|
|
|
596
590
|
-------
|
|
597
591
|
uxds: UxDataSet
|
|
598
592
|
"""
|
|
593
|
+
from uxarray.core.dataset import UxDataset
|
|
594
|
+
|
|
599
595
|
xrds = super().to_dataset(dim=dim, name=name, promote_attrs=promote_attrs)
|
|
600
|
-
uxds =
|
|
596
|
+
uxds = UxDataset(xrds, uxgrid=self._uxgrid)
|
|
601
597
|
|
|
602
598
|
return uxds
|
|
603
599
|
|
|
@@ -645,8 +641,8 @@ class UxDataArray(xr.DataArray):
|
|
|
645
641
|
|
|
646
642
|
elif not self._face_centered():
|
|
647
643
|
raise DataCenteringError(
|
|
648
|
-
"Integration of
|
|
649
|
-
f"(Got {self.
|
|
644
|
+
"Integration of data not mapped to faces is not yet supported. "
|
|
645
|
+
f"(Got data_mapping={self.data_mapping!r} with sizes={dict(**self.sizes)})"
|
|
650
646
|
)
|
|
651
647
|
|
|
652
648
|
else:
|
|
@@ -1796,7 +1792,7 @@ class UxDataArray(xr.DataArray):
|
|
|
1796
1792
|
# Spherical metric term, the companion of the one in curl(). Omitting
|
|
1797
1793
|
# it is only valid on a plane.
|
|
1798
1794
|
tan_lat = np.tan(np.deg2rad(self.uxgrid.face_lat.values))
|
|
1799
|
-
metric = other.
|
|
1795
|
+
metric = other.data * tan_lat
|
|
1800
1796
|
if scale_by_radius and "sphere_radius" in self.uxgrid._ds.attrs:
|
|
1801
1797
|
metric = metric / self.uxgrid._ds.attrs["sphere_radius"]
|
|
1802
1798
|
divergence = divergence - metric
|
|
@@ -2006,7 +2002,10 @@ class UxDataArray(xr.DataArray):
|
|
|
2006
2002
|
using n_edge=7 selects just the two faces touching edge 7. For data on 'n_face',
|
|
2007
2003
|
the result would have 'n_face' with just those two faces. For data on 'n_edge',
|
|
2008
2004
|
the result would have 'n_edge' with all edges located on either of those two faces.
|
|
2005
|
+
|
|
2009
2006
|
Grid dimension indexers cannot have more than 1 dimension (such as a 2D DataArray).
|
|
2007
|
+
Grid dimensions are never renamed (even if indexed by 1D DataArray with different dim name).
|
|
2008
|
+
Grid dimension indexer cannot have a non-grid dimension which exists in the original UxDataArray.
|
|
2010
2009
|
|
|
2011
2010
|
Parameters
|
|
2012
2011
|
----------
|
|
@@ -2042,6 +2041,10 @@ class UxDataArray(xr.DataArray):
|
|
|
2042
2041
|
-------
|
|
2043
2042
|
UxDataArray
|
|
2044
2043
|
A new UxDataArray indexed according to `indexers` and updated grid if applicable.
|
|
2044
|
+
If indexer DataArrays have coordinates that do not conflict with
|
|
2045
|
+
this object, then these coordinates will be attached,
|
|
2046
|
+
except that 1D coordinates of indexers applied along a grid dimension will
|
|
2047
|
+
only be included if it is 'n_face' and the data also has 'n_face' dimension.
|
|
2045
2048
|
|
|
2046
2049
|
Raises
|
|
2047
2050
|
------
|
|
@@ -2071,22 +2074,27 @@ class UxDataArray(xr.DataArray):
|
|
|
2071
2074
|
indexers = indexers.copy() # don't modify the original dict
|
|
2072
2075
|
grid_indexer = indexers.pop(grid_dim)
|
|
2073
2076
|
|
|
2077
|
+
_crash_if_1d_xarray_indexer_dim_in_uxarray_obj(self, grid_dim, grid_indexer)
|
|
2078
|
+
|
|
2074
2079
|
sliced_grid = self.uxgrid.isel(
|
|
2075
2080
|
**{grid_dim: grid_indexer}, inverse_indices=inverse_indices
|
|
2076
2081
|
)
|
|
2077
2082
|
|
|
2078
|
-
|
|
2083
|
+
result = self._slice_from_grid(sliced_grid)
|
|
2084
|
+
|
|
2085
|
+
result = _assign_grid_dim_indexer_coords_if_appropriate(
|
|
2086
|
+
result, grid_dim, grid_indexer
|
|
2087
|
+
)
|
|
2079
2088
|
|
|
2080
2089
|
# if there are any remaining indexers, apply them
|
|
2081
2090
|
if indexers:
|
|
2082
|
-
|
|
2091
|
+
result = super(UxDataArray, result).isel(
|
|
2083
2092
|
indexers=indexers, drop=drop, missing_dims=missing_dims
|
|
2084
2093
|
)
|
|
2085
2094
|
# re‐wrap so the grid sticks around
|
|
2086
|
-
|
|
2095
|
+
result = type(self)(result, uxgrid=sliced_grid)
|
|
2087
2096
|
|
|
2088
|
-
|
|
2089
|
-
return da
|
|
2097
|
+
return result
|
|
2090
2098
|
else: # len(grid_dims)>1; _validate_indexers should have crashed.
|
|
2091
2099
|
raise AssertionError("internal implementation error if reached this line")
|
|
2092
2100
|
|
|
@@ -2106,7 +2114,10 @@ class UxDataArray(xr.DataArray):
|
|
|
2106
2114
|
using n_edge=7 selects just the two faces touching edge 7. For data on 'n_face',
|
|
2107
2115
|
the result would have 'n_face' with just those two faces. For data on 'n_edge',
|
|
2108
2116
|
the result would have 'n_edge' with all edges located on either of those two faces.
|
|
2117
|
+
|
|
2109
2118
|
Grid dimension indexers cannot have more than 1 dimension (such as a 2D DataArray).
|
|
2119
|
+
Grid dimensions are never renamed (even if indexed by 1D DataArray with different dim name).
|
|
2120
|
+
Grid dimension indexer cannot have a non-grid dimension which exists in the original UxDataArray.
|
|
2110
2121
|
|
|
2111
2122
|
By default, grid dims do not have coordinates assigned. But, if they have
|
|
2112
2123
|
been assigned, `.sel()` respects them in the intuitive way. For example,
|
|
@@ -2167,7 +2178,8 @@ class UxDataArray(xr.DataArray):
|
|
|
2167
2178
|
and the uxgrid indexed appropriately as well, if indexing any grid dim.
|
|
2168
2179
|
If indexer DataArrays have coordinates that do not conflict with
|
|
2169
2180
|
this object, then these coordinates will be attached,
|
|
2170
|
-
except
|
|
2181
|
+
except that 1D coordinates of indexers applied along a grid dimension will
|
|
2182
|
+
only be included if it is 'n_face' and the data also has 'n_face' dimension.
|
|
2171
2183
|
In general, the result's data will be a view of the data in this array,
|
|
2172
2184
|
unless indexing along a grid dimension or otherwise
|
|
2173
2185
|
triggering vectorized indexing by using an array indexer,
|
|
@@ -2213,6 +2225,10 @@ class UxDataArray(xr.DataArray):
|
|
|
2213
2225
|
# offload the grid-indexing work to isel():
|
|
2214
2226
|
result = self.isel({grid_dim: grid_indices}, drop=drop)
|
|
2215
2227
|
|
|
2228
|
+
# special case: if grid_dim in indexer and result.coords, ensure consistency.
|
|
2229
|
+
# (all other coords' consistency checks already occurred in isel().)
|
|
2230
|
+
_assert_grid_dim_coord_consistent_if_in_both(result, grid_dim, grid_indexer)
|
|
2231
|
+
|
|
2216
2232
|
# index by other dims if any remain:
|
|
2217
2233
|
ds = result.to_xarray().sel(
|
|
2218
2234
|
indexers=indexers, # (grid_dim indexer was popped)
|
|
@@ -2321,7 +2337,7 @@ class UxDataArray(xr.DataArray):
|
|
|
2321
2337
|
"Data variable must be either node, edge, or face centered."
|
|
2322
2338
|
)
|
|
2323
2339
|
|
|
2324
|
-
return
|
|
2340
|
+
return type(self)(da_sliced, uxgrid=sliced_grid)
|
|
2325
2341
|
|
|
2326
2342
|
def get_dual(self):
|
|
2327
2343
|
"""Compute the dual mesh for a data array, returns a new data array
|
|
@@ -2359,9 +2375,7 @@ class UxDataArray(xr.DataArray):
|
|
|
2359
2375
|
dims = [dim_map.get(dim, dim) for dim in self.dims]
|
|
2360
2376
|
|
|
2361
2377
|
# Construct the new data array
|
|
2362
|
-
uxda =
|
|
2363
|
-
uxgrid=dual, data=self.data, dims=dims, name=self.name
|
|
2364
|
-
)
|
|
2378
|
+
uxda = type(self)(uxgrid=dual, data=self.data, dims=dims, name=self.name)
|
|
2365
2379
|
|
|
2366
2380
|
return uxda
|
|
2367
2381
|
|
|
@@ -11,7 +11,7 @@ from xarray.core import dtypes
|
|
|
11
11
|
from xarray.core.options import OPTIONS
|
|
12
12
|
from xarray.core.utils import UncachedAccessor
|
|
13
13
|
|
|
14
|
-
import
|
|
14
|
+
from uxarray.constants import GRID_DIMS
|
|
15
15
|
from uxarray.core.dataarray import UxDataArray
|
|
16
16
|
from uxarray.core.utils import (
|
|
17
17
|
_map_dims_to_ugrid,
|
|
@@ -28,6 +28,11 @@ from uxarray.grid.validation import _check_duplicate_nodes_indices
|
|
|
28
28
|
from uxarray.io._healpix import get_zoom_from_cells
|
|
29
29
|
from uxarray.plot.accessor import UxDatasetPlotAccessor
|
|
30
30
|
from uxarray.remap.accessor import RemapAccessor
|
|
31
|
+
from uxarray.utils.coords import (
|
|
32
|
+
_assert_grid_dim_coord_consistent_if_in_both,
|
|
33
|
+
_assign_grid_dim_indexer_coords_if_appropriate,
|
|
34
|
+
_crash_if_1d_xarray_indexer_dim_in_uxarray_obj,
|
|
35
|
+
)
|
|
31
36
|
|
|
32
37
|
|
|
33
38
|
class UxDataset(xr.Dataset):
|
|
@@ -387,33 +392,39 @@ class UxDataset(xr.Dataset):
|
|
|
387
392
|
|
|
388
393
|
return cls.from_xarray(ds, uxgrid, {face_dim: "n_face"})
|
|
389
394
|
|
|
390
|
-
def
|
|
395
|
+
def _slice_from_grid(self, sliced_grid):
|
|
396
|
+
"""returns UxDataset based on slicing self according to sliced_grid.
|
|
397
|
+
sliced_grid should be a ``Grid`` which came directly from self.uxgrid.isel(...)
|
|
398
|
+
(or from slicing something equal to self.uxgrid), else behavior is undefined.
|
|
399
|
+
"""
|
|
391
400
|
data_vars = {}
|
|
392
401
|
for name, da in self.data_vars.items():
|
|
393
|
-
if
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
data_vars[name] = da.isel({grid_dim: grid_indexer})
|
|
402
|
+
if hasattr(da, "_slice_from_grid") and any(
|
|
403
|
+
dim in da.dims for dim in GRID_DIMS
|
|
404
|
+
):
|
|
405
|
+
data_vars[name] = da._slice_from_grid(sliced_grid)
|
|
398
406
|
else:
|
|
399
407
|
data_vars[name] = da
|
|
400
408
|
|
|
401
|
-
coords
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
409
|
+
# Also account for any coords which aren't attached to any data_var:
|
|
410
|
+
bonus_coords = {}
|
|
411
|
+
for coord in self.coords:
|
|
412
|
+
for data_var in data_vars.values():
|
|
413
|
+
if coord in data_var.coords:
|
|
414
|
+
break
|
|
415
|
+
else: # didn't break
|
|
416
|
+
da = self.coords[coord]
|
|
417
|
+
if hasattr(da, "_slice_from_grid") and any(
|
|
418
|
+
dim in da.dims for dim in GRID_DIMS
|
|
419
|
+
):
|
|
420
|
+
bonus_coords[coord] = da._slice_from_grid(sliced_grid)
|
|
421
|
+
else:
|
|
422
|
+
bonus_coords[coord] = da
|
|
415
423
|
|
|
416
|
-
|
|
424
|
+
ds_sliced = xr.Dataset(
|
|
425
|
+
data_vars=data_vars, coords=bonus_coords, attrs=self.attrs
|
|
426
|
+
)
|
|
427
|
+
return type(self)(ds_sliced, uxgrid=sliced_grid)
|
|
417
428
|
|
|
418
429
|
def isel(
|
|
419
430
|
self,
|
|
@@ -435,7 +446,10 @@ class UxDataset(xr.Dataset):
|
|
|
435
446
|
using n_edge=7 selects just the two faces touching edge 7. For data on 'n_face',
|
|
436
447
|
the result would have 'n_face' with just those two faces. For data on 'n_edge',
|
|
437
448
|
the result would have 'n_edge' with all edges located on either of those two faces.
|
|
449
|
+
|
|
438
450
|
Grid dimension indexers cannot have more than 1 dimension (such as a 2D DataArray).
|
|
451
|
+
Grid dimensions are never renamed (even if indexed by 1D DataArray with different dim name).
|
|
452
|
+
Grid dimension indexer cannot have a non-grid dimension which exists in the original UxDataset.
|
|
439
453
|
|
|
440
454
|
Parameters
|
|
441
455
|
----------
|
|
@@ -471,6 +485,10 @@ class UxDataset(xr.Dataset):
|
|
|
471
485
|
-------
|
|
472
486
|
UxDataset
|
|
473
487
|
A new UxDataset indexed according to `indexers` and updated grid if applicable.
|
|
488
|
+
If indexer DataArrays have coordinates that do not conflict with
|
|
489
|
+
this object, then these coordinates will be attached,
|
|
490
|
+
except that 1D coordinates of indexers applied along a grid dimension will
|
|
491
|
+
only be included if it is 'n_face' and the data also has 'n_face' dimension.
|
|
474
492
|
|
|
475
493
|
Raises
|
|
476
494
|
------
|
|
@@ -500,23 +518,27 @@ class UxDataset(xr.Dataset):
|
|
|
500
518
|
indexers = indexers.copy() # don't modify the original dict
|
|
501
519
|
grid_indexer = indexers.pop(grid_dim)
|
|
502
520
|
|
|
503
|
-
|
|
521
|
+
_crash_if_1d_xarray_indexer_dim_in_uxarray_obj(self, grid_dim, grid_indexer)
|
|
522
|
+
|
|
504
523
|
sliced_grid = self.uxgrid.isel(
|
|
505
524
|
**{grid_dim: grid_indexer}, inverse_indices=inverse_indices
|
|
506
525
|
)
|
|
507
526
|
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
grid_indexer
|
|
527
|
+
result = self._slice_from_grid(sliced_grid)
|
|
528
|
+
|
|
529
|
+
result = _assign_grid_dim_indexer_coords_if_appropriate(
|
|
530
|
+
result, grid_dim, grid_indexer
|
|
512
531
|
)
|
|
513
532
|
|
|
533
|
+
# if there are any remaining indexers, apply them
|
|
514
534
|
if indexers:
|
|
515
|
-
|
|
516
|
-
|
|
535
|
+
result = super(UxDataset, result).isel(
|
|
536
|
+
indexers=indexers, drop=drop, missing_dims=missing_dims
|
|
517
537
|
)
|
|
538
|
+
# re‐wrap so the grid sticks around
|
|
539
|
+
result = type(self)(result, uxgrid=sliced_grid)
|
|
518
540
|
|
|
519
|
-
return
|
|
541
|
+
return result
|
|
520
542
|
else: # len(grid_dims)>1; _validate_indexers should have crashed.
|
|
521
543
|
raise AssertionError("internal implementation error if reached this line")
|
|
522
544
|
|
|
@@ -537,7 +559,10 @@ class UxDataset(xr.Dataset):
|
|
|
537
559
|
using n_edge=7 selects just the two faces touching edge 7. For data on 'n_face',
|
|
538
560
|
the result would have 'n_face' with just those two faces. For data on 'n_edge',
|
|
539
561
|
the result would have 'n_edge' with all edges located on either of those two faces.
|
|
562
|
+
|
|
540
563
|
Grid dimension indexers cannot have more than 1 dimension (such as a 2D DataArray).
|
|
564
|
+
Grid dimensions are never renamed (even if indexed by 1D DataArray with different dim name).
|
|
565
|
+
Grid dimension indexer cannot have a non-grid dimension which exists in the original UxDataset.
|
|
541
566
|
|
|
542
567
|
By default, grid dims do not have coordinates assigned. But, if they have
|
|
543
568
|
been assigned, `.sel()` respects them in the intuitive way. For example,
|
|
@@ -566,7 +591,8 @@ class UxDataset(xr.Dataset):
|
|
|
566
591
|
multi-index, the indexer may also be a dict-like object with keys
|
|
567
592
|
matching index level names.
|
|
568
593
|
If DataArrays are passed as indexers, xarray-style indexing will be
|
|
569
|
-
carried out
|
|
594
|
+
carried out (see :ref:`indexing` for the details),
|
|
595
|
+
with one exception: grid dimensions will never be renamed.
|
|
570
596
|
One of indexers or indexers_kwargs must be provided.
|
|
571
597
|
method : {None, "nearest", "pad", "ffill", "backfill", "bfill"}, optional
|
|
572
598
|
Method to use for inexact matches:
|
|
@@ -599,7 +625,8 @@ class UxDataset(xr.Dataset):
|
|
|
599
625
|
and the uxgrid indexed appropriately as well, if indexing any grid dim.
|
|
600
626
|
If indexer DataArrays have coordinates that do not conflict with
|
|
601
627
|
this object, then these coordinates will be attached,
|
|
602
|
-
except
|
|
628
|
+
except that 1D coordinates of indexers applied along a grid dimension will
|
|
629
|
+
only be included if it is 'n_face' and the data also has 'n_face' dimension.
|
|
603
630
|
In general, each array's data will be a view of the array's data
|
|
604
631
|
in this dataset, unless indexing along a grid dimension or otherwise
|
|
605
632
|
triggering vectorized indexing by using an array indexer,
|
|
@@ -646,6 +673,10 @@ class UxDataset(xr.Dataset):
|
|
|
646
673
|
# offload the grid-indexing work to isel():
|
|
647
674
|
result = self.isel({grid_dim: grid_indices}, drop=drop)
|
|
648
675
|
|
|
676
|
+
# special case: if grid_dim in indexer and result.coords, ensure consistency.
|
|
677
|
+
# (all other coords' consistency checks already occurred in isel().)
|
|
678
|
+
_assert_grid_dim_coord_consistent_if_in_both(result, grid_dim, grid_indexer)
|
|
679
|
+
|
|
649
680
|
# index by other dims if any remain:
|
|
650
681
|
ds = result.to_xarray().sel(
|
|
651
682
|
indexers=indexers, # (grid_dim indexer was popped)
|
|
@@ -921,7 +952,7 @@ class UxDataset(xr.Dataset):
|
|
|
921
952
|
)
|
|
922
953
|
|
|
923
954
|
# Initialize new dataset
|
|
924
|
-
dataset =
|
|
955
|
+
dataset = type(self)(uxgrid=dual)
|
|
925
956
|
|
|
926
957
|
# Dictionary to swap dimensions
|
|
927
958
|
dim_map = {"n_face": "n_node", "n_node": "n_face"}
|
|
@@ -932,9 +963,7 @@ class UxDataset(xr.Dataset):
|
|
|
932
963
|
dims = [dim_map.get(dim, dim) for dim in self[var].dims]
|
|
933
964
|
|
|
934
965
|
# Construct the new data array
|
|
935
|
-
uxda =
|
|
936
|
-
uxgrid=dual, data=self[var].data, dims=dims, name=var
|
|
937
|
-
)
|
|
966
|
+
uxda = UxDataArray(uxgrid=dual, data=self[var].data, dims=dims, name=var)
|
|
938
967
|
|
|
939
968
|
# Add data array to dataset
|
|
940
969
|
dataset[var] = uxda
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import warnings
|
|
2
|
+
|
|
1
3
|
import numpy as np
|
|
2
4
|
import xarray as xr
|
|
3
5
|
from xarray.core.utils import either_dict_or_kwargs
|
|
@@ -186,10 +188,7 @@ def _resolve_coordinate_labels_to_indices(
|
|
|
186
188
|
):
|
|
187
189
|
"""returns indices which would be selected by coord_array.sel({dim: labels_to_sel}, ...)
|
|
188
190
|
coord_array.isel({dim: result}) should be equivalent to coord_array.sel({dim: labels_to_sel}, ...).
|
|
189
|
-
|
|
190
|
-
(Implementation here drops extra coordinates from any indexers,
|
|
191
|
-
but if it is being applied to grid dims for sel() then it will produce behavior
|
|
192
|
-
which is consistent with isel(), unless issue #1712 gets fixed.)
|
|
191
|
+
If labels_to_sel is an xr.DataArray, its coords/dims will also be attached to the result.
|
|
193
192
|
|
|
194
193
|
dim: str
|
|
195
194
|
dimension name to select along
|
|
@@ -203,10 +202,26 @@ def _resolve_coordinate_labels_to_indices(
|
|
|
203
202
|
# (Maybe a more efficient implementation exists, but this is simple and gives correct results.)
|
|
204
203
|
indices = xr.DataArray(np.arange(coord_array.sizes[dim]), dims=dim)
|
|
205
204
|
_indices_coord_name = f"__{dim}_indices__" # just needs to be any unused name.
|
|
205
|
+
if _indices_coord_name in coord_array.coords:
|
|
206
|
+
warnings.warn(
|
|
207
|
+
f"Coordinate {_indices_coord_name!r} already exists in coord_array.coords "
|
|
208
|
+
"and will be overwritten, which may cause errors or subtly incorrect results..."
|
|
209
|
+
)
|
|
206
210
|
if hasattr(coord_array, "to_xarray"): # convert to xarray to avoid recursive sel()
|
|
207
211
|
coord_array = coord_array.to_xarray()
|
|
208
212
|
coord_with_indices = coord_array.assign_coords({_indices_coord_name: indices})
|
|
209
213
|
selected = coord_with_indices.sel(
|
|
210
214
|
{dim: labels_to_sel}, method=method, tolerance=tolerance
|
|
211
215
|
)
|
|
212
|
-
|
|
216
|
+
result = selected[_indices_coord_name]
|
|
217
|
+
if isinstance(labels_to_sel, xr.DataArray):
|
|
218
|
+
# handle coords appropriately
|
|
219
|
+
result = result.drop_vars((dim, _indices_coord_name))
|
|
220
|
+
# (drop grid dim coords because the caller is expected to handle those directly;
|
|
221
|
+
# here the goal is just to properly propagate any other coords from labels_to_sel.)
|
|
222
|
+
result = result.rename(None) # no reason to keep the _indices_coord_name
|
|
223
|
+
# (and keeping it for longer could maybe cause confusing error later?)
|
|
224
|
+
else:
|
|
225
|
+
# drop all coords/name info which was added internally during this method.
|
|
226
|
+
result = result.values
|
|
227
|
+
return result
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import numpy as np
|
|
2
2
|
|
|
3
|
+
from uxarray.utils.imports import _raise_hint_if_optional_deps_missing
|
|
4
|
+
|
|
3
5
|
|
|
4
6
|
def sample_geodesic(
|
|
5
7
|
start: tuple[float, float], end: tuple[float, float], steps: int
|
|
6
8
|
) -> tuple[np.ndarray, np.ndarray]:
|
|
9
|
+
_raise_hint_if_optional_deps_missing("pyproj")
|
|
7
10
|
from pyproj import Geod
|
|
8
11
|
|
|
9
12
|
lon0, lat0 = start
|
|
@@ -38,3 +38,10 @@ class GridsMismatchError(ValueError):
|
|
|
38
38
|
|
|
39
39
|
class YacNotAvailableError(RuntimeError):
|
|
40
40
|
"""Raised when the YAC backend is requested but unavailable."""
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
# # # ----- Miscellaneous Errors ----- # # #
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class OptionalDependencyNotFoundError(ModuleNotFoundError):
|
|
47
|
+
"""indicates functionality relies on a not-yet-installed optional dependency."""
|