|
| 1 | +""" |
| 2 | +grd2xyz - Convert grid to data table |
| 3 | +""" |
| 4 | +import warnings |
| 5 | + |
| 6 | +import pandas as pd |
| 7 | +import xarray as xr |
| 8 | +from pygmt.clib import Session |
| 9 | +from pygmt.exceptions import GMTInvalidInput |
| 10 | +from pygmt.helpers import ( |
| 11 | + GMTTempFile, |
| 12 | + build_arg_string, |
| 13 | + fmt_docstring, |
| 14 | + kwargs_to_strings, |
| 15 | + use_alias, |
| 16 | +) |
| 17 | + |
| 18 | + |
| 19 | +@fmt_docstring |
| 20 | +@use_alias( |
| 21 | + R="region", |
| 22 | + V="verbose", |
| 23 | + o="outcols", |
| 24 | +) |
| 25 | +@kwargs_to_strings(R="sequence", o="sequence_comma") |
| 26 | +def grd2xyz(grid, output_type="pandas", outfile=None, **kwargs): |
| 27 | + r""" |
| 28 | + Convert grid to data table. |
| 29 | +
|
| 30 | + Read a grid and output xyz-triplets as a :class:`numpy.ndarray`, |
| 31 | + :class:`pandas.DataFrame`, or ASCII file. |
| 32 | +
|
| 33 | + Full option list at :gmt-docs:`grd2xyz.html` |
| 34 | +
|
| 35 | + {aliases} |
| 36 | +
|
| 37 | + Parameters |
| 38 | + ---------- |
| 39 | + grid : str or xarray.DataArray |
| 40 | + The file name of the input grid or the grid loaded as a |
| 41 | + :class:`xarray.DataArray`. This is the only required parameter. |
| 42 | + output_type : str |
| 43 | + Determine the format the xyz data will be returned in [Default is |
| 44 | + ``pandas``]: |
| 45 | +
|
| 46 | + - ``numpy`` - :class:`numpy.ndarray` |
| 47 | + - ``pandas``- :class:`pandas.DataFrame` |
| 48 | + - ``file`` - ASCII file (requires ``outfile``) |
| 49 | + outfile : str |
| 50 | + The file name for the output ASCII file. |
| 51 | + {R} |
| 52 | + Adding ``region`` will select a subsection of the grid. If this |
| 53 | + subsection exceeds the boundaries of the grid, only the common region |
| 54 | + will be output. |
| 55 | + {V} |
| 56 | + {o} |
| 57 | +
|
| 58 | + Returns |
| 59 | + ------- |
| 60 | + ret : pandas.DataFrame or numpy.ndarray or None |
| 61 | + Return type depends on ``outfile`` and ``output_type``: |
| 62 | +
|
| 63 | + - None if ``outfile`` is set (output will be stored in file set by |
| 64 | + ``outfile``) |
| 65 | + - :class:`pandas.DataFrame` or :class:`numpy.ndarray` if ``outfile`` is |
| 66 | + not set (depends on ``output_type``) |
| 67 | +
|
| 68 | + """ |
| 69 | + if output_type not in ["numpy", "pandas", "file"]: |
| 70 | + raise GMTInvalidInput( |
| 71 | + "Must specify 'output_type' either as 'numpy', 'pandas' or 'file'." |
| 72 | + ) |
| 73 | + |
| 74 | + if outfile is not None and output_type != "file": |
| 75 | + msg = ( |
| 76 | + f"Changing 'output_type' of grd2xyz from '{output_type}' to 'file' " |
| 77 | + "since 'outfile' parameter is set. Please use output_type='file' " |
| 78 | + "to silence this warning." |
| 79 | + ) |
| 80 | + warnings.warn(message=msg, category=RuntimeWarning, stacklevel=2) |
| 81 | + output_type = "file" |
| 82 | + elif outfile is None and output_type == "file": |
| 83 | + raise GMTInvalidInput("Must specify 'outfile' for ASCII output.") |
| 84 | + |
| 85 | + if "o" in kwargs and output_type == "pandas": |
| 86 | + raise GMTInvalidInput( |
| 87 | + "If 'outcols' is specified, 'output_type' must be either 'numpy'" |
| 88 | + "or 'file'." |
| 89 | + ) |
| 90 | + |
| 91 | + # Set the default column names for the pandas dataframe header |
| 92 | + dataframe_header = ["x", "y", "z"] |
| 93 | + # Let output pandas column names match input DataArray dimension names |
| 94 | + if isinstance(grid, xr.DataArray) and output_type == "pandas": |
| 95 | + # Reverse the dims because it is rows, columns ordered. |
| 96 | + dataframe_header = [grid.dims[1], grid.dims[0], grid.name] |
| 97 | + |
| 98 | + with GMTTempFile() as tmpfile: |
| 99 | + with Session() as lib: |
| 100 | + file_context = lib.virtualfile_from_data(check_kind="raster", data=grid) |
| 101 | + with file_context as infile: |
| 102 | + if outfile is None: |
| 103 | + outfile = tmpfile.name |
| 104 | + arg_str = " ".join([infile, build_arg_string(kwargs), "->" + outfile]) |
| 105 | + lib.call_module("grd2xyz", arg_str) |
| 106 | + |
| 107 | + # Read temporary csv output to a pandas table |
| 108 | + if outfile == tmpfile.name: # if user did not set outfile, return pd.DataFrame |
| 109 | + result = pd.read_csv( |
| 110 | + tmpfile.name, sep="\t", names=dataframe_header, comment=">" |
| 111 | + ) |
| 112 | + elif outfile != tmpfile.name: # return None if outfile set, output in outfile |
| 113 | + result = None |
| 114 | + |
| 115 | + if output_type == "numpy": |
| 116 | + result = result.to_numpy() |
| 117 | + return result |
0 commit comments