Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrap grd2xyz #1284

Merged
merged 66 commits into from
Sep 22, 2021
Merged
Show file tree
Hide file tree
Changes from 61 commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
17a86be
add grd2xyz import/doc link
willschlitzer May 22, 2021
7e7a7fa
format fix
willschlitzer May 22, 2021
6525ff3
create grd2xyz.py
willschlitzer May 22, 2021
13e309c
create test_grd2xyz.py
willschlitzer May 22, 2021
c08d717
spelling fix; change docstring
willschlitzer May 22, 2021
cd26ff2
Merge branch 'master' into wrap-grd2xyz
willschlitzer May 24, 2021
ccd27c0
Merge branch 'master' into wrap-grd2xyz
willschlitzer May 25, 2021
bf58dc2
allow specifiying format for returned xyz data
willschlitzer May 25, 2021
7f100d5
add format tests in test_grd2xyz.py
willschlitzer May 25, 2021
0701d62
change format parameter to xyz_format
willschlitzer May 25, 2021
789ac47
Merge branch 'master' into wrap-grd2xyz
willschlitzer May 25, 2021
8787892
Merge branch 'master' into wrap-grd2xyz
willschlitzer May 26, 2021
11f1782
Merge branch 'master' into wrap-grd2xyz
willschlitzer May 26, 2021
6ac279c
Update pygmt/src/grd2xyz.py
willschlitzer Jul 6, 2021
a226f34
change xyz_format to output_type
willschlitzer Jul 6, 2021
0b52451
change default output to DataFrame
willschlitzer Jul 6, 2021
37d366d
update info return options
willschlitzer Jul 6, 2021
b27699a
add grd2xyz import/doc link
willschlitzer May 22, 2021
0361381
format fix
willschlitzer May 22, 2021
a9fef07
create grd2xyz.py
willschlitzer May 22, 2021
957d8fe
create test_grd2xyz.py
willschlitzer May 22, 2021
5a4baa5
spelling fix; change docstring
willschlitzer May 22, 2021
1cf9e56
allow specifiying format for returned xyz data
willschlitzer May 25, 2021
948ca73
add format tests in test_grd2xyz.py
willschlitzer May 25, 2021
b050cd8
change format parameter to xyz_format
willschlitzer May 25, 2021
9ab9701
Update pygmt/src/grd2xyz.py
willschlitzer Jul 6, 2021
891ff6c
change xyz_format to output_type
willschlitzer Jul 6, 2021
02cd02f
change default output to DataFrame
willschlitzer Jul 6, 2021
00bece0
update info return options
willschlitzer Jul 6, 2021
3b6fc93
Merge branch 'wrap-grd2xyz' of github.com:GenericMappingTools/pygmt i…
willschlitzer Jul 16, 2021
01613ff
change output name to "data" from "info"
willschlitzer Jul 16, 2021
3da6dda
Apply suggestions from code review
willschlitzer Jul 16, 2021
2dcf859
remove numpy import
willschlitzer Jul 16, 2021
283d515
update test_grd2xyz.py
willschlitzer Jul 16, 2021
77315ba
Merge branch 'master' into wrap-grd2xyz
willschlitzer Jul 16, 2021
29c8be6
Apply suggestions from code review
willschlitzer Aug 25, 2021
c4549e4
Apply suggestions from code review
willschlitzer Aug 30, 2021
66761a8
Apply suggestions from code review
willschlitzer Aug 30, 2021
0a525b6
add test_grd2xyz_file_output()
willschlitzer Aug 30, 2021
8de23a8
assign column names in dataframe
willschlitzer Aug 31, 2021
938532a
remove unused import
willschlitzer Aug 31, 2021
161c94b
adding comments
willschlitzer Aug 31, 2021
317a3dd
adding test_grd2xyz_outfile_incorrect_output_type
willschlitzer Sep 1, 2021
41051a9
style fix
willschlitzer Sep 1, 2021
9eebee3
Apply suggestions from code review
willschlitzer Sep 2, 2021
3ac3642
Apply suggestions from code review
willschlitzer Sep 14, 2021
81b0511
Update pygmt/src/grd2xyz.py
willschlitzer Sep 15, 2021
af6aac9
update test
willschlitzer Sep 16, 2021
e1c6555
Apply suggestions from code review
willschlitzer Sep 16, 2021
1927795
add line for grd2xyz region
willschlitzer Sep 16, 2021
95c7731
Merge remote-tracking branch 'origin/wrap-grd2xyz' into wrap-grd2xyz
willschlitzer Sep 16, 2021
76190ab
update region docstring
willschlitzer Sep 16, 2021
31388eb
add if statement
willschlitzer Sep 16, 2021
924a3e0
Apply suggestions from code review
willschlitzer Sep 19, 2021
9a3c377
update comment for o if statement
willschlitzer Sep 19, 2021
4b1214c
change if statement for o
willschlitzer Sep 20, 2021
59bae5c
add test for setting o and output_type to pandas
willschlitzer Sep 20, 2021
2a11880
run make format
willschlitzer Sep 20, 2021
ff45946
typo fix
willschlitzer Sep 20, 2021
290cf04
Merge branch 'main' into wrap-grd2xyz
willschlitzer Sep 22, 2021
e3336c4
Apply suggestions from code review
willschlitzer Sep 22, 2021
552bf3f
Apply suggestions from code review
willschlitzer Sep 22, 2021
6731814
Update pygmt/src/grd2xyz.py
willschlitzer Sep 22, 2021
f49dac0
fix sentence in docstring
willschlitzer Sep 22, 2021
708e3c4
run make format
willschlitzer Sep 22, 2021
f94df58
Merge branch 'main' into wrap-grd2xyz
willschlitzer Sep 22, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/api/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ Operations on grids:
.. autosummary::
:toctree: generated

grd2xyz
grdclip
grdcut
grdfill
Expand Down
1 change: 1 addition & 0 deletions pygmt/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
blockmode,
config,
grd2cpt,
grd2xyz,
grdclip,
grdcut,
grdfill,
Expand Down
1 change: 1 addition & 0 deletions pygmt/src/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from pygmt.src.config import config
from pygmt.src.contour import contour
from pygmt.src.grd2cpt import grd2cpt
from pygmt.src.grd2xyz import grd2xyz
from pygmt.src.grdclip import grdclip
from pygmt.src.grdcontour import grdcontour
from pygmt.src.grdcut import grdcut
Expand Down
118 changes: 118 additions & 0 deletions pygmt/src/grd2xyz.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
"""
grd2xyz - Convert grid to data table
"""
import warnings

import pandas as pd
willschlitzer marked this conversation as resolved.
Show resolved Hide resolved
import xarray as xr
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,
)


@fmt_docstring
@use_alias(
R="region",
V="verbose",
willschlitzer marked this conversation as resolved.
Show resolved Hide resolved
o="outcols",
)
@kwargs_to_strings(R="sequence", o="sequence_comma")
def grd2xyz(grid, output_type="pandas", outfile=None, **kwargs):
r"""
Convert grid to data table.

Read a grid and output xyz-triplets as a :class:`numpy.ndarray`,
:class:`pandas.DataFrame`, or ASCII file.

Full option list at :gmt-docs:`grd2xyz.html`

{aliases}

Parameters
----------
grid : str or xarray.DataArray
The file name of the input grid or the grid loaded as a
:class:`xarray.DataArray`. This is the only required parameter.
output_type : str
Determine the format the xyz data will be returned in [Default is
``pandas``]:

willschlitzer marked this conversation as resolved.
Show resolved Hide resolved
- ``numpy`` - :class:`numpy.ndarray`
- ``pandas``- :class:`pandas.DataFrame`
- ``file`` - ASCII file (requires ``outfile``)
outfile : str
The file name for the output ASCII file.
{R}
seisman marked this conversation as resolved.
Show resolved Hide resolved
Adding ``region`` will select a subsection of the grid. If this
subsection exceeds the boundaries of the grid, only the common region
will be output.
{V}
willschlitzer marked this conversation as resolved.
Show resolved Hide resolved
{o}

Returns
-------
ret : pandas.DataFrame or numpy.ndarray or None
Return type depends on ``outfile`` and ``output_type``:

- None if ``outfile`` is set (output will be stored in file set by
``outfile``)
- :class:`pandas.DataFrame` or :class:`numpy.ndarray` if ``outfile`` is
not set (depends on ``output_type`` [Default is
:class:`pandas.DataFrame`])
willschlitzer marked this conversation as resolved.
Show resolved Hide resolved

"""
if output_type not in ["numpy", "pandas", "file"]:
maxrjones marked this conversation as resolved.
Show resolved Hide resolved
raise GMTInvalidInput(
"Must specify 'output_type' either as 'numpy', 'pandas' or 'file'."
)

if outfile is not None and output_type != "file":
msg = (
f"Changing `output_type` of grd2xyz from '{output_type}' to 'file' "
"since `outfile` parameter is set. Please use `output_type='file'` "
"to silence this warning."
willschlitzer marked this conversation as resolved.
Show resolved Hide resolved
)
warnings.warn(message=msg, category=RuntimeWarning, stacklevel=2)
output_type = "file"
elif outfile is None and output_type == "file":
raise GMTInvalidInput("Must specify `outfile` for ASCII output.")
willschlitzer marked this conversation as resolved.
Show resolved Hide resolved

if "o" in kwargs and output_type == "pandas":
raise GMTInvalidInput(
"If 'outcols' is specified, `output_type` must be either 'numpy'"
willschlitzer marked this conversation as resolved.
Show resolved Hide resolved
"or 'file'."
)

# Set the default column names for the pandas dataframe header
dataframe_header = ["x", "y", "z"]
# Let output pandas column names match input DataArray dimension names
if isinstance(grid, xr.DataArray) and output_type == "pandas":
# Reverse the dims because it is rows, columns ordered.
dataframe_header = [grid.dims[1], grid.dims[0], grid.name]

with GMTTempFile() as tmpfile:
with Session() as lib:
file_context = lib.virtualfile_from_data(check_kind="raster", data=grid)
with file_context as infile:
if outfile is None:
outfile = tmpfile.name
arg_str = " ".join([infile, build_arg_string(kwargs), "->" + outfile])
lib.call_module("grd2xyz", arg_str)

# Read temporary csv output to a pandas table
if outfile == tmpfile.name: # if user did not set outfile, return pd.DataFrame
result = pd.read_csv(
tmpfile.name, sep="\t", names=dataframe_header, comment=">"
)
Comment on lines +109 to +111
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See line 79. If -o is used, dataframe_header is undefined, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not really sure what this is asking me to do. I added an if statement that doesn't pass an argument to names if o is in kwargs.

elif outfile != tmpfile.name: # return None if outfile set, output in outfile
result = None

if output_type == "numpy":
result = result.to_numpy()
return result
96 changes: 96 additions & 0 deletions pygmt/tests/test_grd2xyz.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
"""
Tests for grd2xyz.
"""
import os

import numpy as np
import pandas as pd
import pytest
from pygmt import grd2xyz
from pygmt.datasets import load_earth_relief
from pygmt.exceptions import GMTInvalidInput
from pygmt.helpers import GMTTempFile


@pytest.fixture(scope="module", name="grid")
def fixture_grid():
"""
Load the grid data from the sample earth_relief file.
"""
return load_earth_relief(resolution="01d", region=[-1, 1, 3, 5])


def test_grd2xyz(grid):
"""
Make sure grd2xyz works as expected.
"""
xyz_data = grd2xyz(grid=grid, output_type="numpy")
assert xyz_data.shape == (4, 3)


def test_grd2xyz_format(grid):
"""
Test that correct formats are returned.
"""
lon = -0.5
lat = 3.5
orig_val = grid.sel(lon=lon, lat=lat).to_numpy()
xyz_default = grd2xyz(grid=grid)
xyz_val = xyz_default[(xyz_default["lon"] == lon) & (xyz_default["lat"] == lat)][
"elevation"
].to_numpy()
assert isinstance(xyz_default, pd.DataFrame)
assert orig_val.size == 1
assert xyz_val.size == 1
np.testing.assert_allclose(orig_val, xyz_val)
xyz_array = grd2xyz(grid=grid, output_type="numpy")
assert isinstance(xyz_array, np.ndarray)
xyz_df = grd2xyz(grid=grid, output_type="pandas")
assert isinstance(xyz_df, pd.DataFrame)
assert list(xyz_df.columns) == ["lon", "lat", "elevation"]


def test_grd2xyz_file_output(grid):
"""
Test that grd2xyz returns a file output when it is specified.
"""
with GMTTempFile(suffix=".xyz") as tmpfile:
result = grd2xyz(grid=grid, outfile=tmpfile.name, output_type="file")
assert result is None # return value is None
assert os.path.exists(path=tmpfile.name) # check that outfile exists


def test_grd2xyz_invalid_format(grid):
"""
Test that grd2xyz fails with incorrect format.
"""
with pytest.raises(GMTInvalidInput):
grd2xyz(grid=grid, output_type=1)


def test_grd2xyz_no_outfile(grid):
"""
Test that grd2xyz fails when a string output is set with no outfile.
"""
with pytest.raises(GMTInvalidInput):
grd2xyz(grid=grid, output_type="file")


def test_grd2xyz_outfile_incorrect_output_type(grid):
"""
Test that grd2xyz raises a warning when an outfile name is set but the
output_type is not set to file is set with no outfile.
seisman marked this conversation as resolved.
Show resolved Hide resolved
"""
with pytest.warns(RuntimeWarning):
with GMTTempFile(suffix=".xyz") as tmpfile:
result = grd2xyz(grid=grid, outfile=tmpfile.name, output_type="numpy")
assert result is None # return value is None
assert os.path.exists(path=tmpfile.name) # check that outfile exists


def test_grd2xyz_pandas_output_with_o(grid):
"""
Test that grd2xyz fails when 'o' is set and output_type is set to 'pandas'.
willschlitzer marked this conversation as resolved.
Show resolved Hide resolved
"""
with pytest.raises(GMTInvalidInput):
grd2xyz(grid=grid, output_type="pandas", o="2")
willschlitzer marked this conversation as resolved.
Show resolved Hide resolved