Skip to content

Commit

Permalink
Merge branch 'main' into load_tile_map/doctest
Browse files Browse the repository at this point in the history
  • Loading branch information
seisman authored Mar 15, 2024
2 parents 42ba2bc + 3a507a8 commit 5a485a4
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 223 deletions.
12 changes: 12 additions & 0 deletions pygmt/helpers/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,18 @@
input and skip trailing text. **Note**: If ``incols`` is also
used then the columns given to ``outcols`` correspond to the
order after the ``incols`` selection has taken place.""",
"outfile": """
outfile
File name for saving the result data. Required if ``output_type="file"``.
If specified, ``output_type`` will be forced to be ``"file"``.""",
"output_type": """
output_type
Desired output type of the result data.
- ``pandas`` will return a :class:`pandas.DataFrame` object.
- ``numpy`` will return a :class:`numpy.ndarray` object.
- ``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
Expand Down
40 changes: 32 additions & 8 deletions pygmt/helpers/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,51 @@
"""

import warnings
from typing import Literal

from pygmt.exceptions import GMTInvalidInput


def validate_output_table_type(output_type, outfile=None):
def validate_output_table_type(
output_type: Literal["pandas", "numpy", "file"], outfile: str | None = None
) -> Literal["pandas", "numpy", "file"]:
"""
Check if the ``output_type`` and ``outfile`` parameters are valid.
Parameters
----------
output_type : str
The type for a table output. Valid values are "file", "numpy", and
"pandas".
outfile : str
The file name for the output table file. Required if
``output_type="file"``.
output_type
Desired output type of tabular data. Valid values are ``"pandas"``,
``"numpy"`` and ``"file"``.
outfile
File name for saving the result data. Required if ``output_type`` is ``"file"``.
If specified, ``output_type`` will be forced to be ``"file"``.
Returns
-------
str
The original or corrected output type.
The original or updated output type.
Examples
--------
>>> validate_output_table_type(output_type="pandas")
'pandas'
>>> validate_output_table_type(output_type="numpy")
'numpy'
>>> validate_output_table_type(output_type="file", outfile="output-fname.txt")
'file'
>>> validate_output_table_type(output_type="invalid-type")
Traceback (most recent call last):
...
pygmt.exceptions.GMTInvalidInput: Must specify 'output_type' either as 'file', ...
>>> validate_output_table_type("file", outfile=None)
Traceback (most recent call last):
...
pygmt.exceptions.GMTInvalidInput: Must specify 'outfile' for output_type='file'.
>>> with warnings.catch_warnings(record=True) as w:
... validate_output_table_type("pandas", outfile="not-none.txt")
... assert len(w) == 1
'file'
"""
if output_type not in ["file", "numpy", "pandas"]:
raise GMTInvalidInput(
Expand Down
62 changes: 25 additions & 37 deletions pygmt/src/filter1d.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
filter1d - Time domain filtering of 1-D data tables
"""

from typing import Literal

import numpy as np
import pandas as pd
from pygmt.clib import Session
from pygmt.exceptions import GMTInvalidInput
from pygmt.helpers import (
GMTTempFile,
build_arg_string,
fmt_docstring,
use_alias,
Expand All @@ -20,7 +22,12 @@
F="filter_type",
N="time_col",
)
def filter1d(data, output_type="pandas", outfile=None, **kwargs):
def filter1d(
data,
output_type: Literal["pandas", "numpy", "file"] = "pandas",
outfile: str | None = None,
**kwargs,
) -> pd.DataFrame | np.ndarray | None:
r"""
Time domain filtering of 1-D data tables.
Expand All @@ -38,6 +45,8 @@ def filter1d(data, output_type="pandas", outfile=None, **kwargs):
Parameters
----------
{output_type}
{outfile}
filter_type : str
**type**\ *width*\ [**+h**].
Set the filter **type**. Choose among convolution and non-convolution
Expand Down Expand Up @@ -91,48 +100,27 @@ def filter1d(data, output_type="pandas", outfile=None, **kwargs):
left-most column is 0, while the right-most is (*n_cols* - 1)
[Default is ``0``].
output_type : str
Determine the format the xyz data will be returned in [Default is
``pandas``]:
- ``numpy`` - :class:`numpy.ndarray`
- ``pandas``- :class:`pandas.DataFrame`
- ``file`` - ASCII file (requires ``outfile``)
outfile : str
The file name for the output ASCII file.
Returns
-------
ret : pandas.DataFrame or numpy.ndarray or None
ret
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`])
- 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``)
"""
if kwargs.get("F") is None:
raise GMTInvalidInput("Pass a required argument to 'filter_type'.")

output_type = validate_output_table_type(output_type, outfile=outfile)

with GMTTempFile() as tmpfile:
with Session() as lib:
with lib.virtualfile_in(check_kind="vector", data=data) as vintbl:
if outfile is None:
outfile = tmpfile.name
lib.call_module(
module="filter1d",
args=build_arg_string(kwargs, infile=vintbl, outfile=outfile),
)

# 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", header=None, comment=">")
elif outfile != tmpfile.name: # return None if outfile set, output in outfile
result = None

if output_type == "numpy":
result = result.to_numpy()
return result
with Session() as lib:
with (
lib.virtualfile_in(check_kind="vector", data=data) as vintbl,
lib.virtualfile_out(kind="dataset", fname=outfile) as vouttbl,
):
lib.call_module(
module="filter1d",
args=build_arg_string(kwargs, infile=vintbl, outfile=vouttbl),
)
return lib.virtualfile_to_dataset(output_type=output_type, vfname=vouttbl)
75 changes: 34 additions & 41 deletions pygmt/src/grd2xyz.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,24 @@
grd2xyz - Convert grid to data table
"""

from typing import TYPE_CHECKING, Literal

import numpy as np
import pandas as pd
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,
validate_output_table_type,
)

if TYPE_CHECKING:
from collections.abc import Hashable

__doctest_skip__ = ["grd2xyz"]


Expand All @@ -33,7 +38,12 @@
s="skiprows",
)
@kwargs_to_strings(R="sequence", o="sequence_comma")
def grd2xyz(grid, output_type="pandas", outfile=None, **kwargs):
def grd2xyz(
grid,
output_type: Literal["pandas", "numpy", "file"] = "pandas",
outfile: str | None = None,
**kwargs,
) -> pd.DataFrame | np.ndarray | None:
r"""
Convert grid to data table.
Expand All @@ -47,15 +57,8 @@ def grd2xyz(grid, output_type="pandas", outfile=None, **kwargs):
Parameters
----------
{grid}
output_type : str
Determine the format the xyz data will be returned in [Default is
``pandas``]:
- ``numpy`` - :class:`numpy.ndarray`
- ``pandas``- :class:`pandas.DataFrame`
- ``file`` - ASCII file (requires ``outfile``)
outfile : str
The file name for the output ASCII file.
{output_type}
{outfile}
cstyle : str
[**f**\|\ **i**].
Replace the x- and y-coordinates on output with the corresponding
Expand Down Expand Up @@ -118,13 +121,12 @@ def grd2xyz(grid, output_type="pandas", outfile=None, **kwargs):
Returns
-------
ret : pandas.DataFrame or numpy.ndarray or None
ret
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``)
- 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``)
Example
-------
Expand All @@ -149,31 +151,22 @@ def grd2xyz(grid, output_type="pandas", outfile=None, **kwargs):
"or 'file'."
)

# Set the default column names for the pandas dataframe header
dataframe_header = ["x", "y", "z"]
# Set the default column names for the pandas dataframe header.
column_names: list[Hashable] = ["x", "y", "z"]
# Let output pandas column names match input DataArray dimension names
if isinstance(grid, xr.DataArray) and output_type == "pandas":
if output_type == "pandas" and isinstance(grid, xr.DataArray):
# 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:
with lib.virtualfile_in(check_kind="raster", data=grid) as vingrd:
if outfile is None:
outfile = tmpfile.name
lib.call_module(
module="grd2xyz",
args=build_arg_string(kwargs, infile=vingrd, outfile=outfile),
)

# 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=">"
column_names = [grid.dims[1], grid.dims[0], grid.name]

with Session() as lib:
with (
lib.virtualfile_in(check_kind="raster", data=grid) as vingrd,
lib.virtualfile_out(kind="dataset", fname=outfile) as vouttbl,
):
lib.call_module(
module="grd2xyz",
args=build_arg_string(kwargs, infile=vingrd, outfile=vouttbl),
)
return lib.virtualfile_to_dataset(
output_type=output_type, vfname=vouttbl, column_names=column_names
)
elif outfile != tmpfile.name: # return None if outfile set, output in outfile
result = None

if output_type == "numpy":
result = result.to_numpy()
return result
Loading

0 comments on commit 5a485a4

Please sign in to comment.