|
26 | 26 | )
|
27 | 27 | from pygmt.clib.loading import load_libgmt
|
28 | 28 | from pygmt.datatypes import _GMT_DATASET, _GMT_GRID
|
| 29 | +from pygmt.datatypes.header import gmt_grdfloat |
29 | 30 | from pygmt.exceptions import (
|
30 | 31 | GMTCLibError,
|
31 | 32 | GMTCLibNoSessionError,
|
@@ -325,6 +326,22 @@ def get_libgmt_func(self, name, argtypes=None, restype=None):
|
325 | 326 | function.restype = restype
|
326 | 327 | return function
|
327 | 328 |
|
| 329 | + def set_allocmode(self, family, obj): |
| 330 | + """ |
| 331 | + Set allocation mode of object to external. |
| 332 | + """ |
| 333 | + c_set_allocmode = self.get_libgmt_func( |
| 334 | + "GMT_Set_AllocMode", |
| 335 | + argtypes=[ctp.c_void_p, ctp.c_uint, ctp.c_void_p], |
| 336 | + restype=ctp.c_void_p, |
| 337 | + ) |
| 338 | + family_int = self._parse_constant(family, valid=FAMILIES, valid_modifiers=VIAS) |
| 339 | + status = c_set_allocmode(self.session_pointer, family_int, obj) |
| 340 | + if status: |
| 341 | + raise GMTCLibError( |
| 342 | + f"Failed to set allocation mode of object to external:\n{self._error_message}" |
| 343 | + ) |
| 344 | + |
328 | 345 | def create(self, name):
|
329 | 346 | """
|
330 | 347 | Create a new GMT C API session.
|
@@ -1597,7 +1614,7 @@ def virtualfile_in( # noqa: PLR0912
|
1597 | 1614 | "file": contextlib.nullcontext,
|
1598 | 1615 | "arg": contextlib.nullcontext,
|
1599 | 1616 | "geojson": tempfile_from_geojson,
|
1600 |
| - "grid": self.virtualfile_from_grid, |
| 1617 | + "grid": self.virtualfile_from_xrgrid, |
1601 | 1618 | "image": tempfile_from_image,
|
1602 | 1619 | # Note: virtualfile_from_matrix is not used because a matrix can be
|
1603 | 1620 | # converted to vectors instead, and using vectors allows for better
|
@@ -1806,6 +1823,45 @@ def read_virtualfile(
|
1806 | 1823 | dtype = {"dataset": _GMT_DATASET, "grid": _GMT_GRID}[kind]
|
1807 | 1824 | return ctp.cast(pointer, ctp.POINTER(dtype))
|
1808 | 1825 |
|
| 1826 | + @contextlib.contextmanager |
| 1827 | + def virtualfile_from_xrgrid(self, xrgrid): |
| 1828 | + """ |
| 1829 | + Create a virtual file from an xarray.DataArray object. |
| 1830 | + """ |
| 1831 | + family = "GMT_IS_GRID" |
| 1832 | + geometry = "GMT_IS_SURFACE" |
| 1833 | + matrix, region, inc = dataarray_to_matrix(xrgrid) |
| 1834 | + |
| 1835 | + _gtype = {0: "GMT_GRID_IS_CARTESIAN", 1: "GMT_GRID_IS_GEO"}[xrgrid.gmt.gtype] |
| 1836 | + _reg = {0: "GMT_GRID_NODE_REG", 1: "GMT_GRID_PIXEL_REG"}[ |
| 1837 | + xrgrid.gmt.registration |
| 1838 | + ] |
| 1839 | + |
| 1840 | + data = self.create_data( |
| 1841 | + family, |
| 1842 | + geometry, |
| 1843 | + mode=f"GMT_CONTAINER_ONLY|{_gtype}", |
| 1844 | + ranges=region, |
| 1845 | + inc=inc, |
| 1846 | + registration=_reg, |
| 1847 | + pad=self["GMT_PAD_DEFAULT"], |
| 1848 | + ) |
| 1849 | + if Version(self._info["version"]) < Version("6.5.0"): |
| 1850 | + # Upstream bug fixed in GMT>=6.5.0 |
| 1851 | + self.set_allocmode(family, data) |
| 1852 | + |
| 1853 | + gmtgrid = ctp.cast(data, ctp.POINTER(_GMT_GRID)) |
| 1854 | + header = gmtgrid.contents.header.contents |
| 1855 | + header.z_min, header.z_max = matrix.min(), matrix.max() |
| 1856 | + |
| 1857 | + matrix = np.pad(matrix, self["GMT_PAD_DEFAULT"]).astype(np.float32) |
| 1858 | + gmtgrid.contents.data = matrix.ctypes.data_as(ctp.POINTER(gmt_grdfloat)) |
| 1859 | + |
| 1860 | + with self.open_virtualfile( |
| 1861 | + family, geometry, "GMT_IN|GMT_IS_REFERENCE", gmtgrid |
| 1862 | + ) as vfile: |
| 1863 | + yield vfile |
| 1864 | + |
1809 | 1865 | def virtualfile_to_dataset(
|
1810 | 1866 | self,
|
1811 | 1867 | vfname: str,
|
|
0 commit comments