14
14
15
15
import numpy as np
16
16
import pandas as pd
17
+ import xarray as xr
17
18
from packaging .version import Version
18
19
from pygmt .clib .conversion import (
19
20
array_to_datetime ,
@@ -1712,8 +1713,39 @@ def virtualfile_out(
1712
1713
with self .open_virtualfile (family , geometry , "GMT_OUT" , None ) as vfile :
1713
1714
yield vfile
1714
1715
1716
+ def inquire_virtualfile (self , vfname : str ) -> int :
1717
+ """
1718
+ Get the family of a virtual file.
1719
+
1720
+ Parameters
1721
+ ----------
1722
+ vfname
1723
+ Name of the virtual file to inquire.
1724
+
1725
+ Returns
1726
+ -------
1727
+ family
1728
+ The integer value for the family of the virtual file.
1729
+
1730
+ Examples
1731
+ --------
1732
+ >>> from pygmt.clib import Session
1733
+ >>> with Session() as lib:
1734
+ ... with lib.virtualfile_out(kind="dataset") as vfile:
1735
+ ... family = lib.inquire_virtualfile(vfile)
1736
+ ... assert family == lib["GMT_IS_DATASET"]
1737
+ """
1738
+ c_inquire_virtualfile = self .get_libgmt_func (
1739
+ "GMT_Inquire_VirtualFile" ,
1740
+ argtypes = [ctp .c_void_p , ctp .c_char_p ],
1741
+ restype = ctp .c_uint ,
1742
+ )
1743
+ return c_inquire_virtualfile (self .session_pointer , vfname .encode ())
1744
+
1715
1745
def read_virtualfile (
1716
- self , vfname : str , kind : Literal ["dataset" , "grid" , "cube" , None ] = None
1746
+ self ,
1747
+ vfname : str ,
1748
+ kind : Literal ["dataset" , "grid" , "image" , "cube" , None ] = None ,
1717
1749
):
1718
1750
"""
1719
1751
Read data from a virtual file and optionally cast into a GMT data container.
@@ -1772,13 +1804,15 @@ def read_virtualfile(
1772
1804
# _GMT_DATASET).
1773
1805
if kind is None : # Return the ctypes void pointer
1774
1806
return pointer
1807
+ if kind == "image" :
1808
+ raise NotImplementedError (f"kind={ kind } is not supported yet." )
1775
1809
dtype = {"dataset" : _GMT_DATASET , "grid" : _GMT_GRID , "cube" : _GMT_CUBE }[kind ]
1776
1810
return ctp .cast (pointer , ctp .POINTER (dtype ))
1777
1811
1778
1812
def virtualfile_to_dataset (
1779
1813
self ,
1780
1814
vfname : str ,
1781
- output_type : Literal ["pandas" , "numpy" , "file" ] = "pandas" ,
1815
+ output_type : Literal ["pandas" , "numpy" , "file" , "strings" ] = "pandas" ,
1782
1816
column_names : list [str ] | None = None ,
1783
1817
dtype : type | dict [str , type ] | None = None ,
1784
1818
index_col : str | int | None = None ,
@@ -1799,6 +1833,7 @@ def virtualfile_to_dataset(
1799
1833
- ``"pandas"`` will return a :class:`pandas.DataFrame` object.
1800
1834
- ``"numpy"`` will return a :class:`numpy.ndarray` object.
1801
1835
- ``"file"`` means the result was saved to a file and will return ``None``.
1836
+ - ``"strings"`` will return the trailing text only as an array of strings.
1802
1837
column_names
1803
1838
The column names for the :class:`pandas.DataFrame` output.
1804
1839
dtype
@@ -1844,6 +1879,16 @@ def virtualfile_to_dataset(
1844
1879
... assert result is None
1845
1880
... assert Path(outtmp.name).stat().st_size > 0
1846
1881
...
1882
+ ... # strings output
1883
+ ... with Session() as lib:
1884
+ ... with lib.virtualfile_out(kind="dataset") as vouttbl:
1885
+ ... lib.call_module("read", f"{tmpfile.name} {vouttbl} -Td")
1886
+ ... outstr = lib.virtualfile_to_dataset(
1887
+ ... vfname=vouttbl, output_type="strings"
1888
+ ... )
1889
+ ... assert isinstance(outstr, np.ndarray)
1890
+ ... assert outstr.dtype.kind in ("S", "U")
1891
+ ...
1847
1892
... # numpy output
1848
1893
... with Session() as lib:
1849
1894
... with lib.virtualfile_out(kind="dataset") as vouttbl:
@@ -1872,6 +1917,9 @@ def virtualfile_to_dataset(
1872
1917
... column_names=["col1", "col2", "col3", "coltext"],
1873
1918
... )
1874
1919
... assert isinstance(outpd2, pd.DataFrame)
1920
+ >>> outstr
1921
+ array(['TEXT1 TEXT23', 'TEXT4 TEXT567', 'TEXT8 TEXT90',
1922
+ 'TEXT123 TEXT456789'], dtype='<U18')
1875
1923
>>> outnp
1876
1924
array([[1.0, 2.0, 3.0, 'TEXT1 TEXT23'],
1877
1925
[4.0, 5.0, 6.0, 'TEXT4 TEXT567'],
@@ -1893,16 +1941,83 @@ def virtualfile_to_dataset(
1893
1941
if output_type == "file" : # Already written to file, so return None
1894
1942
return None
1895
1943
1896
- # Read the virtual file as a GMT dataset and convert to pandas.DataFrame
1897
- result = self .read_virtualfile (vfname , kind = "dataset" ).contents .to_dataframe (
1898
- column_names = column_names ,
1899
- dtype = dtype ,
1900
- index_col = index_col ,
1944
+ # Read the virtual file as a _GMT_DATASET object
1945
+ result = self .read_virtualfile (vfname , kind = "dataset" ).contents
1946
+
1947
+ if output_type == "strings" : # strings output
1948
+ return result .to_strings ()
1949
+
1950
+ result = result .to_dataframe (
1951
+ column_names = column_names , dtype = dtype , index_col = index_col
1901
1952
)
1902
1953
if output_type == "numpy" : # numpy.ndarray output
1903
1954
return result .to_numpy ()
1904
1955
return result # pandas.DataFrame output
1905
1956
1957
+ def virtualfile_to_raster (
1958
+ self ,
1959
+ vfname : str ,
1960
+ kind : Literal ["grid" , "image" , "cube" , None ] = "grid" ,
1961
+ outgrid : str | None = None ,
1962
+ ) -> xr .DataArray | None :
1963
+ """
1964
+ Output raster data stored in a virtual file to an :class:`xarray.DataArray`
1965
+ object.
1966
+
1967
+ The raster data can be a grid, an image or a cube.
1968
+
1969
+ Parameters
1970
+ ----------
1971
+ vfname
1972
+ The virtual file name that stores the result grid/image/cube.
1973
+ kind
1974
+ Type of the raster data. Valid values are ``"grid"``, ``"image"``,
1975
+ ``"cube"`` or ``None``. If ``None``, will inquire the data type from the
1976
+ virtual file name.
1977
+ outgrid
1978
+ Name of the output grid/image/cube. If specified, it means the raster data
1979
+ was already saved into an actual file and will return ``None``.
1980
+
1981
+ Returns
1982
+ -------
1983
+ result
1984
+ The result grid/image/cube. If ``outgrid`` is specified, return ``None``.
1985
+
1986
+ Examples
1987
+ --------
1988
+ >>> from pathlib import Path
1989
+ >>> from pygmt.clib import Session
1990
+ >>> from pygmt.helpers import GMTTempFile
1991
+ >>> with Session() as lib:
1992
+ ... # file output
1993
+ ... with GMTTempFile(suffix=".nc") as tmpfile:
1994
+ ... outgrid = tmpfile.name
1995
+ ... with lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd:
1996
+ ... lib.call_module("read", f"@earth_relief_01d_g {voutgrd} -Tg")
1997
+ ... result = lib.virtualfile_to_raster(
1998
+ ... vfname=voutgrd, outgrid=outgrid
1999
+ ... )
2000
+ ... assert result == None
2001
+ ... assert Path(outgrid).stat().st_size > 0
2002
+ ...
2003
+ ... # xarray.DataArray output
2004
+ ... outgrid = None
2005
+ ... with lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd:
2006
+ ... lib.call_module("read", f"@earth_relief_01d_g {voutgrd} -Tg")
2007
+ ... result = lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid)
2008
+ ... assert isinstance(result, xr.DataArray)
2009
+ """
2010
+ if outgrid is not None :
2011
+ return None
2012
+ if kind is None : # Inquire the data family from the virtualfile
2013
+ family = self .inquire_virtualfile (vfname )
2014
+ kind = { # type: ignore[assignment]
2015
+ self ["GMT_IS_GRID" ]: "grid" ,
2016
+ self ["GMT_IS_IMAGE" ]: "image" ,
2017
+ self ["GMT_IS_CUBE" ]: "cube" ,
2018
+ }[family ]
2019
+ return self .read_virtualfile (vfname , kind = kind ).contents .to_dataarray ()
2020
+
1906
2021
def extract_region (self ):
1907
2022
"""
1908
2023
Extract the WESN bounding box of the currently active figure.
0 commit comments