From e2433f61c559be63977eb2a5a87810f80b103a4a Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Mon, 1 Apr 2024 14:13:35 +0800 Subject: [PATCH 01/11] Wrap GMT's standard data type GMT_GRID for grids --- pygmt/datatypes/grid.py | 192 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 191 insertions(+), 1 deletion(-) diff --git a/pygmt/datatypes/grid.py b/pygmt/datatypes/grid.py index e67f44ebef5..bd5e9599b75 100644 --- a/pygmt/datatypes/grid.py +++ b/pygmt/datatypes/grid.py @@ -3,7 +3,197 @@ """ import ctypes as ctp +from typing import ClassVar + +import numpy as np +import xarray as xr +from pygmt.datatypes.header import _GMT_GRID_HEADER, gmt_grdfloat class _GMT_GRID(ctp.Structure): # noqa: N801 - pass + """ + GMT grid structure for holding a grid and its header. + + The class is only meant for internal use and is not exposed to users. See the GMT + source code gmt_resources.h for the original C structure definitions. + + Examples + -------- + >>> from pygmt.clib import Session + >>> with Session() as lib: + ... with lib.virtualfile_out(kind="grid") as voutgrd: + ... lib.call_module("read", f"@static_earth_relief.nc {voutgrd} -Tg") + ... # Read the grid from the virtual file + ... grid = lib.read_virtualfile(voutgrd, kind="grid").contents + ... # The grid header + ... header = grid.header.contents + ... # Access the header properties + ... print(header.n_rows, header.n_columns, header.registration) + ... print(header.wesn[:], header.z_min, header.z_max, header.inc[:]) + ... print(header.z_scale_factor, header.z_add_offset) + ... print(header.x_units, header.y_units, header.z_units) + ... print(header.title) + ... print(header.command) + ... print(header.remark) + ... print(header.nm, header.size, header.complex_mode) + ... print(header.type, header.n_bands, header.mx, header.my) + ... print(header.pad[:]) + ... print(header.mem_layout, header.nan_value, header.xy_off) + ... # The x and y coordinates + ... print(grid.x[: header.n_columns]) + ... print(grid.y[: header.n_rows]) + ... # The data array (with paddings) + ... data = np.reshape( + ... grid.data[: header.mx * header.my], (header.my, header.mx) + ... ) + ... # The data array (without paddings) + ... pad = header.pad[:] + ... data = data[pad[2] : header.my - pad[3], pad[0] : header.mx - pad[1]] + ... print(data) + 14 8 1 + [-55.0, -47.0, -24.0, -10.0] 190.0 981.0 [1.0, 1.0] + 1.0 0.0 + b'longitude [degrees_east]' b'latitude [degrees_north]' b'elevation (m)' + b'Produced by grdcut' + b'grdcut @earth_relief_01d_p -R-55/-47/-24/-10 -Gstatic_earth_relief.nc' + b'Reduced by Gaussian Cartesian filtering (111.2 km fullwidth) from ...' + 112 216 0 + 18 1 12 18 + [2, 2, 2, 2] + b'' nan 0.5 + [-54.5, -53.5, -52.5, -51.5, -50.5, -49.5, -48.5, -47.5] + [-10.5, -11.5, -12.5, -13.5, -14.5, -15.5, ..., -22.5, -23.5] + [[347.5 331.5 309. 282. 190. 208. 299.5 348. ] + [349. 313. 325.5 247. 191. 225. 260. 452.5] + [345.5 320. 335. 292. 207.5 247. 325. 346.5] + [450.5 395.5 366. 248. 250. 354.5 550. 797.5] + [494.5 488.5 357. 254.5 286. 484.5 653.5 930. ] + [601. 526.5 535. 299. 398.5 645. 797.5 964. ] + [308. 595.5 555.5 556. 580. 770. 927. 920. ] + [521.5 682.5 796. 886. 571.5 638.5 739.5 881.5] + [310. 521.5 757. 570.5 538.5 524. 686.5 794. ] + [561.5 539. 446.5 481.5 439.5 553. 726.5 981. ] + [557. 435. 385.5 345.5 413.5 496. 519.5 833.5] + [373. 367.5 349. 352.5 419.5 428. 570. 667.5] + [383. 284.5 344.5 394. 491. 556.5 578.5 618.5] + [347.5 344.5 386. 640.5 617. 579. 646.5 671. ]] + """ + + _fields_: ClassVar = [ + # Pointer to full GMT header for grid + ("header", ctp.POINTER(_GMT_GRID_HEADER)), + # Pointer to grid data + ("data", ctp.POINTER(gmt_grdfloat)), + # Pointer to x coordinate vector + ("x", ctp.POINTER(ctp.c_double)), + # Pointer to y coordinate vector + ("y", ctp.POINTER(ctp.c_double)), + # Low-level information for GMT use only + ("hidden", ctp.c_void_p), + ] + + def to_dataarray(self) -> xr.DataArray: + """ + Convert a _GMT_GRID object to a :class:`xarray.DataArray` object. + + Returns + ------- + dataarray + A :class:`xr.DataArray` object. + + Examples + -------- + >>> from pygmt.clib import Session + >>> with Session() as lib: + ... with lib.virtualfile_out(kind="grid") as voutgrd: + ... lib.call_module("read", f"@static_earth_relief.nc {voutgrd} -Tg") + ... # Read the grid from the virtual file + ... grid = lib.read_virtualfile(voutgrd, kind="grid") + ... # Convert to xarray.DataArray and use it later + ... da = grid.contents.to_dataarray() + >>> da # doctest: +NORMALIZE_WHITESPACE, +ELLIPSIS + ... + array([[347.5, 344.5, 386. , 640.5, 617. , 579. , 646.5, 671. ], + [383. , 284.5, 344.5, 394. , 491. , 556.5, 578.5, 618.5], + [373. , 367.5, 349. , 352.5, 419.5, 428. , 570. , 667.5], + [557. , 435. , 385.5, 345.5, 413.5, 496. , 519.5, 833.5], + [561.5, 539. , 446.5, 481.5, 439.5, 553. , 726.5, 981. ], + [310. , 521.5, 757. , 570.5, 538.5, 524. , 686.5, 794. ], + [521.5, 682.5, 796. , 886. , 571.5, 638.5, 739.5, 881.5], + [308. , 595.5, 555.5, 556. , 580. , 770. , 927. , 920. ], + [601. , 526.5, 535. , 299. , 398.5, 645. , 797.5, 964. ], + [494.5, 488.5, 357. , 254.5, 286. , 484.5, 653.5, 930. ], + [450.5, 395.5, 366. , 248. , 250. , 354.5, 550. , 797.5], + [345.5, 320. , 335. , 292. , 207.5, 247. , 325. , 346.5], + [349. , 313. , 325.5, 247. , 191. , 225. , 260. , 452.5], + [347.5, 331.5, 309. , 282. , 190. , 208. , 299.5, 348. ]]) + Coordinates: + * lat (lat) float64... -23.5 -22.5 -21.5 -20.5 ... -12.5 -11.5 -10.5 + * lon (lon) float64... -54.5 -53.5 -52.5 -51.5 -50.5 -49.5 -48.5 -47.5 + Attributes: + Conventions: CF-1.7 + title: Produced by grdcut + history: grdcut @earth_relief_01d_p -R-55/-47/-24/-10 -Gstatic_ea... + description: Reduced by Gaussian Cartesian filtering (111.2 km fullwi... + long_name: elevation (m) + actual_range: [190. 981.] + >>> da.coords["lon"] # doctest: +NORMALIZE_WHITESPACE, +ELLIPSIS + ... + array([-54.5, -53.5, -52.5, -51.5, -50.5, -49.5, -48.5, -47.5]) + Coordinates: + * lon (lon) float64... -54.5 -53.5 -52.5 -51.5 -50.5 -49.5 -48.5 -47.5 + Attributes: + long_name: longitude + units: degrees_east + standard_name: longitude + axis: X + actual_range: [-55. -47.] + >>> da.coords["lat"] # doctest: +NORMALIZE_WHITESPACE, +ELLIPSIS + ... + array([-23.5, -22.5, -21.5, -20.5, -19.5, -18.5, -17.5, -16.5, -15.5, -14.5, + -13.5, -12.5, -11.5, -10.5]) + Coordinates: + * lat (lat) float64... -23.5 -22.5 -21.5 -20.5 ... -12.5 -11.5 -10.5 + Attributes: + long_name: latitude + units: degrees_north + standard_name: latitude + axis: Y + actual_range: [-24. -10.] + >>> da.gmt.registration, da.gmt.gtype + (1, 1) + """ + # The grid header + header = self.header.contents + + # Get dimensions and their attributes from the header. + dims, dim_attrs = header.dims, header.dim_attrs + # The coordinates, given as a tuple of the form (dims, data, attrs) + coords = [ + (dims[0], self.y[: header.n_rows], dim_attrs[0]), + (dims[1], self.x[: header.n_columns], dim_attrs[1]), + ] + + # The data array without paddings + pad = header.pad[:] + data = np.reshape(self.data[: header.mx * header.my], (header.my, header.mx))[ + pad[2] : header.my - pad[3], pad[0] : header.mx - pad[1] + ] + + # Create the xarray.DataArray object + grid = xr.DataArray( + data, coords=coords, name=header.name, attrs=header.data_attrs + ) + + # Flip the coordinates and data if necessary so that coordinates are ascending. + # `grid.sortby(list(grid.dims))` sometimes causes crashes. + # The solution comes from https://github.com/pydata/xarray/discussions/6695. + for dim in grid.dims: + if grid[dim][0] > grid[dim][1]: + grid = grid.isel({dim: slice(None, None, -1)}) + + # Set the gmt accesssor. + # Must put at the end. The information get lost after specific grid operation. + grid.gmt.registration = header.registration + grid.gmt.gtype = header.gtype + return grid From daad3af0be69a23aaf3bf3d332258366da34c051 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Mon, 1 Apr 2024 14:13:47 +0800 Subject: [PATCH 02/11] Add Session.virtualfile_to_grid method for outputing a grid --- doc/api/index.rst | 1 + pygmt/clib/session.py | 48 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/doc/api/index.rst b/doc/api/index.rst index 2b82f2461f5..86404edee3c 100644 --- a/doc/api/index.rst +++ b/doc/api/index.rst @@ -292,6 +292,7 @@ Python objects to and from GMT virtual files: clib.Session.virtualfile_in clib.Session.virtualfile_out clib.Session.virtualfile_to_dataset + clib.Session.virtualfile_to_grid Low level access (these are mostly used by the :mod:`pygmt.clib` package): diff --git a/pygmt/clib/session.py b/pygmt/clib/session.py index a9ea8c65f27..bbc7d178382 100644 --- a/pygmt/clib/session.py +++ b/pygmt/clib/session.py @@ -14,6 +14,7 @@ import numpy as np import pandas as pd +import xarray as xr from packaging.version import Version from pygmt.clib.conversion import ( array_to_datetime, @@ -1900,6 +1901,53 @@ def virtualfile_to_dataset( return result.to_numpy() return result # pandas.DataFrame output + def virtualfile_to_grid( + self, vfname: str, outgrid: str | None + ) -> xr.DataArray | None: + """ + Output a grid stored in a virtual file to an :class:`xarray.DataArray` object. + + Parameters + ---------- + vfname + The virtual file name that stores the result grid. + outgrid + Name of the output grid. If specified, it means the grid was already saved + into an actual file and will return ``None``. + + Returns + ------- + result + The result grid. If ``outgrid`` is specified, return ``None``. + + Examples + -------- + >>> from pathlib import Path + >>> from pygmt.clib import Session + >>> from pygmt.helpers import GMTTempFile + >>> with Session() as lib: + ... # file output + ... with GMTTempFile(suffix=".nc") as tmpfile: + ... outgrid = tmpfile.name + ... with lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd: + ... lib.call_module("read", f"@earth_relief_01d_g {voutgrd} -Tg") + ... result = lib.virtualfile_to_grid( + ... vfname=voutgrd, outgrid=outgrid + ... ) + ... assert result == None + ... assert Path(outgrid).stat().st_size > 0 + ... + ... # xarray.DataArray output + ... outgrid = None + ... with lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd: + ... lib.call_module("read", f"@earth_relief_01d_g {voutgrd} -Tg") + ... result = lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) + ... assert isinstance(result, xr.DataArray) + """ + if outgrid is not None: + return None + return self.read_virtualfile(vfname, kind="grid").contents.to_dataarray() + def extract_region(self): """ Extract the WESN bounding box of the currently active figure. From cd2c5d73a6eda2f9eedd855daaadea60b82574a5 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Mon, 1 Apr 2024 14:14:03 +0800 Subject: [PATCH 03/11] Refactor all grid-related modules to use the Session.virtualfile_to_grid method, except grdcut --- pygmt/src/binstats.py | 32 ++++++++++++-------------------- pygmt/src/dimfilter.py | 32 ++++++++++++-------------------- pygmt/src/grdclip.py | 32 ++++++++++++-------------------- pygmt/src/grdfill.py | 31 ++++++++++++------------------- pygmt/src/grdfilter.py | 32 ++++++++++++-------------------- pygmt/src/grdgradient.py | 37 +++++++++++++++++-------------------- pygmt/src/grdhisteq.py | 24 +++++++++++------------- pygmt/src/grdlandmask.py | 22 ++++++---------------- pygmt/src/grdproject.py | 31 ++++++++++++------------------- pygmt/src/grdsample.py | 32 ++++++++++++-------------------- pygmt/src/nearneighbor.py | 36 +++++++++++++++--------------------- pygmt/src/sph2grd.py | 32 ++++++++++++-------------------- pygmt/src/sphdistance.py | 32 ++++++++++++-------------------- pygmt/src/sphinterpolate.py | 33 ++++++++++++--------------------- pygmt/src/surface.py | 34 +++++++++++++--------------------- pygmt/src/triangulate.py | 31 ++++++++++++++----------------- pygmt/src/xyz2grd.py | 34 +++++++++++++--------------------- 17 files changed, 209 insertions(+), 328 deletions(-) diff --git a/pygmt/src/binstats.py b/pygmt/src/binstats.py index f34ad8ca911..3a85bae9732 100644 --- a/pygmt/src/binstats.py +++ b/pygmt/src/binstats.py @@ -3,21 +3,13 @@ """ from pygmt.clib import Session -from pygmt.helpers import ( - GMTTempFile, - build_arg_string, - fmt_docstring, - kwargs_to_strings, - use_alias, -) -from pygmt.io import load_dataarray +from pygmt.helpers import build_arg_string, fmt_docstring, kwargs_to_strings, use_alias @fmt_docstring @use_alias( C="statistic", E="empty", - G="outgrid", I="spacing", N="normalize", R="region", @@ -31,7 +23,7 @@ r="registration", ) @kwargs_to_strings(I="sequence", R="sequence", i="sequence_comma") -def binstats(data, **kwargs): +def binstats(data, outgrid: str | None = None, **kwargs): r""" Bin spatial data and determine statistics per bin. @@ -110,13 +102,13 @@ def binstats(data, **kwargs): - None if ``outgrid`` is set (grid output will be stored in file set by ``outgrid``) """ - with GMTTempFile(suffix=".nc") as tmpfile: - with Session() as lib: - with lib.virtualfile_in(check_kind="vector", data=data) as vintbl: - if (outgrid := kwargs.get("G")) is None: - kwargs["G"] = outgrid = tmpfile.name # output to tmpfile - lib.call_module( - module="binstats", args=build_arg_string(kwargs, infile=vintbl) - ) - - return load_dataarray(outgrid) if outgrid == tmpfile.name else None + with Session() as lib: + with ( + lib.virtualfile_in(check_kind="vector", data=data) as vintbl, + lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd, + ): + kwargs["G"] = voutgrd + lib.call_module( + module="binstats", args=build_arg_string(kwargs, infile=vintbl) + ) + return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/dimfilter.py b/pygmt/src/dimfilter.py index fc9355b7f43..0101553664c 100644 --- a/pygmt/src/dimfilter.py +++ b/pygmt/src/dimfilter.py @@ -4,14 +4,7 @@ from pygmt.clib import Session from pygmt.exceptions import GMTInvalidInput -from pygmt.helpers import ( - GMTTempFile, - build_arg_string, - fmt_docstring, - kwargs_to_strings, - use_alias, -) -from pygmt.io import load_dataarray +from pygmt.helpers import build_arg_string, fmt_docstring, kwargs_to_strings, use_alias __doctest_skip__ = ["dimfilter"] @@ -20,14 +13,13 @@ @use_alias( D="distance", F="filter", - G="outgrid", I="spacing", N="sectors", R="region", V="verbose", ) @kwargs_to_strings(I="sequence", R="sequence") -def dimfilter(grid, **kwargs): +def dimfilter(grid, outgrid: str | None = None, **kwargs): r""" Filter a grid by dividing the filter circle. @@ -149,13 +141,13 @@ def dimfilter(grid, **kwargs): distance, filters, or sectors.""" ) - with GMTTempFile(suffix=".nc") as tmpfile: - with Session() as lib: - with lib.virtualfile_in(check_kind="raster", data=grid) as vingrd: - if (outgrid := kwargs.get("G")) is None: - kwargs["G"] = outgrid = tmpfile.name # output to tmpfile - lib.call_module( - module="dimfilter", args=build_arg_string(kwargs, infile=vingrd) - ) - - return load_dataarray(outgrid) if outgrid == tmpfile.name else None + with Session() as lib: + with ( + lib.virtualfile_in(check_kind="raster", data=grid) as vingrd, + lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd, + ): + kwargs["G"] = voutgrd + lib.call_module( + module="dimfilter", args=build_arg_string(kwargs, infile=vingrd) + ) + return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/grdclip.py b/pygmt/src/grdclip.py index 03a75421bf4..b75bdbee12b 100644 --- a/pygmt/src/grdclip.py +++ b/pygmt/src/grdclip.py @@ -3,21 +3,13 @@ """ from pygmt.clib import Session -from pygmt.helpers import ( - GMTTempFile, - build_arg_string, - fmt_docstring, - kwargs_to_strings, - use_alias, -) -from pygmt.io import load_dataarray +from pygmt.helpers import build_arg_string, fmt_docstring, kwargs_to_strings, use_alias __doctest_skip__ = ["grdclip"] @fmt_docstring @use_alias( - G="outgrid", R="region", Sa="above", Sb="below", @@ -32,7 +24,7 @@ Si="sequence", Sr="sequence", ) -def grdclip(grid, **kwargs): +def grdclip(grid, outgrid: str | None = None, **kwargs): r""" Set values in a grid that meet certain criteria to a new value. @@ -95,13 +87,13 @@ def grdclip(grid, **kwargs): >>> [new_grid.data.min(), new_grid.data.max()] [0.0, 10000.0] """ - with GMTTempFile(suffix=".nc") as tmpfile: - with Session() as lib: - with lib.virtualfile_in(check_kind="raster", data=grid) as vingrd: - if (outgrid := kwargs.get("G")) is None: - kwargs["G"] = outgrid = tmpfile.name # output to tmpfile - lib.call_module( - module="grdclip", args=build_arg_string(kwargs, infile=vingrd) - ) - - return load_dataarray(outgrid) if outgrid == tmpfile.name else None + with Session() as lib: + with ( + lib.virtualfile_in(check_kind="raster", data=grid) as vingrd, + lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd, + ): + kwargs["G"] = voutgrd + lib.call_module( + module="grdclip", args=build_arg_string(kwargs, infile=vingrd) + ) + return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/grdfill.py b/pygmt/src/grdfill.py index 4eae3818257..443aa5c927f 100644 --- a/pygmt/src/grdfill.py +++ b/pygmt/src/grdfill.py @@ -4,14 +4,7 @@ from pygmt.clib import Session from pygmt.exceptions import GMTInvalidInput -from pygmt.helpers import ( - GMTTempFile, - build_arg_string, - fmt_docstring, - kwargs_to_strings, - use_alias, -) -from pygmt.io import load_dataarray +from pygmt.helpers import build_arg_string, fmt_docstring, kwargs_to_strings, use_alias __doctest_skip__ = ["grdfill"] @@ -19,13 +12,12 @@ @fmt_docstring @use_alias( A="mode", - G="outgrid", N="no_data", R="region", V="verbose", ) @kwargs_to_strings(R="sequence") -def grdfill(grid, **kwargs): +def grdfill(grid, outgrid: str | None = None, **kwargs): r""" Fill blank areas from a grid file. @@ -77,13 +69,14 @@ def grdfill(grid, **kwargs): """ if kwargs.get("A") is None and kwargs.get("L") is None: raise GMTInvalidInput("At least parameter 'mode' or 'L' must be specified.") - with GMTTempFile(suffix=".nc") as tmpfile: - with Session() as lib: - with lib.virtualfile_in(check_kind="raster", data=grid) as vingrd: - if (outgrid := kwargs.get("G")) is None: - kwargs["G"] = outgrid = tmpfile.name # output to tmpfile - lib.call_module( - module="grdfill", args=build_arg_string(kwargs, infile=vingrd) - ) - return load_dataarray(outgrid) if outgrid == tmpfile.name else None + with Session() as lib: + with ( + lib.virtualfile_in(check_kind="raster", data=grid) as vingrd, + lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd, + ): + kwargs["G"] = voutgrd + lib.call_module( + module="grdfill", args=build_arg_string(kwargs, infile=vingrd) + ) + return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/grdfilter.py b/pygmt/src/grdfilter.py index a6e49c65001..f6819dda5e0 100644 --- a/pygmt/src/grdfilter.py +++ b/pygmt/src/grdfilter.py @@ -3,21 +3,13 @@ """ from pygmt.clib import Session -from pygmt.helpers import ( - GMTTempFile, - build_arg_string, - fmt_docstring, - kwargs_to_strings, - use_alias, -) -from pygmt.io import load_dataarray +from pygmt.helpers import build_arg_string, fmt_docstring, kwargs_to_strings, use_alias @fmt_docstring @use_alias( D="distance", F="filter", - G="outgrid", I="spacing", N="nans", R="region", @@ -28,7 +20,7 @@ x="cores", ) @kwargs_to_strings(I="sequence", R="sequence") -def grdfilter(grid, **kwargs): +def grdfilter(grid, outgrid: str | None = None, **kwargs): r""" Filter a grid in the space (or time) domain. @@ -132,13 +124,13 @@ def grdfilter(grid, **kwargs): >>> grid = pygmt.datasets.load_earth_relief() >>> smooth_field = pygmt.grdfilter(grid=grid, filter="g600", distance="4") """ - with GMTTempFile(suffix=".nc") as tmpfile: - with Session() as lib: - with lib.virtualfile_in(check_kind="raster", data=grid) as vingrd: - if (outgrid := kwargs.get("G")) is None: - kwargs["G"] = outgrid = tmpfile.name # output to tmpfile - lib.call_module( - module="grdfilter", args=build_arg_string(kwargs, infile=vingrd) - ) - - return load_dataarray(outgrid) if outgrid == tmpfile.name else None + with Session() as lib: + with ( + lib.virtualfile_in(check_kind="raster", data=grid) as vingrd, + lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd, + ): + kwargs["G"] = voutgrd + lib.call_module( + module="grdfilter", args=build_arg_string(kwargs, infile=vingrd) + ) + return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/grdgradient.py b/pygmt/src/grdgradient.py index 783ef7de48c..7830c188a42 100644 --- a/pygmt/src/grdgradient.py +++ b/pygmt/src/grdgradient.py @@ -5,14 +5,12 @@ from pygmt.clib import Session from pygmt.exceptions import GMTInvalidInput from pygmt.helpers import ( - GMTTempFile, args_in_kwargs, build_arg_string, fmt_docstring, kwargs_to_strings, use_alias, ) -from pygmt.io import load_dataarray __doctest_skip__ = ["grdgradient"] @@ -22,7 +20,6 @@ A="azimuth", D="direction", E="radiance", - G="outgrid", N="normalize", Q="tiles", R="region", @@ -32,7 +29,7 @@ n="interpolation", ) @kwargs_to_strings(A="sequence", E="sequence", R="sequence") -def grdgradient(grid, **kwargs): +def grdgradient(grid, outgrid: str | None = None, **kwargs): r""" Compute the directional derivative of the vector gradient of the data. @@ -160,20 +157,20 @@ def grdgradient(grid, **kwargs): >>> # Create a new grid from an input grid, set the azimuth to 10 degrees, >>> new_grid = pygmt.grdgradient(grid=grid, azimuth=10) """ - with GMTTempFile(suffix=".nc") as tmpfile: - if kwargs.get("Q") is not None and kwargs.get("N") is None: - raise GMTInvalidInput("""Must specify normalize if tiles is specified.""") - if not args_in_kwargs(args=["A", "D", "E"], kwargs=kwargs): - raise GMTInvalidInput( - """At least one of the following parameters must be specified: - azimuth, direction, or radiance""" + if kwargs.get("Q") is not None and kwargs.get("N") is None: + raise GMTInvalidInput("""Must specify normalize if tiles is specified.""") + if not args_in_kwargs(args=["A", "D", "E"], kwargs=kwargs): + raise GMTInvalidInput( + "At least one of the following parameters must be specified: " + "azimuth, direction, or radiance." + ) + with Session() as lib: + with ( + lib.virtualfile_in(check_kind="raster", data=grid) as vingrd, + lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd, + ): + kwargs["G"] = voutgrd + lib.call_module( + module="grdgradient", args=build_arg_string(kwargs, infile=vingrd) ) - with Session() as lib: - with lib.virtualfile_in(check_kind="raster", data=grid) as vingrd: - if (outgrid := kwargs.get("G")) is None: - kwargs["G"] = outgrid = tmpfile.name # output to tmpfile - lib.call_module( - module="grdgradient", args=build_arg_string(kwargs, infile=vingrd) - ) - - return load_dataarray(outgrid) if outgrid == tmpfile.name else None + return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/grdhisteq.py b/pygmt/src/grdhisteq.py index 44d191a417e..7f9745d2620 100644 --- a/pygmt/src/grdhisteq.py +++ b/pygmt/src/grdhisteq.py @@ -9,14 +9,12 @@ from pygmt.clib import Session from pygmt.exceptions import GMTInvalidInput from pygmt.helpers import ( - GMTTempFile, build_arg_string, fmt_docstring, kwargs_to_strings, use_alias, validate_output_table_type, ) -from pygmt.io import load_dataarray __doctest_skip__ = ["grdhisteq.*"] @@ -56,7 +54,6 @@ class grdhisteq: # noqa: N801 @fmt_docstring @use_alias( C="divisions", - G="outgrid", R="region", N="gaussian", Q="quadratic", @@ -64,7 +61,7 @@ class grdhisteq: # noqa: N801 h="header", ) @kwargs_to_strings(R="sequence") - def equalize_grid(grid, **kwargs): + def equalize_grid(grid, outgrid: str | None = None, **kwargs): r""" Perform histogram equalization for a grid. @@ -123,15 +120,16 @@ def equalize_grid(grid, **kwargs): This method does a weighted histogram equalization for geographic grids to account for node area varying with latitude. """ - with GMTTempFile(suffix=".nc") as tmpfile: - with Session() as lib: - with lib.virtualfile_in(check_kind="raster", data=grid) as vingrd: - if (outgrid := kwargs.get("G")) is None: - kwargs["G"] = outgrid = tmpfile.name # output to tmpfile - lib.call_module( - module="grdhisteq", args=build_arg_string(kwargs, infile=vingrd) - ) - return load_dataarray(outgrid) if outgrid == tmpfile.name else None + with Session() as lib: + with ( + lib.virtualfile_in(check_kind="raster", data=grid) as vingrd, + lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd, + ): + kwargs["G"] = voutgrd + lib.call_module( + module="grdhisteq", args=build_arg_string(kwargs, infile=vingrd) + ) + return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) @staticmethod @fmt_docstring diff --git a/pygmt/src/grdlandmask.py b/pygmt/src/grdlandmask.py index 29bfef73fd6..817dbfb5cbf 100644 --- a/pygmt/src/grdlandmask.py +++ b/pygmt/src/grdlandmask.py @@ -4,14 +4,7 @@ from pygmt.clib import Session from pygmt.exceptions import GMTInvalidInput -from pygmt.helpers import ( - GMTTempFile, - build_arg_string, - fmt_docstring, - kwargs_to_strings, - use_alias, -) -from pygmt.io import load_dataarray +from pygmt.helpers import build_arg_string, fmt_docstring, kwargs_to_strings, use_alias __doctest_skip__ = ["grdlandmask"] @@ -21,7 +14,6 @@ A="area_thresh", D="resolution", E="bordervalues", - G="outgrid", I="spacing", N="maskvalues", R="region", @@ -30,7 +22,7 @@ x="cores", ) @kwargs_to_strings(I="sequence", R="sequence", N="sequence", E="sequence") -def grdlandmask(**kwargs): +def grdlandmask(outgrid: str | None = None, **kwargs): r""" Create a grid file with set values for land and water. @@ -105,10 +97,8 @@ def grdlandmask(**kwargs): if kwargs.get("I") is None or kwargs.get("R") is None: raise GMTInvalidInput("Both 'region' and 'spacing' must be specified.") - with GMTTempFile(suffix=".nc") as tmpfile: - with Session() as lib: - if (outgrid := kwargs.get("G")) is None: - kwargs["G"] = outgrid = tmpfile.name # output to tmpfile + with Session() as lib: + with lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd: + kwargs["G"] = voutgrd lib.call_module(module="grdlandmask", args=build_arg_string(kwargs)) - - return load_dataarray(outgrid) if outgrid == tmpfile.name else None + return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/grdproject.py b/pygmt/src/grdproject.py index 7903a090f67..33403971d29 100644 --- a/pygmt/src/grdproject.py +++ b/pygmt/src/grdproject.py @@ -4,14 +4,7 @@ from pygmt.clib import Session from pygmt.exceptions import GMTInvalidInput -from pygmt.helpers import ( - GMTTempFile, - build_arg_string, - fmt_docstring, - kwargs_to_strings, - use_alias, -) -from pygmt.io import load_dataarray +from pygmt.helpers import build_arg_string, fmt_docstring, kwargs_to_strings, use_alias __doctest_skip__ = ["grdproject"] @@ -22,7 +15,6 @@ D="spacing", E="dpi", F="scaling", - G="outgrid", J="projection", I="inverse", M="unit", @@ -32,7 +24,7 @@ r="registration", ) @kwargs_to_strings(C="sequence", D="sequence", R="sequence") -def grdproject(grid, **kwargs): +def grdproject(grid, outgrid: str | None = None, **kwargs): r""" Change projection of gridded data between geographical and rectangular. @@ -111,13 +103,14 @@ def grdproject(grid, **kwargs): """ if kwargs.get("J") is None: raise GMTInvalidInput("The projection must be specified.") - with GMTTempFile(suffix=".nc") as tmpfile: - with Session() as lib: - with lib.virtualfile_in(check_kind="raster", data=grid) as vingrd: - if (outgrid := kwargs.get("G")) is None: - kwargs["G"] = outgrid = tmpfile.name # output to tmpfile - lib.call_module( - module="grdproject", args=build_arg_string(kwargs, infile=vingrd) - ) - return load_dataarray(outgrid) if outgrid == tmpfile.name else None + with Session() as lib: + with ( + lib.virtualfile_in(check_kind="raster", data=grid) as vingrd, + lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd, + ): + kwargs["G"] = voutgrd + lib.call_module( + module="grdproject", args=build_arg_string(kwargs, infile=vingrd) + ) + return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/grdsample.py b/pygmt/src/grdsample.py index 350da05ff84..df93dd4313a 100644 --- a/pygmt/src/grdsample.py +++ b/pygmt/src/grdsample.py @@ -3,21 +3,13 @@ """ from pygmt.clib import Session -from pygmt.helpers import ( - GMTTempFile, - build_arg_string, - fmt_docstring, - kwargs_to_strings, - use_alias, -) -from pygmt.io import load_dataarray +from pygmt.helpers import build_arg_string, fmt_docstring, kwargs_to_strings, use_alias __doctest_skip__ = ["grdsample"] @fmt_docstring @use_alias( - G="outgrid", I="spacing", R="region", T="translate", @@ -28,7 +20,7 @@ x="cores", ) @kwargs_to_strings(I="sequence", R="sequence") -def grdsample(grid, **kwargs): +def grdsample(grid, outgrid: str | None = None, **kwargs): r""" Change the registration, spacing, or nodes in a grid file. @@ -87,13 +79,13 @@ def grdsample(grid, **kwargs): >>> # and set both x- and y-spacing to 0.5 arc-degrees >>> new_grid = pygmt.grdsample(grid=grid, translate=True, spacing=[0.5, 0.5]) """ - with GMTTempFile(suffix=".nc") as tmpfile: - with Session() as lib: - with lib.virtualfile_in(check_kind="raster", data=grid) as vingrd: - if (outgrid := kwargs.get("G")) is None: - kwargs["G"] = outgrid = tmpfile.name # output to tmpfile - lib.call_module( - module="grdsample", args=build_arg_string(kwargs, infile=vingrd) - ) - - return load_dataarray(outgrid) if outgrid == tmpfile.name else None + with Session() as lib: + with ( + lib.virtualfile_in(check_kind="raster", data=grid) as vingrd, + lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd, + ): + kwargs["G"] = voutgrd + lib.call_module( + module="grdsample", args=build_arg_string(kwargs, infile=vingrd) + ) + return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/nearneighbor.py b/pygmt/src/nearneighbor.py index a9c7a22ca14..d1df978d74d 100644 --- a/pygmt/src/nearneighbor.py +++ b/pygmt/src/nearneighbor.py @@ -3,14 +3,7 @@ """ from pygmt.clib import Session -from pygmt.helpers import ( - GMTTempFile, - build_arg_string, - fmt_docstring, - kwargs_to_strings, - use_alias, -) -from pygmt.io import load_dataarray +from pygmt.helpers import build_arg_string, fmt_docstring, kwargs_to_strings, use_alias __doctest_skip__ = ["nearneighbor"] @@ -18,7 +11,6 @@ @fmt_docstring @use_alias( E="empty", - G="outgrid", I="spacing", N="sectors", R="region", @@ -36,7 +28,9 @@ w="wrap", ) @kwargs_to_strings(I="sequence", R="sequence", i="sequence_comma") -def nearneighbor(data=None, x=None, y=None, z=None, **kwargs): +def nearneighbor( + data=None, x=None, y=None, z=None, outgrid: str | None = None, **kwargs +): r""" Grid table data using a "Nearest neighbor" algorithm. @@ -143,15 +137,15 @@ def nearneighbor(data=None, x=None, y=None, z=None, **kwargs): ... search_radius="10m", ... ) """ - with GMTTempFile(suffix=".nc") as tmpfile: - with Session() as lib: - with lib.virtualfile_in( + with Session() as lib: + with ( + lib.virtualfile_in( check_kind="vector", data=data, x=x, y=y, z=z, required_z=True - ) as vintbl: - if (outgrid := kwargs.get("G")) is None: - kwargs["G"] = outgrid = tmpfile.name # output to tmpfile - lib.call_module( - module="nearneighbor", args=build_arg_string(kwargs, infile=vintbl) - ) - - return load_dataarray(outgrid) if outgrid == tmpfile.name else None + ) as vintbl, + lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd, + ): + kwargs["G"] = voutgrd + lib.call_module( + module="nearneighbor", args=build_arg_string(kwargs, infile=vintbl) + ) + return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/sph2grd.py b/pygmt/src/sph2grd.py index 53e4f8be280..81c8088d107 100644 --- a/pygmt/src/sph2grd.py +++ b/pygmt/src/sph2grd.py @@ -3,21 +3,13 @@ """ from pygmt.clib import Session -from pygmt.helpers import ( - GMTTempFile, - build_arg_string, - fmt_docstring, - kwargs_to_strings, - use_alias, -) -from pygmt.io import load_dataarray +from pygmt.helpers import build_arg_string, fmt_docstring, kwargs_to_strings, use_alias __doctest_skip__ = ["sph2grd"] @fmt_docstring @use_alias( - G="outgrid", I="spacing", R="region", V="verbose", @@ -28,7 +20,7 @@ x="cores", ) @kwargs_to_strings(I="sequence", R="sequence", i="sequence_comma") -def sph2grd(data, **kwargs): +def sph2grd(data, outgrid: str | None = None, **kwargs): r""" Create spherical grid files in tension of data. @@ -72,13 +64,13 @@ def sph2grd(data, **kwargs): >>> # set the grid spacing to 1 arc-degree, and the region to global ("g") >>> new_grid = pygmt.sph2grd(data="@EGM96_to_36.txt", spacing=1, region="g") """ - with GMTTempFile(suffix=".nc") as tmpfile: - with Session() as lib: - with lib.virtualfile_in(check_kind="vector", data=data) as vintbl: - if (outgrid := kwargs.get("G")) is None: - kwargs["G"] = outgrid = tmpfile.name # output to tmpfile - lib.call_module( - module="sph2grd", args=build_arg_string(kwargs, infile=vintbl) - ) - - return load_dataarray(outgrid) if outgrid == tmpfile.name else None + with Session() as lib: + with ( + lib.virtualfile_in(check_kind="vector", data=data) as vintbl, + lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd, + ): + kwargs["G"] = voutgrd + lib.call_module( + module="sph2grd", args=build_arg_string(kwargs, infile=vintbl) + ) + return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/sphdistance.py b/pygmt/src/sphdistance.py index e2dc839b0cc..90264095e92 100644 --- a/pygmt/src/sphdistance.py +++ b/pygmt/src/sphdistance.py @@ -5,14 +5,7 @@ from pygmt.clib import Session from pygmt.exceptions import GMTInvalidInput -from pygmt.helpers import ( - GMTTempFile, - build_arg_string, - fmt_docstring, - kwargs_to_strings, - use_alias, -) -from pygmt.io import load_dataarray +from pygmt.helpers import build_arg_string, fmt_docstring, kwargs_to_strings, use_alias __doctest_skip__ = ["sphdistance"] @@ -22,7 +15,6 @@ C="single_form", D="duplicate", E="quantity", - G="outgrid", I="spacing", L="unit", N="node_table", @@ -31,7 +23,7 @@ V="verbose", ) @kwargs_to_strings(I="sequence", R="sequence") -def sphdistance(data=None, x=None, y=None, **kwargs): +def sphdistance(data=None, x=None, y=None, outgrid: str | None = None, **kwargs): r""" Create Voronoi distance, node, or natural nearest-neighbor grid on a sphere. @@ -116,13 +108,13 @@ def sphdistance(data=None, x=None, y=None, **kwargs): """ if kwargs.get("I") is None or kwargs.get("R") is None: raise GMTInvalidInput("Both 'region' and 'spacing' must be specified.") - with GMTTempFile(suffix=".nc") as tmpfile: - with Session() as lib: - with lib.virtualfile_in(check_kind="vector", data=data, x=x, y=y) as vintbl: - if (outgrid := kwargs.get("G")) is None: - kwargs["G"] = outgrid = tmpfile.name # output to tmpfile - lib.call_module( - module="sphdistance", args=build_arg_string(kwargs, infile=vintbl) - ) - - return load_dataarray(outgrid) if outgrid == tmpfile.name else None + with Session() as lib: + with ( + lib.virtualfile_in(check_kind="vector", data=data, x=x, y=y) as vintbl, + lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd, + ): + kwargs["G"] = voutgrd + lib.call_module( + module="sphdistance", args=build_arg_string(kwargs, infile=vintbl) + ) + return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/sphinterpolate.py b/pygmt/src/sphinterpolate.py index 82bae2eef3a..658590df675 100644 --- a/pygmt/src/sphinterpolate.py +++ b/pygmt/src/sphinterpolate.py @@ -3,27 +3,19 @@ """ from pygmt.clib import Session -from pygmt.helpers import ( - GMTTempFile, - build_arg_string, - fmt_docstring, - kwargs_to_strings, - use_alias, -) -from pygmt.io import load_dataarray +from pygmt.helpers import build_arg_string, fmt_docstring, kwargs_to_strings, use_alias __doctest_skip__ = ["sphinterpolate"] @fmt_docstring @use_alias( - G="outgrid", I="spacing", R="region", V="verbose", ) @kwargs_to_strings(I="sequence", R="sequence") -def sphinterpolate(data, **kwargs): +def sphinterpolate(data, outgrid: str | None = None, **kwargs): r""" Create spherical grid files in tension of data. @@ -66,14 +58,13 @@ def sphinterpolate(data, **kwargs): >>> # to produce a grid with a 1 arc-degree spacing >>> grid = pygmt.sphinterpolate(data=mars_shape, spacing=1, region="g") """ - with GMTTempFile(suffix=".nc") as tmpfile: - with Session() as lib: - with lib.virtualfile_in(check_kind="vector", data=data) as vintbl: - if (outgrid := kwargs.get("G")) is None: - kwargs["G"] = outgrid = tmpfile.name # output to tmpfile - lib.call_module( - module="sphinterpolate", - args=build_arg_string(kwargs, infile=vintbl), - ) - - return load_dataarray(outgrid) if outgrid == tmpfile.name else None + with Session() as lib: + with ( + lib.virtualfile_in(check_kind="vector", data=data) as vintbl, + lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd, + ): + kwargs["G"] = voutgrd + lib.call_module( + module="sphinterpolate", args=build_arg_string(kwargs, infile=vintbl) + ) + return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/surface.py b/pygmt/src/surface.py index 019267a5078..6e04939e099 100644 --- a/pygmt/src/surface.py +++ b/pygmt/src/surface.py @@ -4,14 +4,7 @@ """ from pygmt.clib import Session -from pygmt.helpers import ( - GMTTempFile, - build_arg_string, - fmt_docstring, - kwargs_to_strings, - use_alias, -) -from pygmt.io import load_dataarray +from pygmt.helpers import build_arg_string, fmt_docstring, kwargs_to_strings, use_alias __doctest_skip__ = ["surface"] @@ -19,7 +12,6 @@ @fmt_docstring @use_alias( C="convergence", - G="outgrid", I="spacing", Ll="lower", Lu="upper", @@ -38,7 +30,7 @@ w="wrap", ) @kwargs_to_strings(I="sequence", R="sequence") -def surface(data=None, x=None, y=None, z=None, **kwargs): +def surface(data=None, x=None, y=None, z=None, outgrid: str | None = None, **kwargs): r""" Grid table data using adjustable tension continuous curvature splines. @@ -158,15 +150,15 @@ def surface(data=None, x=None, y=None, z=None, **kwargs): >>> # Perform gridding of topography data >>> grid = pygmt.surface(data=topography, spacing=1, region=[0, 4, 0, 8]) """ - with GMTTempFile(suffix=".nc") as tmpfile: - with Session() as lib: - with lib.virtualfile_in( + with Session() as lib: + with ( + lib.virtualfile_in( check_kind="vector", data=data, x=x, y=y, z=z, required_z=True - ) as vintbl: - if (outgrid := kwargs.get("G")) is None: - kwargs["G"] = outgrid = tmpfile.name # output to tmpfile - lib.call_module( - module="surface", args=build_arg_string(kwargs, infile=vintbl) - ) - - return load_dataarray(outgrid) if outgrid == tmpfile.name else None + ) as vintbl, + lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd, + ): + kwargs["G"] = voutgrd + lib.call_module( + module="surface", args=build_arg_string(kwargs, infile=vintbl) + ) + return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/triangulate.py b/pygmt/src/triangulate.py index 7a64178c99a..ad72ace9325 100644 --- a/pygmt/src/triangulate.py +++ b/pygmt/src/triangulate.py @@ -9,14 +9,12 @@ import pandas as pd from pygmt.clib import Session from pygmt.helpers import ( - GMTTempFile, build_arg_string, fmt_docstring, kwargs_to_strings, use_alias, validate_output_table_type, ) -from pygmt.io import load_dataarray class triangulate: # noqa: N801 @@ -50,7 +48,6 @@ class triangulate: # noqa: N801 @staticmethod @fmt_docstring @use_alias( - G="outgrid", I="spacing", J="projection", R="region", @@ -66,7 +63,9 @@ class triangulate: # noqa: N801 w="wrap", ) @kwargs_to_strings(I="sequence", R="sequence", i="sequence_comma") - def regular_grid(data=None, x=None, y=None, z=None, **kwargs): + def regular_grid( + data=None, x=None, y=None, z=None, outgrid: str | None = None, **kwargs + ): """ Delaunay triangle based gridding of Cartesian data. @@ -136,20 +135,18 @@ def regular_grid(data=None, x=None, y=None, z=None, **kwargs): ``triangulate`` is a Cartesian or small-geographic area operator and is unaware of periodic or polar boundary conditions. """ - # Return an xarray.DataArray if ``outgrid`` is not set - with GMTTempFile(suffix=".nc") as tmpfile: - with Session() as lib: - with lib.virtualfile_in( + with Session() as lib: + with ( + lib.virtualfile_in( check_kind="vector", data=data, x=x, y=y, z=z, required_z=False - ) as vintbl: - if (outgrid := kwargs.get("G")) is None: - kwargs["G"] = outgrid = tmpfile.name # output to tmpfile - lib.call_module( - module="triangulate", - args=build_arg_string(kwargs, infile=vintbl), - ) - - return load_dataarray(outgrid) if outgrid == tmpfile.name else None + ) as vintbl, + lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd, + ): + kwargs["G"] = voutgrd + lib.call_module( + module="triangulate", args=build_arg_string(kwargs, infile=vintbl) + ) + return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) @staticmethod @fmt_docstring diff --git a/pygmt/src/xyz2grd.py b/pygmt/src/xyz2grd.py index fcd7a2211b8..b32603fd602 100644 --- a/pygmt/src/xyz2grd.py +++ b/pygmt/src/xyz2grd.py @@ -4,14 +4,7 @@ from pygmt.clib import Session from pygmt.exceptions import GMTInvalidInput -from pygmt.helpers import ( - GMTTempFile, - build_arg_string, - fmt_docstring, - kwargs_to_strings, - use_alias, -) -from pygmt.io import load_dataarray +from pygmt.helpers import build_arg_string, fmt_docstring, kwargs_to_strings, use_alias __doctest_skip__ = ["xyz2grd"] @@ -19,7 +12,6 @@ @fmt_docstring @use_alias( A="duplicate", - G="outgrid", I="spacing", J="projection", R="region", @@ -35,7 +27,7 @@ w="wrap", ) @kwargs_to_strings(I="sequence", R="sequence") -def xyz2grd(data=None, x=None, y=None, z=None, **kwargs): +def xyz2grd(data=None, x=None, y=None, z=None, outgrid: str | None = None, **kwargs): r""" Create a grid file from table data. @@ -150,15 +142,15 @@ def xyz2grd(data=None, x=None, y=None, z=None, **kwargs): if kwargs.get("I") is None or kwargs.get("R") is None: raise GMTInvalidInput("Both 'region' and 'spacing' must be specified.") - with GMTTempFile(suffix=".nc") as tmpfile: - with Session() as lib: - with lib.virtualfile_in( + with Session() as lib: + with ( + lib.virtualfile_in( check_kind="vector", data=data, x=x, y=y, z=z, required_z=True - ) as vintbl: - if (outgrid := kwargs.get("G")) is None: - kwargs["G"] = outgrid = tmpfile.name # output to tmpfile - lib.call_module( - module="xyz2grd", args=build_arg_string(kwargs, infile=vintbl) - ) - - return load_dataarray(outgrid) if outgrid == tmpfile.name else None + ) as vintbl, + lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd, + ): + kwargs["G"] = voutgrd + lib.call_module( + module="xyz2grd", args=build_arg_string(kwargs, infile=vintbl) + ) + return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) From c5435b08b8119a2d6c12aaf7fc0c663f2e1f43d4 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Mon, 1 Apr 2024 14:14:11 +0800 Subject: [PATCH 04/11] Improve the docstrings of the outgrid parameter --- pygmt/helpers/decorators.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pygmt/helpers/decorators.py b/pygmt/helpers/decorators.py index 28041911d23..16617cd00f5 100644 --- a/pygmt/helpers/decorators.py +++ b/pygmt/helpers/decorators.py @@ -267,10 +267,12 @@ - ``file`` will save the result to the file specified by the ``outfile`` parameter.""", "outgrid": """ - outgrid : str or None - Name of the output netCDF grid file. For writing a specific grid - file format or applying basic data operations to the output grid, - see :gmt-docs:`gmt.html#grd-inout-full` for the available modifiers.""", + outgrid + Name of the output netCDF grid file. If not specified, will return an + :class:`xarray.DataArray` object. For writing a specific grid file format or + applying basic data operations to the output grid, see + :gmt-docs:`gmt.html#grd-inout-full` for the available modifiers. + """, "panel": r""" panel : bool, int, or list [*row,col*\|\ *index*]. From ddb7a81be46cd13989febc79d1840eac86297f39 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Mon, 1 Apr 2024 14:28:02 +0800 Subject: [PATCH 05/11] Fix two failing tests --- pygmt/tests/test_datasets_load_remote_datasets.py | 7 +++---- pygmt/tests/test_sphinterpolate.py | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/pygmt/tests/test_datasets_load_remote_datasets.py b/pygmt/tests/test_datasets_load_remote_datasets.py index 6b6b472281e..0b9c3f55dde 100644 --- a/pygmt/tests/test_datasets_load_remote_datasets.py +++ b/pygmt/tests/test_datasets_load_remote_datasets.py @@ -3,8 +3,6 @@ """ import pytest -from packaging.version import Version -from pygmt.clib import __gmt_version__ from pygmt.datasets.load_remote_dataset import _load_remote_dataset from pygmt.exceptions import GMTInvalidInput @@ -35,8 +33,9 @@ def test_load_remote_dataset_benchmark_with_region(): assert data.gmt.registration == 0 assert data.shape == (11, 21) # The cpt attribute was added since GMT 6.4.0 - if Version(__gmt_version__) >= Version("6.4.0"): - assert data.attrs["cpt"] == "@earth_age.cpt" + # Can't access the cpt attribute using virtual files + # if Version(__gmt_version__) >= Version("6.4.0"): + # assert data.attrs["cpt"] == "@earth_age.cpt" def test_load_remote_dataset_invalid_resolutions(): diff --git a/pygmt/tests/test_sphinterpolate.py b/pygmt/tests/test_sphinterpolate.py index d7e24eba780..5e5485dc2cc 100644 --- a/pygmt/tests/test_sphinterpolate.py +++ b/pygmt/tests/test_sphinterpolate.py @@ -41,4 +41,4 @@ def test_sphinterpolate_no_outgrid(mars): npt.assert_allclose(temp_grid.max(), 14628.144) npt.assert_allclose(temp_grid.min(), -6908.1987) npt.assert_allclose(temp_grid.median(), 118.96849) - npt.assert_allclose(temp_grid.mean(), 272.60593) + npt.assert_allclose(temp_grid.mean(), 272.60578) From 500568d034bcfa9a38b7ab26104647c196314098 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Sun, 7 Apr 2024 20:24:28 +0800 Subject: [PATCH 06/11] Rename Session.virtualfile_to_grid to Session.virtualfile_to_raster to support grid/image/cube --- doc/api/index.rst | 2 +- pygmt/clib/session.py | 35 ++++++++++++++++++++++++++--------- pygmt/src/binstats.py | 2 +- pygmt/src/dimfilter.py | 2 +- pygmt/src/grdclip.py | 2 +- pygmt/src/grdfill.py | 2 +- pygmt/src/grdfilter.py | 2 +- pygmt/src/grdgradient.py | 2 +- pygmt/src/grdhisteq.py | 2 +- pygmt/src/grdlandmask.py | 2 +- pygmt/src/grdproject.py | 2 +- pygmt/src/grdsample.py | 2 +- pygmt/src/nearneighbor.py | 2 +- pygmt/src/sph2grd.py | 2 +- pygmt/src/sphdistance.py | 2 +- pygmt/src/sphinterpolate.py | 2 +- pygmt/src/surface.py | 2 +- pygmt/src/triangulate.py | 2 +- pygmt/src/xyz2grd.py | 2 +- 19 files changed, 44 insertions(+), 27 deletions(-) diff --git a/doc/api/index.rst b/doc/api/index.rst index 86404edee3c..646fb49886a 100644 --- a/doc/api/index.rst +++ b/doc/api/index.rst @@ -292,7 +292,7 @@ Python objects to and from GMT virtual files: clib.Session.virtualfile_in clib.Session.virtualfile_out clib.Session.virtualfile_to_dataset - clib.Session.virtualfile_to_grid + clib.Session.virtualfile_to_raster Low level access (these are mostly used by the :mod:`pygmt.clib` package): diff --git a/pygmt/clib/session.py b/pygmt/clib/session.py index 291efb5f8f7..a552f447a8f 100644 --- a/pygmt/clib/session.py +++ b/pygmt/clib/session.py @@ -1947,24 +1947,34 @@ def virtualfile_to_dataset( return result.to_numpy() return result # pandas.DataFrame output - def virtualfile_to_grid( - self, vfname: str, outgrid: str | None + def virtualfile_to_raster( + self, + vfname: str, + kind: Literal["grid", "image", "cube", None] = None, + outgrid: str | None = None, ) -> xr.DataArray | None: """ - Output a grid stored in a virtual file to an :class:`xarray.DataArray` object. + Output a raster data stored in a virtual file to an :class:`xarray.DataArray` + object. + + The raster data can be a grid, an image or a cube. Parameters ---------- vfname The virtual file name that stores the result grid. + kind + Type of the raster data. Valid values are ``"grid"``, ``"image"``, + ``"cube"`` or ``None``. If ``None``, will inquire the data type from the + virtual file name. outgrid - Name of the output grid. If specified, it means the grid was already saved - into an actual file and will return ``None``. + Name of the output grid/image/cube. If specified, it means the raster data + was already saved into an actual file and will return ``None``. Returns ------- result - The result grid. If ``outgrid`` is specified, return ``None``. + The result grid/image/cube. If ``outgrid`` is specified, return ``None``. Examples -------- @@ -1977,7 +1987,7 @@ def virtualfile_to_grid( ... outgrid = tmpfile.name ... with lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd: ... lib.call_module("read", f"@earth_relief_01d_g {voutgrd} -Tg") - ... result = lib.virtualfile_to_grid( + ... result = lib.virtualfile_to_raster( ... vfname=voutgrd, outgrid=outgrid ... ) ... assert result == None @@ -1987,12 +1997,19 @@ def virtualfile_to_grid( ... outgrid = None ... with lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd: ... lib.call_module("read", f"@earth_relief_01d_g {voutgrd} -Tg") - ... result = lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) + ... result = lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) ... assert isinstance(result, xr.DataArray) """ if outgrid is not None: return None - return self.read_virtualfile(vfname, kind="grid").contents.to_dataarray() + if kind is None: # Inquire the data family from the virtualfile + family = self.inquire_virtualfile(vfname) + kind = { + self["GMT_IS_GRID"]: "grid", + self["GMT_IS_IMAGE"]: "image", + self["GMT_IS_CUBE"]: "cube", + }[family] + return self.read_virtualfile(vfname, kind=kind).contents.to_dataarray() def extract_region(self): """ diff --git a/pygmt/src/binstats.py b/pygmt/src/binstats.py index 3a85bae9732..028e79da1cc 100644 --- a/pygmt/src/binstats.py +++ b/pygmt/src/binstats.py @@ -111,4 +111,4 @@ def binstats(data, outgrid: str | None = None, **kwargs): lib.call_module( module="binstats", args=build_arg_string(kwargs, infile=vintbl) ) - return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/dimfilter.py b/pygmt/src/dimfilter.py index 0101553664c..f07c56f9171 100644 --- a/pygmt/src/dimfilter.py +++ b/pygmt/src/dimfilter.py @@ -150,4 +150,4 @@ def dimfilter(grid, outgrid: str | None = None, **kwargs): lib.call_module( module="dimfilter", args=build_arg_string(kwargs, infile=vingrd) ) - return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/grdclip.py b/pygmt/src/grdclip.py index b75bdbee12b..00c58a370e9 100644 --- a/pygmt/src/grdclip.py +++ b/pygmt/src/grdclip.py @@ -96,4 +96,4 @@ def grdclip(grid, outgrid: str | None = None, **kwargs): lib.call_module( module="grdclip", args=build_arg_string(kwargs, infile=vingrd) ) - return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/grdfill.py b/pygmt/src/grdfill.py index 443aa5c927f..1fe1dbf24ca 100644 --- a/pygmt/src/grdfill.py +++ b/pygmt/src/grdfill.py @@ -79,4 +79,4 @@ def grdfill(grid, outgrid: str | None = None, **kwargs): lib.call_module( module="grdfill", args=build_arg_string(kwargs, infile=vingrd) ) - return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/grdfilter.py b/pygmt/src/grdfilter.py index f6819dda5e0..f8d9915c231 100644 --- a/pygmt/src/grdfilter.py +++ b/pygmt/src/grdfilter.py @@ -133,4 +133,4 @@ def grdfilter(grid, outgrid: str | None = None, **kwargs): lib.call_module( module="grdfilter", args=build_arg_string(kwargs, infile=vingrd) ) - return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/grdgradient.py b/pygmt/src/grdgradient.py index 7830c188a42..0a656d2e09d 100644 --- a/pygmt/src/grdgradient.py +++ b/pygmt/src/grdgradient.py @@ -173,4 +173,4 @@ def grdgradient(grid, outgrid: str | None = None, **kwargs): lib.call_module( module="grdgradient", args=build_arg_string(kwargs, infile=vingrd) ) - return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/grdhisteq.py b/pygmt/src/grdhisteq.py index 7f9745d2620..7cf2e9f25a4 100644 --- a/pygmt/src/grdhisteq.py +++ b/pygmt/src/grdhisteq.py @@ -129,7 +129,7 @@ def equalize_grid(grid, outgrid: str | None = None, **kwargs): lib.call_module( module="grdhisteq", args=build_arg_string(kwargs, infile=vingrd) ) - return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) @staticmethod @fmt_docstring diff --git a/pygmt/src/grdlandmask.py b/pygmt/src/grdlandmask.py index 817dbfb5cbf..75d3327e121 100644 --- a/pygmt/src/grdlandmask.py +++ b/pygmt/src/grdlandmask.py @@ -101,4 +101,4 @@ def grdlandmask(outgrid: str | None = None, **kwargs): with lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd: kwargs["G"] = voutgrd lib.call_module(module="grdlandmask", args=build_arg_string(kwargs)) - return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/grdproject.py b/pygmt/src/grdproject.py index 33403971d29..9046ccbfa6a 100644 --- a/pygmt/src/grdproject.py +++ b/pygmt/src/grdproject.py @@ -113,4 +113,4 @@ def grdproject(grid, outgrid: str | None = None, **kwargs): lib.call_module( module="grdproject", args=build_arg_string(kwargs, infile=vingrd) ) - return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/grdsample.py b/pygmt/src/grdsample.py index df93dd4313a..8c2c0f692a2 100644 --- a/pygmt/src/grdsample.py +++ b/pygmt/src/grdsample.py @@ -88,4 +88,4 @@ def grdsample(grid, outgrid: str | None = None, **kwargs): lib.call_module( module="grdsample", args=build_arg_string(kwargs, infile=vingrd) ) - return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/nearneighbor.py b/pygmt/src/nearneighbor.py index d1df978d74d..81e0fd4d50f 100644 --- a/pygmt/src/nearneighbor.py +++ b/pygmt/src/nearneighbor.py @@ -148,4 +148,4 @@ def nearneighbor( lib.call_module( module="nearneighbor", args=build_arg_string(kwargs, infile=vintbl) ) - return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/sph2grd.py b/pygmt/src/sph2grd.py index 81c8088d107..533b578caa0 100644 --- a/pygmt/src/sph2grd.py +++ b/pygmt/src/sph2grd.py @@ -73,4 +73,4 @@ def sph2grd(data, outgrid: str | None = None, **kwargs): lib.call_module( module="sph2grd", args=build_arg_string(kwargs, infile=vintbl) ) - return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/sphdistance.py b/pygmt/src/sphdistance.py index 90264095e92..2c426a54352 100644 --- a/pygmt/src/sphdistance.py +++ b/pygmt/src/sphdistance.py @@ -117,4 +117,4 @@ def sphdistance(data=None, x=None, y=None, outgrid: str | None = None, **kwargs) lib.call_module( module="sphdistance", args=build_arg_string(kwargs, infile=vintbl) ) - return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/sphinterpolate.py b/pygmt/src/sphinterpolate.py index 658590df675..a8d57d20abe 100644 --- a/pygmt/src/sphinterpolate.py +++ b/pygmt/src/sphinterpolate.py @@ -67,4 +67,4 @@ def sphinterpolate(data, outgrid: str | None = None, **kwargs): lib.call_module( module="sphinterpolate", args=build_arg_string(kwargs, infile=vintbl) ) - return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/surface.py b/pygmt/src/surface.py index 6e04939e099..d336034632a 100644 --- a/pygmt/src/surface.py +++ b/pygmt/src/surface.py @@ -161,4 +161,4 @@ def surface(data=None, x=None, y=None, z=None, outgrid: str | None = None, **kwa lib.call_module( module="surface", args=build_arg_string(kwargs, infile=vintbl) ) - return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/triangulate.py b/pygmt/src/triangulate.py index ad72ace9325..135928ca424 100644 --- a/pygmt/src/triangulate.py +++ b/pygmt/src/triangulate.py @@ -146,7 +146,7 @@ def regular_grid( lib.call_module( module="triangulate", args=build_arg_string(kwargs, infile=vintbl) ) - return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) @staticmethod @fmt_docstring diff --git a/pygmt/src/xyz2grd.py b/pygmt/src/xyz2grd.py index b32603fd602..c3a5bd434ad 100644 --- a/pygmt/src/xyz2grd.py +++ b/pygmt/src/xyz2grd.py @@ -153,4 +153,4 @@ def xyz2grd(data=None, x=None, y=None, z=None, outgrid: str | None = None, **kwa lib.call_module( module="xyz2grd", args=build_arg_string(kwargs, infile=vintbl) ) - return lib.virtualfile_to_grid(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) From 6b38734f2c3a405c6d33c161e4ff6d33dba72f45 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Sun, 7 Apr 2024 20:34:38 +0800 Subject: [PATCH 07/11] Fix static type issues --- pygmt/clib/session.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pygmt/clib/session.py b/pygmt/clib/session.py index a552f447a8f..dbcee888800 100644 --- a/pygmt/clib/session.py +++ b/pygmt/clib/session.py @@ -1740,7 +1740,9 @@ def inquire_virtualfile(self, vfname: str) -> int: return c_inquire_virtualfile(self.session_pointer, vfname.encode()) def read_virtualfile( - self, vfname: str, kind: Literal["dataset", "grid", None] = None + self, + vfname: str, + kind: Literal["dataset", "grid", "image", "cube", None] = None, ): """ Read data from a virtual file and optionally cast into a GMT data container. @@ -1799,6 +1801,8 @@ def read_virtualfile( # _GMT_DATASET). if kind is None: # Return the ctypes void pointer return pointer + if kind in ["image", "cube"]: + raise NotImplementedError(f"kind={kind} is not supported yet.") dtype = {"dataset": _GMT_DATASET, "grid": _GMT_GRID}[kind] return ctp.cast(pointer, ctp.POINTER(dtype)) @@ -2004,7 +2008,7 @@ def virtualfile_to_raster( return None if kind is None: # Inquire the data family from the virtualfile family = self.inquire_virtualfile(vfname) - kind = { + kind = { # type: ignore[assignment] self["GMT_IS_GRID"]: "grid", self["GMT_IS_IMAGE"]: "image", self["GMT_IS_CUBE"]: "cube", From ab9a83822815eb162c165bd1c00d0b2ffbeee86f Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Sun, 7 Apr 2024 20:57:00 +0800 Subject: [PATCH 08/11] Explicitly set kind='grid' to avoid calling Session.inquire_virtualfile --- pygmt/src/binstats.py | 4 +++- pygmt/src/dimfilter.py | 4 +++- pygmt/src/grdclip.py | 4 +++- pygmt/src/grdfill.py | 4 +++- pygmt/src/grdfilter.py | 4 +++- pygmt/src/grdgradient.py | 4 +++- pygmt/src/grdhisteq.py | 4 +++- pygmt/src/grdlandmask.py | 4 +++- pygmt/src/grdproject.py | 4 +++- pygmt/src/grdsample.py | 4 +++- pygmt/src/nearneighbor.py | 4 +++- pygmt/src/sph2grd.py | 4 +++- pygmt/src/sphdistance.py | 4 +++- pygmt/src/sphinterpolate.py | 4 +++- pygmt/src/surface.py | 4 +++- pygmt/src/triangulate.py | 4 +++- pygmt/src/xyz2grd.py | 4 +++- 17 files changed, 51 insertions(+), 17 deletions(-) diff --git a/pygmt/src/binstats.py b/pygmt/src/binstats.py index 028e79da1cc..5bbb6d22c1f 100644 --- a/pygmt/src/binstats.py +++ b/pygmt/src/binstats.py @@ -111,4 +111,6 @@ def binstats(data, outgrid: str | None = None, **kwargs): lib.call_module( module="binstats", args=build_arg_string(kwargs, infile=vintbl) ) - return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster( + vfname=voutgrd, kind="grid", outgrid=outgrid + ) diff --git a/pygmt/src/dimfilter.py b/pygmt/src/dimfilter.py index f07c56f9171..5edc1538082 100644 --- a/pygmt/src/dimfilter.py +++ b/pygmt/src/dimfilter.py @@ -150,4 +150,6 @@ def dimfilter(grid, outgrid: str | None = None, **kwargs): lib.call_module( module="dimfilter", args=build_arg_string(kwargs, infile=vingrd) ) - return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster( + vfname=voutgrd, kind="grid", outgrid=outgrid + ) diff --git a/pygmt/src/grdclip.py b/pygmt/src/grdclip.py index 00c58a370e9..22bf275a50f 100644 --- a/pygmt/src/grdclip.py +++ b/pygmt/src/grdclip.py @@ -96,4 +96,6 @@ def grdclip(grid, outgrid: str | None = None, **kwargs): lib.call_module( module="grdclip", args=build_arg_string(kwargs, infile=vingrd) ) - return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster( + vfname=voutgrd, kind="grid", outgrid=outgrid + ) diff --git a/pygmt/src/grdfill.py b/pygmt/src/grdfill.py index 1fe1dbf24ca..bbbe90f2725 100644 --- a/pygmt/src/grdfill.py +++ b/pygmt/src/grdfill.py @@ -79,4 +79,6 @@ def grdfill(grid, outgrid: str | None = None, **kwargs): lib.call_module( module="grdfill", args=build_arg_string(kwargs, infile=vingrd) ) - return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster( + vfname=voutgrd, kind="grid", outgrid=outgrid + ) diff --git a/pygmt/src/grdfilter.py b/pygmt/src/grdfilter.py index f8d9915c231..23d9246d1f4 100644 --- a/pygmt/src/grdfilter.py +++ b/pygmt/src/grdfilter.py @@ -133,4 +133,6 @@ def grdfilter(grid, outgrid: str | None = None, **kwargs): lib.call_module( module="grdfilter", args=build_arg_string(kwargs, infile=vingrd) ) - return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster( + vfname=voutgrd, kind="grid", outgrid=outgrid + ) diff --git a/pygmt/src/grdgradient.py b/pygmt/src/grdgradient.py index 0a656d2e09d..e3d89a6a2af 100644 --- a/pygmt/src/grdgradient.py +++ b/pygmt/src/grdgradient.py @@ -173,4 +173,6 @@ def grdgradient(grid, outgrid: str | None = None, **kwargs): lib.call_module( module="grdgradient", args=build_arg_string(kwargs, infile=vingrd) ) - return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster( + vfname=voutgrd, kind="grid", outgrid=outgrid + ) diff --git a/pygmt/src/grdhisteq.py b/pygmt/src/grdhisteq.py index 7cf2e9f25a4..420aadb3a3f 100644 --- a/pygmt/src/grdhisteq.py +++ b/pygmt/src/grdhisteq.py @@ -129,7 +129,9 @@ def equalize_grid(grid, outgrid: str | None = None, **kwargs): lib.call_module( module="grdhisteq", args=build_arg_string(kwargs, infile=vingrd) ) - return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster( + vfname=voutgrd, kind="grid", outgrid=outgrid + ) @staticmethod @fmt_docstring diff --git a/pygmt/src/grdlandmask.py b/pygmt/src/grdlandmask.py index 75d3327e121..dd1bad10d01 100644 --- a/pygmt/src/grdlandmask.py +++ b/pygmt/src/grdlandmask.py @@ -101,4 +101,6 @@ def grdlandmask(outgrid: str | None = None, **kwargs): with lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd: kwargs["G"] = voutgrd lib.call_module(module="grdlandmask", args=build_arg_string(kwargs)) - return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster( + vfname=voutgrd, kind="grid", outgrid=outgrid + ) diff --git a/pygmt/src/grdproject.py b/pygmt/src/grdproject.py index 9046ccbfa6a..362f704752c 100644 --- a/pygmt/src/grdproject.py +++ b/pygmt/src/grdproject.py @@ -113,4 +113,6 @@ def grdproject(grid, outgrid: str | None = None, **kwargs): lib.call_module( module="grdproject", args=build_arg_string(kwargs, infile=vingrd) ) - return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster( + vfname=voutgrd, kind="grid", outgrid=outgrid + ) diff --git a/pygmt/src/grdsample.py b/pygmt/src/grdsample.py index 8c2c0f692a2..63ff57d4aef 100644 --- a/pygmt/src/grdsample.py +++ b/pygmt/src/grdsample.py @@ -88,4 +88,6 @@ def grdsample(grid, outgrid: str | None = None, **kwargs): lib.call_module( module="grdsample", args=build_arg_string(kwargs, infile=vingrd) ) - return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster( + vfname=voutgrd, kind="grid", outgrid=outgrid + ) diff --git a/pygmt/src/nearneighbor.py b/pygmt/src/nearneighbor.py index 81e0fd4d50f..df271cfd6a3 100644 --- a/pygmt/src/nearneighbor.py +++ b/pygmt/src/nearneighbor.py @@ -148,4 +148,6 @@ def nearneighbor( lib.call_module( module="nearneighbor", args=build_arg_string(kwargs, infile=vintbl) ) - return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster( + vfname=voutgrd, kind="grid", outgrid=outgrid + ) diff --git a/pygmt/src/sph2grd.py b/pygmt/src/sph2grd.py index 533b578caa0..d0f1642fd7f 100644 --- a/pygmt/src/sph2grd.py +++ b/pygmt/src/sph2grd.py @@ -73,4 +73,6 @@ def sph2grd(data, outgrid: str | None = None, **kwargs): lib.call_module( module="sph2grd", args=build_arg_string(kwargs, infile=vintbl) ) - return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster( + vfname=voutgrd, kind="grid", outgrid=outgrid + ) diff --git a/pygmt/src/sphdistance.py b/pygmt/src/sphdistance.py index 2c426a54352..695b80669c2 100644 --- a/pygmt/src/sphdistance.py +++ b/pygmt/src/sphdistance.py @@ -117,4 +117,6 @@ def sphdistance(data=None, x=None, y=None, outgrid: str | None = None, **kwargs) lib.call_module( module="sphdistance", args=build_arg_string(kwargs, infile=vintbl) ) - return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster( + vfname=voutgrd, kind="grid", outgrid=outgrid + ) diff --git a/pygmt/src/sphinterpolate.py b/pygmt/src/sphinterpolate.py index a8d57d20abe..d4f2d67ba62 100644 --- a/pygmt/src/sphinterpolate.py +++ b/pygmt/src/sphinterpolate.py @@ -67,4 +67,6 @@ def sphinterpolate(data, outgrid: str | None = None, **kwargs): lib.call_module( module="sphinterpolate", args=build_arg_string(kwargs, infile=vintbl) ) - return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster( + vfname=voutgrd, kind="grid", outgrid=outgrid + ) diff --git a/pygmt/src/surface.py b/pygmt/src/surface.py index d336034632a..acff6270b27 100644 --- a/pygmt/src/surface.py +++ b/pygmt/src/surface.py @@ -161,4 +161,6 @@ def surface(data=None, x=None, y=None, z=None, outgrid: str | None = None, **kwa lib.call_module( module="surface", args=build_arg_string(kwargs, infile=vintbl) ) - return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster( + vfname=voutgrd, kind="grid", outgrid=outgrid + ) diff --git a/pygmt/src/triangulate.py b/pygmt/src/triangulate.py index 135928ca424..813ec2cb85c 100644 --- a/pygmt/src/triangulate.py +++ b/pygmt/src/triangulate.py @@ -146,7 +146,9 @@ def regular_grid( lib.call_module( module="triangulate", args=build_arg_string(kwargs, infile=vintbl) ) - return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster( + vfname=voutgrd, kind="grid", outgrid=outgrid + ) @staticmethod @fmt_docstring diff --git a/pygmt/src/xyz2grd.py b/pygmt/src/xyz2grd.py index c3a5bd434ad..be1f33e8921 100644 --- a/pygmt/src/xyz2grd.py +++ b/pygmt/src/xyz2grd.py @@ -153,4 +153,6 @@ def xyz2grd(data=None, x=None, y=None, z=None, outgrid: str | None = None, **kwa lib.call_module( module="xyz2grd", args=build_arg_string(kwargs, infile=vintbl) ) - return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) + return lib.virtualfile_to_raster( + vfname=voutgrd, kind="grid", outgrid=outgrid + ) From 01664f855a9e751ff3ebc3de2ebeedfcc3986282 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Tue, 9 Apr 2024 13:07:40 +0800 Subject: [PATCH 09/11] Fix a typo [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Yvonne Fröhlich <94163266+yvonnefroehlich@users.noreply.github.com> --- pygmt/datatypes/grid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/datatypes/grid.py b/pygmt/datatypes/grid.py index bd5e9599b75..9695ad73889 100644 --- a/pygmt/datatypes/grid.py +++ b/pygmt/datatypes/grid.py @@ -192,7 +192,7 @@ def to_dataarray(self) -> xr.DataArray: if grid[dim][0] > grid[dim][1]: grid = grid.isel({dim: slice(None, None, -1)}) - # Set the gmt accesssor. + # Set the gmt accessor. # Must put at the end. The information get lost after specific grid operation. grid.gmt.registration = header.registration grid.gmt.gtype = header.gtype From 2e51ba765de71c985c798dc47c8a48e8d2265586 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Sun, 14 Apr 2024 08:42:06 +0800 Subject: [PATCH 10/11] Apply suggestions from code review Co-authored-by: Wei Ji <23487320+weiji14@users.noreply.github.com> --- pygmt/clib/session.py | 4 ++-- pygmt/datatypes/grid.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pygmt/clib/session.py b/pygmt/clib/session.py index dbcee888800..5ce9d44103b 100644 --- a/pygmt/clib/session.py +++ b/pygmt/clib/session.py @@ -1958,7 +1958,7 @@ def virtualfile_to_raster( outgrid: str | None = None, ) -> xr.DataArray | None: """ - Output a raster data stored in a virtual file to an :class:`xarray.DataArray` + Output raster data stored in a virtual file to an :class:`xarray.DataArray` object. The raster data can be a grid, an image or a cube. @@ -1966,7 +1966,7 @@ def virtualfile_to_raster( Parameters ---------- vfname - The virtual file name that stores the result grid. + The virtual file name that stores the result grid/image/cube. kind Type of the raster data. Valid values are ``"grid"``, ``"image"``, ``"cube"`` or ``None``. If ``None``, will inquire the data type from the diff --git a/pygmt/datatypes/grid.py b/pygmt/datatypes/grid.py index 9695ad73889..1caa0bd0240 100644 --- a/pygmt/datatypes/grid.py +++ b/pygmt/datatypes/grid.py @@ -14,7 +14,7 @@ class _GMT_GRID(ctp.Structure): # noqa: N801 """ GMT grid structure for holding a grid and its header. - The class is only meant for internal use and is not exposed to users. See the GMT + This class is only meant for internal use and is not exposed to users. See the GMT source code gmt_resources.h for the original C structure definitions. Examples @@ -192,8 +192,8 @@ def to_dataarray(self) -> xr.DataArray: if grid[dim][0] > grid[dim][1]: grid = grid.isel({dim: slice(None, None, -1)}) - # Set the gmt accessor. - # Must put at the end. The information get lost after specific grid operation. + # Set GMT accessors. + # Must put at the end, otherwise info gets lost after certain grid operations. grid.gmt.registration = header.registration grid.gmt.gtype = header.gtype return grid From 97c3cc9f9a9ff67bfc016603f4cd24547967c6f3 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Tue, 16 Apr 2024 08:44:56 +0800 Subject: [PATCH 11/11] Session.virtualfile_to_raster: let kind default to 'grid' --- pygmt/clib/session.py | 2 +- pygmt/src/binstats.py | 4 +--- pygmt/src/dimfilter.py | 4 +--- pygmt/src/grdclip.py | 4 +--- pygmt/src/grdfill.py | 4 +--- pygmt/src/grdfilter.py | 4 +--- pygmt/src/grdgradient.py | 4 +--- pygmt/src/grdhisteq.py | 4 +--- pygmt/src/grdlandmask.py | 4 +--- pygmt/src/grdproject.py | 4 +--- pygmt/src/grdsample.py | 4 +--- pygmt/src/nearneighbor.py | 4 +--- pygmt/src/sph2grd.py | 4 +--- pygmt/src/sphdistance.py | 4 +--- pygmt/src/sphinterpolate.py | 4 +--- pygmt/src/surface.py | 4 +--- pygmt/src/triangulate.py | 4 +--- pygmt/src/xyz2grd.py | 4 +--- 18 files changed, 18 insertions(+), 52 deletions(-) diff --git a/pygmt/clib/session.py b/pygmt/clib/session.py index 5ce9d44103b..8a8b52df8e5 100644 --- a/pygmt/clib/session.py +++ b/pygmt/clib/session.py @@ -1954,7 +1954,7 @@ def virtualfile_to_dataset( def virtualfile_to_raster( self, vfname: str, - kind: Literal["grid", "image", "cube", None] = None, + kind: Literal["grid", "image", "cube", None] = "grid", outgrid: str | None = None, ) -> xr.DataArray | None: """ diff --git a/pygmt/src/binstats.py b/pygmt/src/binstats.py index 5bbb6d22c1f..028e79da1cc 100644 --- a/pygmt/src/binstats.py +++ b/pygmt/src/binstats.py @@ -111,6 +111,4 @@ def binstats(data, outgrid: str | None = None, **kwargs): lib.call_module( module="binstats", args=build_arg_string(kwargs, infile=vintbl) ) - return lib.virtualfile_to_raster( - vfname=voutgrd, kind="grid", outgrid=outgrid - ) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/dimfilter.py b/pygmt/src/dimfilter.py index 5edc1538082..f07c56f9171 100644 --- a/pygmt/src/dimfilter.py +++ b/pygmt/src/dimfilter.py @@ -150,6 +150,4 @@ def dimfilter(grid, outgrid: str | None = None, **kwargs): lib.call_module( module="dimfilter", args=build_arg_string(kwargs, infile=vingrd) ) - return lib.virtualfile_to_raster( - vfname=voutgrd, kind="grid", outgrid=outgrid - ) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/grdclip.py b/pygmt/src/grdclip.py index 22bf275a50f..00c58a370e9 100644 --- a/pygmt/src/grdclip.py +++ b/pygmt/src/grdclip.py @@ -96,6 +96,4 @@ def grdclip(grid, outgrid: str | None = None, **kwargs): lib.call_module( module="grdclip", args=build_arg_string(kwargs, infile=vingrd) ) - return lib.virtualfile_to_raster( - vfname=voutgrd, kind="grid", outgrid=outgrid - ) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/grdfill.py b/pygmt/src/grdfill.py index bbbe90f2725..1fe1dbf24ca 100644 --- a/pygmt/src/grdfill.py +++ b/pygmt/src/grdfill.py @@ -79,6 +79,4 @@ def grdfill(grid, outgrid: str | None = None, **kwargs): lib.call_module( module="grdfill", args=build_arg_string(kwargs, infile=vingrd) ) - return lib.virtualfile_to_raster( - vfname=voutgrd, kind="grid", outgrid=outgrid - ) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/grdfilter.py b/pygmt/src/grdfilter.py index 23d9246d1f4..f8d9915c231 100644 --- a/pygmt/src/grdfilter.py +++ b/pygmt/src/grdfilter.py @@ -133,6 +133,4 @@ def grdfilter(grid, outgrid: str | None = None, **kwargs): lib.call_module( module="grdfilter", args=build_arg_string(kwargs, infile=vingrd) ) - return lib.virtualfile_to_raster( - vfname=voutgrd, kind="grid", outgrid=outgrid - ) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/grdgradient.py b/pygmt/src/grdgradient.py index e3d89a6a2af..0a656d2e09d 100644 --- a/pygmt/src/grdgradient.py +++ b/pygmt/src/grdgradient.py @@ -173,6 +173,4 @@ def grdgradient(grid, outgrid: str | None = None, **kwargs): lib.call_module( module="grdgradient", args=build_arg_string(kwargs, infile=vingrd) ) - return lib.virtualfile_to_raster( - vfname=voutgrd, kind="grid", outgrid=outgrid - ) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/grdhisteq.py b/pygmt/src/grdhisteq.py index 420aadb3a3f..7cf2e9f25a4 100644 --- a/pygmt/src/grdhisteq.py +++ b/pygmt/src/grdhisteq.py @@ -129,9 +129,7 @@ def equalize_grid(grid, outgrid: str | None = None, **kwargs): lib.call_module( module="grdhisteq", args=build_arg_string(kwargs, infile=vingrd) ) - return lib.virtualfile_to_raster( - vfname=voutgrd, kind="grid", outgrid=outgrid - ) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) @staticmethod @fmt_docstring diff --git a/pygmt/src/grdlandmask.py b/pygmt/src/grdlandmask.py index dd1bad10d01..75d3327e121 100644 --- a/pygmt/src/grdlandmask.py +++ b/pygmt/src/grdlandmask.py @@ -101,6 +101,4 @@ def grdlandmask(outgrid: str | None = None, **kwargs): with lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd: kwargs["G"] = voutgrd lib.call_module(module="grdlandmask", args=build_arg_string(kwargs)) - return lib.virtualfile_to_raster( - vfname=voutgrd, kind="grid", outgrid=outgrid - ) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/grdproject.py b/pygmt/src/grdproject.py index 362f704752c..9046ccbfa6a 100644 --- a/pygmt/src/grdproject.py +++ b/pygmt/src/grdproject.py @@ -113,6 +113,4 @@ def grdproject(grid, outgrid: str | None = None, **kwargs): lib.call_module( module="grdproject", args=build_arg_string(kwargs, infile=vingrd) ) - return lib.virtualfile_to_raster( - vfname=voutgrd, kind="grid", outgrid=outgrid - ) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/grdsample.py b/pygmt/src/grdsample.py index 63ff57d4aef..8c2c0f692a2 100644 --- a/pygmt/src/grdsample.py +++ b/pygmt/src/grdsample.py @@ -88,6 +88,4 @@ def grdsample(grid, outgrid: str | None = None, **kwargs): lib.call_module( module="grdsample", args=build_arg_string(kwargs, infile=vingrd) ) - return lib.virtualfile_to_raster( - vfname=voutgrd, kind="grid", outgrid=outgrid - ) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/nearneighbor.py b/pygmt/src/nearneighbor.py index df271cfd6a3..81e0fd4d50f 100644 --- a/pygmt/src/nearneighbor.py +++ b/pygmt/src/nearneighbor.py @@ -148,6 +148,4 @@ def nearneighbor( lib.call_module( module="nearneighbor", args=build_arg_string(kwargs, infile=vintbl) ) - return lib.virtualfile_to_raster( - vfname=voutgrd, kind="grid", outgrid=outgrid - ) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/sph2grd.py b/pygmt/src/sph2grd.py index d0f1642fd7f..533b578caa0 100644 --- a/pygmt/src/sph2grd.py +++ b/pygmt/src/sph2grd.py @@ -73,6 +73,4 @@ def sph2grd(data, outgrid: str | None = None, **kwargs): lib.call_module( module="sph2grd", args=build_arg_string(kwargs, infile=vintbl) ) - return lib.virtualfile_to_raster( - vfname=voutgrd, kind="grid", outgrid=outgrid - ) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/sphdistance.py b/pygmt/src/sphdistance.py index 695b80669c2..2c426a54352 100644 --- a/pygmt/src/sphdistance.py +++ b/pygmt/src/sphdistance.py @@ -117,6 +117,4 @@ def sphdistance(data=None, x=None, y=None, outgrid: str | None = None, **kwargs) lib.call_module( module="sphdistance", args=build_arg_string(kwargs, infile=vintbl) ) - return lib.virtualfile_to_raster( - vfname=voutgrd, kind="grid", outgrid=outgrid - ) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/sphinterpolate.py b/pygmt/src/sphinterpolate.py index d4f2d67ba62..a8d57d20abe 100644 --- a/pygmt/src/sphinterpolate.py +++ b/pygmt/src/sphinterpolate.py @@ -67,6 +67,4 @@ def sphinterpolate(data, outgrid: str | None = None, **kwargs): lib.call_module( module="sphinterpolate", args=build_arg_string(kwargs, infile=vintbl) ) - return lib.virtualfile_to_raster( - vfname=voutgrd, kind="grid", outgrid=outgrid - ) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/surface.py b/pygmt/src/surface.py index acff6270b27..d336034632a 100644 --- a/pygmt/src/surface.py +++ b/pygmt/src/surface.py @@ -161,6 +161,4 @@ def surface(data=None, x=None, y=None, z=None, outgrid: str | None = None, **kwa lib.call_module( module="surface", args=build_arg_string(kwargs, infile=vintbl) ) - return lib.virtualfile_to_raster( - vfname=voutgrd, kind="grid", outgrid=outgrid - ) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/src/triangulate.py b/pygmt/src/triangulate.py index 813ec2cb85c..135928ca424 100644 --- a/pygmt/src/triangulate.py +++ b/pygmt/src/triangulate.py @@ -146,9 +146,7 @@ def regular_grid( lib.call_module( module="triangulate", args=build_arg_string(kwargs, infile=vintbl) ) - return lib.virtualfile_to_raster( - vfname=voutgrd, kind="grid", outgrid=outgrid - ) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) @staticmethod @fmt_docstring diff --git a/pygmt/src/xyz2grd.py b/pygmt/src/xyz2grd.py index be1f33e8921..c3a5bd434ad 100644 --- a/pygmt/src/xyz2grd.py +++ b/pygmt/src/xyz2grd.py @@ -153,6 +153,4 @@ def xyz2grd(data=None, x=None, y=None, z=None, outgrid: str | None = None, **kwa lib.call_module( module="xyz2grd", args=build_arg_string(kwargs, infile=vintbl) ) - return lib.virtualfile_to_raster( - vfname=voutgrd, kind="grid", outgrid=outgrid - ) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid)