From 12c266283242e6cc1b596b1cdb678090585c2994 Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Tue, 29 Apr 2025 21:28:21 +1200 Subject: [PATCH 01/16] Allow passing region to GMTBackendEntrypoint.open_dataset Support passing in a region as a Sequence [xmin, xmax, ymin, ymax] or ISO country code to `xarray.open_dataset` when using `engine="gmt"`. --- pygmt/tests/test_xarray_backend.py | 43 +++++++++++++++++++++++++++--- pygmt/xarray/backend.py | 12 ++++++--- 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/pygmt/tests/test_xarray_backend.py b/pygmt/tests/test_xarray_backend.py index c62b720b429..2f7cdd5ed7c 100644 --- a/pygmt/tests/test_xarray_backend.py +++ b/pygmt/tests/test_xarray_backend.py @@ -36,8 +36,8 @@ def test_xarray_backend_load_dataarray(): def test_xarray_backend_gmt_open_nc_grid(): """ - Ensure that passing engine='gmt' to xarray.open_dataarray works for opening NetCDF - grids. + Ensure that passing engine='gmt' to xarray.open_dataarray works to open a netCDF + grid. """ with xr.open_dataarray( "@static_earth_relief.nc", engine="gmt", raster_kind="grid" @@ -48,10 +48,29 @@ def test_xarray_backend_gmt_open_nc_grid(): assert da.gmt.registration == GridRegistration.PIXEL +def test_xarray_backend_gmt_open_nc_grid_with_region_bbox(): + """ + Ensure that passing engine='gmt' with a `region` argument to xarray.open_dataarray + works to open a netCDF grid over a specific bounding box. + """ + with xr.open_dataarray( + "@static_earth_relief.nc", + engine="gmt", + raster_kind="grid", + region=[-52, -48, -18, -12], + ) as da: + assert da.sizes == {"lat": 6, "lon": 4} + npt.assert_allclose(da.lat, [-17.5, -16.5, -15.5, -14.5, -13.5, -12.5]) + npt.assert_allclose(da.lon, [-51.5, -50.5, -49.5, -48.5]) + assert da.dtype == "float32" + assert da.gmt.gtype == GridType.GEOGRAPHIC + assert da.gmt.registration == GridRegistration.PIXEL + + def test_xarray_backend_gmt_open_tif_image(): """ - Ensure that passing engine='gmt' to xarray.open_dataarray works for opening GeoTIFF - images. + Ensure that passing engine='gmt' to xarray.open_dataarray works to open a GeoTIFF + image. """ with xr.open_dataarray("@earth_day_01d", engine="gmt", raster_kind="image") as da: assert da.sizes == {"band": 3, "y": 180, "x": 360} @@ -60,6 +79,22 @@ def test_xarray_backend_gmt_open_tif_image(): assert da.gmt.registration == GridRegistration.PIXEL +def test_xarray_backend_gmt_open_tif_image_with_region_iso(): + """ + Ensure that passing engine='gmt' with a `region` argument to xarray.open_dataarray + works to open a GeoTIFF image over a specific ISO country code border. + """ + with xr.open_dataarray( + "@earth_day_01d", engine="gmt", raster_kind="image", region="BN" + ) as da: + assert da.sizes == {"band": 3, "lat": 2, "lon": 2} + npt.assert_allclose(da.lat, [5.5, 4.5]) + npt.assert_allclose(da.lon, [114.5, 115.5]) + assert da.dtype == "uint8" + assert da.gmt.gtype == GridType.GEOGRAPHIC + assert da.gmt.registration == GridRegistration.PIXEL + + def test_xarray_backend_gmt_load_grd_grid(): """ Ensure that passing engine='gmt' to xarray.load_dataarray works for loading GRD diff --git a/pygmt/xarray/backend.py b/pygmt/xarray/backend.py index a95e98983db..f438b7f361c 100644 --- a/pygmt/xarray/backend.py +++ b/pygmt/xarray/backend.py @@ -2,13 +2,14 @@ An xarray backend for reading raster grid/image files using the 'gmt' engine. """ +from collections.abc import Sequence from typing import Literal import xarray as xr from pygmt._typing import PathLike from pygmt.clib import Session from pygmt.exceptions import GMTInvalidInput -from pygmt.helpers import build_arg_list +from pygmt.helpers import build_arg_list, kwargs_to_strings from pygmt.src.which import which from xarray.backends import BackendEntrypoint @@ -71,15 +72,17 @@ class GMTBackendEntrypoint(BackendEntrypoint): """ description = "Open raster (.grd, .nc or .tif) files in Xarray via GMT." - open_dataset_parameters = ("filename_or_obj", "raster_kind") + open_dataset_parameters = ("filename_or_obj", "raster_kind", "region") url = "https://pygmt.org/dev/api/generated/pygmt.GMTBackendEntrypoint.html" + @kwargs_to_strings(region="sequence") def open_dataset( # type: ignore[override] self, filename_or_obj: PathLike, *, drop_variables=None, # noqa: ARG002 raster_kind: Literal["grid", "image"], + region: Sequence[float] | str | None = None, # other backend specific keyword arguments # `chunks` and `cache` DO NOT go here, they are handled by xarray ) -> xr.Dataset: @@ -94,6 +97,9 @@ def open_dataset( # type: ignore[override] :gmt-docs:`reference/features.html#grid-file-format`. raster_kind Whether to read the file as a "grid" (single-band) or "image" (multi-band). + region + Optional. The subregion of the grid or image to load, in the form of a + sequence [*xmin*, *xmax*, *ymin*, *ymax*] or an ISO country code. """ if raster_kind not in {"grid", "image"}: msg = f"Invalid raster kind: '{raster_kind}'. Valid values are 'grid' or 'image'." @@ -101,7 +107,7 @@ def open_dataset( # type: ignore[override] with Session() as lib: with lib.virtualfile_out(kind=raster_kind) as voutfile: - kwdict = {"T": {"grid": "g", "image": "i"}[raster_kind]} + kwdict = {"R": region, "T": {"grid": "g", "image": "i"}[raster_kind]} lib.call_module( module="read", args=[filename_or_obj, voutfile, *build_arg_list(kwdict)], From 3114987a9c72558aa3168163814306a16a48839a Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Tue, 29 Apr 2025 21:37:15 +1200 Subject: [PATCH 02/16] Refactor _load_remote_dataset internals to use xr.load_dataarray Remove duplicated code calling GMT read, since `xr.load_dataarray(engine="gmt")` now works with region argument. --- pygmt/datasets/load_remote_dataset.py | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/pygmt/datasets/load_remote_dataset.py b/pygmt/datasets/load_remote_dataset.py index c6f0471b8ee..b86174dd54d 100644 --- a/pygmt/datasets/load_remote_dataset.py +++ b/pygmt/datasets/load_remote_dataset.py @@ -7,10 +7,8 @@ from typing import Any, Literal, NamedTuple import xarray as xr -from pygmt.clib import Session from pygmt.exceptions import GMTInvalidInput -from pygmt.helpers import build_arg_list, kwargs_to_strings -from pygmt.src import which +from pygmt.helpers import kwargs_to_strings with contextlib.suppress(ImportError): # rioxarray is needed to register the rio accessor @@ -581,22 +579,9 @@ def _load_remote_dataset( raise GMTInvalidInput(msg) fname = f"@{prefix}_{resolution}_{reg}" - kwdict = {"R": region, "T": {"grid": "g", "image": "i"}[dataset.kind]} - with Session() as lib: - with lib.virtualfile_out(kind=dataset.kind) as voutgrd: - lib.call_module( - module="read", - args=[fname, voutgrd, *build_arg_list(kwdict)], - ) - grid = lib.virtualfile_to_raster( - kind=dataset.kind, outgrid=None, vfname=voutgrd - ) - - # Full path to the grid if not tiled grids. - source = which(fname, download="a") if not resinfo.tiled else None - # Manually add source to xarray.DataArray encoding to make the GMT accessors work. - if source: - grid.encoding["source"] = source + grid = xr.load_dataarray( + fname, engine="gmt", raster_kind=dataset.kind, region=region + ) # Add some metadata to the grid grid.attrs["description"] = dataset.description From 72abcaf2d5f4c950acabac44edf3b90d8155b06a Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Tue, 29 Apr 2025 21:55:07 +1200 Subject: [PATCH 03/16] Update TypeError regex for test_xarray_backend_gmt_read_invalid_kind --- pygmt/tests/test_xarray_backend.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pygmt/tests/test_xarray_backend.py b/pygmt/tests/test_xarray_backend.py index 2f7cdd5ed7c..e39dcf028e4 100644 --- a/pygmt/tests/test_xarray_backend.py +++ b/pygmt/tests/test_xarray_backend.py @@ -119,9 +119,7 @@ def test_xarray_backend_gmt_read_invalid_kind(): """ with pytest.raises( TypeError, - match=re.escape( - "GMTBackendEntrypoint.open_dataset() missing 1 required keyword-only argument: 'raster_kind'" - ), + match=re.escape("missing a required argument: 'raster_kind'"), ): xr.open_dataarray("nokind.nc", engine="gmt") From 1a5837aabd1a91cf3f671152e4638499d54e36a6 Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Tue, 29 Apr 2025 22:10:07 +1200 Subject: [PATCH 04/16] Source file for tiled grids is undefined previously, but not anymore? --- pygmt/tests/test_xarray_accessor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/tests/test_xarray_accessor.py b/pygmt/tests/test_xarray_accessor.py index 4967d37e6ce..2c7d6e5137b 100644 --- a/pygmt/tests/test_xarray_accessor.py +++ b/pygmt/tests/test_xarray_accessor.py @@ -144,7 +144,7 @@ def test_xarray_accessor_grid_source_file_not_exist(): # Registration and gtype are correct. assert grid.gmt.registration == GridRegistration.PIXEL assert grid.gmt.gtype == GridType.GEOGRAPHIC - # The source grid file is undefined. + # The source grid file is undefined for tiled grids. assert grid.encoding.get("source") is None # For a sliced grid, fallback to default registration and gtype, because the source From fe6bd44684561500debb34e7dc1fd23f488f8dd1 Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Wed, 30 Apr 2025 11:30:08 +1200 Subject: [PATCH 05/16] Set type-hint for source variable --- pygmt/xarray/backend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/xarray/backend.py b/pygmt/xarray/backend.py index f438b7f361c..e756e0a1639 100644 --- a/pygmt/xarray/backend.py +++ b/pygmt/xarray/backend.py @@ -117,7 +117,7 @@ def open_dataset( # type: ignore[override] vfname=voutfile, kind=raster_kind ) # Add "source" encoding - source = which(fname=filename_or_obj) + source: str | list = which(fname=filename_or_obj) raster.encoding["source"] = ( source[0] if isinstance(source, list) else source ) From 6dec9adc5b33eb6a37e241c8f29d1a3b74bec0f6 Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Wed, 30 Apr 2025 11:57:58 +1200 Subject: [PATCH 06/16] Don't need to re-load GMTDataArray accessor info in GMTBackendEntrypoint GMTDataArrayAccessor info should already be loaded by calling`virtualfile_to_raster` which calls `self.read_virtualfile(vfname, kind=kind).contents.to_xarray()` that sets registration and gtype from the header. --- pygmt/xarray/backend.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pygmt/xarray/backend.py b/pygmt/xarray/backend.py index e756e0a1639..aa09de31e57 100644 --- a/pygmt/xarray/backend.py +++ b/pygmt/xarray/backend.py @@ -121,5 +121,4 @@ def open_dataset( # type: ignore[override] raster.encoding["source"] = ( source[0] if isinstance(source, list) else source ) - _ = raster.gmt # Load GMTDataArray accessor information return raster.to_dataset() From 07b2802449e37c9b90ad3429078761168d286318 Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Wed, 7 May 2025 11:07:25 +1200 Subject: [PATCH 07/16] Set registration and gtype properly as enums on init --- pygmt/xarray/accessor.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pygmt/xarray/accessor.py b/pygmt/xarray/accessor.py index d0891076d2a..5eb12b81201 100644 --- a/pygmt/xarray/accessor.py +++ b/pygmt/xarray/accessor.py @@ -137,9 +137,11 @@ def __init__(self, xarray_obj: xr.DataArray): # two columns of the shortened summary information of grdinfo. if (_source := self._obj.encoding.get("source")) and Path(_source).exists(): with contextlib.suppress(ValueError): - self._registration, self._gtype = map( # type: ignore[assignment] + _registration, _gtype = map( int, grdinfo(_source, per_column="n").split()[-2:] ) + self._registration = GridRegistration(_registration) + self._gtype = GridType(_gtype) @property def registration(self) -> GridRegistration: From 5557b3343247dd1a5312b0ff921daf6f06d56d9d Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Thu, 8 May 2025 15:54:22 +1200 Subject: [PATCH 08/16] Silence Error: h [ERROR]: Tile @*.earth_*.nc not found errors --- pygmt/xarray/backend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/xarray/backend.py b/pygmt/xarray/backend.py index aa09de31e57..b17a34bc267 100644 --- a/pygmt/xarray/backend.py +++ b/pygmt/xarray/backend.py @@ -117,7 +117,7 @@ def open_dataset( # type: ignore[override] vfname=voutfile, kind=raster_kind ) # Add "source" encoding - source: str | list = which(fname=filename_or_obj) + source: str | list = which(fname=filename_or_obj, verbose="q") raster.encoding["source"] = ( source[0] if isinstance(source, list) else source ) From deb2df0af301cbfba6cfdb537a76ede3250e5966 Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Fri, 9 May 2025 20:41:44 +1200 Subject: [PATCH 09/16] Add doctest for load_dataarray with region argument --- pygmt/xarray/backend.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/pygmt/xarray/backend.py b/pygmt/xarray/backend.py index b17a34bc267..25adf5168f4 100644 --- a/pygmt/xarray/backend.py +++ b/pygmt/xarray/backend.py @@ -31,6 +31,9 @@ class GMTBackendEntrypoint(BackendEntrypoint): - ``"grid"``: for reading single-band raster grids - ``"image"``: for reading multi-band raster images + Optionally, you can pass in a `region`in the form of a sequence [*xmin*, *xmax*, + *ymin*, *ymax*] or an ISO country code. + Examples -------- Read a single-band netCDF file using ``raster_kind="grid"`` @@ -69,6 +72,31 @@ class GMTBackendEntrypoint(BackendEntrypoint): * band (band) uint8... 1 2 3 Attributes:... long_name: z + + Load a single-band netCDF file using ``raster_kind="grid"`` over a bounding box + region. + + >>> da_grid = xr.load_dataarray( + ... "@tut_bathy.nc", engine="gmt", raster_kind="grid", region=[-64, -62, 32, 33] + ... ) + >>> da_grid + ... + array([[-4369., -4587., -4469., -4409., -4587., -4505., -4403., -4405., + -4466., -4595., -4609., -4608., -4606., -4607., -4607., -4597., + ... + -4667., -4642., -4677., -4795., -4797., -4800., -4803., -4818., + -4820.]], dtype=float32) + Coordinates: + * lat (lat) float64... 32.0 32.08 32.17 32.25 ... 32.83 32.92 33.0 + * lon (lon) float64... -64.0 -63.92 -63.83 ... -62.17 -62.08 -62.0 + Attributes:... + Conventions: CF-1.7 + title: ETOPO5 global topography + history: grdreformat -fg bermuda.grd bermuda.nc=ns + description: /home/elepaio5/data/grids/etopo5.i2 + actual_range: [-4968. -4315.] + long_name: Topography + units: m """ description = "Open raster (.grd, .nc or .tif) files in Xarray via GMT." From 221b60c4ead5a04523bd1edd31f8408b60140b67 Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Fri, 9 May 2025 21:08:20 +1200 Subject: [PATCH 10/16] Refactor test_xarray_accessor_grid_source_file_not_exist Slicing a tiled grid retains the original source still, but doing math operations like addition cause source to be lost and fallback to default registration/gtype. --- pygmt/tests/test_xarray_accessor.py | 37 +++++++++++++++++++---------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/pygmt/tests/test_xarray_accessor.py b/pygmt/tests/test_xarray_accessor.py index 09e3d7ec8ed..2c23a11e44b 100644 --- a/pygmt/tests/test_xarray_accessor.py +++ b/pygmt/tests/test_xarray_accessor.py @@ -132,10 +132,13 @@ def test_xarray_accessor_sliced_datacube(): Path(fname).unlink() -def test_xarray_accessor_grid_source_file_not_exist(): +def test_xarray_accessor_tiled_grid_slice_and_add(): """ - Check that the accessor fallbacks to the default registration and gtype when the - grid source file (i.e., grid.encoding["source"]) doesn't exist. + Check that the accessor works to get the registration and gtype when the grid source + file is from a tiled grid, that slicing doesn't affect registration/gtype, but math + operations do return the default registration/gtype as a fallback. + + Unit test to track https://github.com/GenericMappingTools/pygmt/issues/524 """ # Load the 05m earth relief grid, which is stored as tiles. grid = load_earth_relief( @@ -144,17 +147,25 @@ def test_xarray_accessor_grid_source_file_not_exist(): # Registration and gtype are correct. assert grid.gmt.registration is GridRegistration.PIXEL assert grid.gmt.gtype is GridType.GEOGRAPHIC - # The source grid file is undefined for tiled grids. - assert grid.encoding.get("source") is None + # The source grid file for tiled grids is the first tile + assert grid.encoding["source"].endswith("S90E000.earth_relief_05m_p.nc") - # For a sliced grid, fallback to default registration and gtype, because the source - # grid file doesn't exist. + # For a sliced grid, ensure we don't fallback to the default registration (gridline) + # and gtype (cartesian), because the source grid file should still exist. sliced_grid = grid[1:3, 1:3] - assert sliced_grid.gmt.registration is GridRegistration.GRIDLINE - assert sliced_grid.gmt.gtype is GridType.CARTESIAN - - # Still possible to manually set registration and gtype. - sliced_grid.gmt.registration = GridRegistration.PIXEL - sliced_grid.gmt.gtype = GridType.GEOGRAPHIC + assert sliced_grid.encoding["source"].endswith("S90E000.earth_relief_05m_p.nc") assert sliced_grid.gmt.registration is GridRegistration.PIXEL assert sliced_grid.gmt.gtype is GridType.GEOGRAPHIC + + # For a grid that underwent mathematical operations, fallback to default + # registration and gtype, because the source grid file doesn't exist. + added_grid = sliced_grid + 9 + assert added_grid.encoding == {} + assert added_grid.gmt.registration is GridRegistration.GRIDLINE + assert added_grid.gmt.gtype is GridType.CARTESIAN + + # Still possible to manually set registration and gtype. + added_grid.gmt.registration = GridRegistration.PIXEL + added_grid.gmt.gtype = GridType.GEOGRAPHIC + assert added_grid.gmt.registration is GridRegistration.PIXEL + assert added_grid.gmt.gtype is GridType.GEOGRAPHIC From 11436addfa621adc7494032058072eae450eb56e Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Fri, 9 May 2025 21:18:43 +1200 Subject: [PATCH 11/16] Difference in returned tile order on CI vs local? Try a different tile to see if it passes on CI --- pygmt/tests/test_xarray_accessor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pygmt/tests/test_xarray_accessor.py b/pygmt/tests/test_xarray_accessor.py index 2c23a11e44b..bd42162d6b2 100644 --- a/pygmt/tests/test_xarray_accessor.py +++ b/pygmt/tests/test_xarray_accessor.py @@ -148,12 +148,12 @@ def test_xarray_accessor_tiled_grid_slice_and_add(): assert grid.gmt.registration is GridRegistration.PIXEL assert grid.gmt.gtype is GridType.GEOGRAPHIC # The source grid file for tiled grids is the first tile - assert grid.encoding["source"].endswith("S90E000.earth_relief_05m_p.nc") + assert grid.encoding["source"].endswith("S90W180.earth_relief_05m_p.nc") # For a sliced grid, ensure we don't fallback to the default registration (gridline) # and gtype (cartesian), because the source grid file should still exist. sliced_grid = grid[1:3, 1:3] - assert sliced_grid.encoding["source"].endswith("S90E000.earth_relief_05m_p.nc") + assert sliced_grid.encoding["source"].endswith("S90W180.earth_relief_05m_p.nc") assert sliced_grid.gmt.registration is GridRegistration.PIXEL assert sliced_grid.gmt.gtype is GridType.GEOGRAPHIC From ba7309598b24d1ce37962b1929617397bdb1c87a Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Thu, 15 May 2025 08:49:36 +1200 Subject: [PATCH 12/16] Reduce diff from merge conflict --- pygmt/tests/test_xarray_accessor.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pygmt/tests/test_xarray_accessor.py b/pygmt/tests/test_xarray_accessor.py index bd42162d6b2..5422f6defcb 100644 --- a/pygmt/tests/test_xarray_accessor.py +++ b/pygmt/tests/test_xarray_accessor.py @@ -148,16 +148,16 @@ def test_xarray_accessor_tiled_grid_slice_and_add(): assert grid.gmt.registration is GridRegistration.PIXEL assert grid.gmt.gtype is GridType.GEOGRAPHIC # The source grid file for tiled grids is the first tile - assert grid.encoding["source"].endswith("S90W180.earth_relief_05m_p.nc") + assert grid.encoding["source"].endswith("S90E000.earth_relief_05m_p.nc") # For a sliced grid, ensure we don't fallback to the default registration (gridline) # and gtype (cartesian), because the source grid file should still exist. sliced_grid = grid[1:3, 1:3] - assert sliced_grid.encoding["source"].endswith("S90W180.earth_relief_05m_p.nc") + assert sliced_grid.encoding["source"].endswith("S90E000.earth_relief_05m_p.nc") assert sliced_grid.gmt.registration is GridRegistration.PIXEL assert sliced_grid.gmt.gtype is GridType.GEOGRAPHIC - # For a grid that underwent mathematical operations, fallback to default + # For a grid that underwent mathematical operations, fallback to default # registration and gtype, because the source grid file doesn't exist. added_grid = sliced_grid + 9 assert added_grid.encoding == {} From 36fb6e09fbe5dac8225ca283e5078e95cd2284e6 Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Thu, 15 May 2025 08:53:42 +1200 Subject: [PATCH 13/16] Remove @kwargs_to_strings from _load_remote_dataset Co-authored-by: Dongdong Tian --- pygmt/datasets/load_remote_dataset.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pygmt/datasets/load_remote_dataset.py b/pygmt/datasets/load_remote_dataset.py index b86174dd54d..e40811a9444 100644 --- a/pygmt/datasets/load_remote_dataset.py +++ b/pygmt/datasets/load_remote_dataset.py @@ -500,7 +500,6 @@ class GMTRemoteDataset(NamedTuple): } -@kwargs_to_strings(region="sequence") def _load_remote_dataset( name: str, prefix: str, From ae785c706a8664fe1cd16df90ac0636a9b79899c Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Thu, 15 May 2025 08:54:02 +1200 Subject: [PATCH 14/16] Docstring updates Co-authored-by: Dongdong Tian --- pygmt/xarray/backend.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pygmt/xarray/backend.py b/pygmt/xarray/backend.py index 25adf5168f4..4bfb8cc2233 100644 --- a/pygmt/xarray/backend.py +++ b/pygmt/xarray/backend.py @@ -31,7 +31,7 @@ class GMTBackendEntrypoint(BackendEntrypoint): - ``"grid"``: for reading single-band raster grids - ``"image"``: for reading multi-band raster images - Optionally, you can pass in a `region`in the form of a sequence [*xmin*, *xmax*, + Optionally, you can pass in a ``region`` in the form of a sequence [*xmin*, *xmax*, *ymin*, *ymax*] or an ISO country code. Examples @@ -126,8 +126,8 @@ def open_dataset( # type: ignore[override] raster_kind Whether to read the file as a "grid" (single-band) or "image" (multi-band). region - Optional. The subregion of the grid or image to load, in the form of a - sequence [*xmin*, *xmax*, *ymin*, *ymax*] or an ISO country code. + The subregion of the grid or image to load, in the form of a sequence + [*xmin*, *xmax*, *ymin*, *ymax*] or an ISO country code. """ if raster_kind not in {"grid", "image"}: msg = f"Invalid raster kind: '{raster_kind}'. Valid values are 'grid' or 'image'." From c1761543b736d9957e10959b9acbe138b8e029be Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Thu, 15 May 2025 08:55:40 +1200 Subject: [PATCH 15/16] format --- pygmt/datasets/load_remote_dataset.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pygmt/datasets/load_remote_dataset.py b/pygmt/datasets/load_remote_dataset.py index e40811a9444..ac23714b34e 100644 --- a/pygmt/datasets/load_remote_dataset.py +++ b/pygmt/datasets/load_remote_dataset.py @@ -8,7 +8,6 @@ import xarray as xr from pygmt.exceptions import GMTInvalidInput -from pygmt.helpers import kwargs_to_strings with contextlib.suppress(ImportError): # rioxarray is needed to register the rio accessor From b488b105b66efae3c91b8e3637ca3bd6cf2d00cd Mon Sep 17 00:00:00 2001 From: Wei Ji <23487320+weiji14@users.noreply.github.com> Date: Thu, 15 May 2025 12:21:20 +1200 Subject: [PATCH 16/16] Sort list of source files alphabetically Co-authored-by: Dongdong Tian --- pygmt/xarray/backend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/xarray/backend.py b/pygmt/xarray/backend.py index 4bfb8cc2233..24530881fb4 100644 --- a/pygmt/xarray/backend.py +++ b/pygmt/xarray/backend.py @@ -147,6 +147,6 @@ def open_dataset( # type: ignore[override] # Add "source" encoding source: str | list = which(fname=filename_or_obj, verbose="q") raster.encoding["source"] = ( - source[0] if isinstance(source, list) else source + sorted(source)[0] if isinstance(source, list) else source ) return raster.to_dataset()