Skip to content

Commit 891c5ed

Browse files
author
Meghan Jones
authored
Refactor blockm* to use virtualfile_from_data and improve i/o (#1280)
- Enables blockm* to work with table-like inputs besides pandas.DataFrame - Makes outfile parameter optional - Loads output data as a pandas.DataFrame when outfile is unset - Updates unit tests accordingly
1 parent b28448b commit 891c5ed

File tree

3 files changed

+59
-61
lines changed

3 files changed

+59
-61
lines changed

pygmt/src/blockm.py

+19-29
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,9 @@
33
"""
44
import pandas as pd
55
from pygmt.clib import Session
6-
from pygmt.exceptions import GMTInvalidInput
76
from pygmt.helpers import (
87
GMTTempFile,
98
build_arg_string,
10-
data_kind,
11-
dummy_context,
129
fmt_docstring,
1310
kwargs_to_strings,
1411
use_alias,
@@ -41,29 +38,24 @@ def _blockm(block_method, table, outfile, **kwargs):
4138
set by ``outfile``)
4239
"""
4340

44-
kind = data_kind(table)
4541
with GMTTempFile(suffix=".csv") as tmpfile:
4642
with Session() as lib:
47-
if kind == "matrix":
48-
if not hasattr(table, "values"):
49-
raise GMTInvalidInput(f"Unrecognized data type: {type(table)}")
50-
file_context = lib.virtualfile_from_matrix(table.values)
51-
elif kind == "file":
52-
if outfile is None:
53-
raise GMTInvalidInput("Please pass in a str to 'outfile'")
54-
file_context = dummy_context(table)
55-
else:
56-
raise GMTInvalidInput(f"Unrecognized data type: {type(table)}")
57-
58-
with file_context as infile:
43+
# Choose how data will be passed into the module
44+
table_context = lib.virtualfile_from_data(check_kind="vector", data=table)
45+
# Run blockm* on data table
46+
with table_context as infile:
5947
if outfile is None:
6048
outfile = tmpfile.name
6149
arg_str = " ".join([infile, build_arg_string(kwargs), "->" + outfile])
6250
lib.call_module(module=block_method, args=arg_str)
6351

6452
# Read temporary csv output to a pandas table
6553
if outfile == tmpfile.name: # if user did not set outfile, return pd.DataFrame
66-
result = pd.read_csv(tmpfile.name, sep="\t", names=table.columns)
54+
try:
55+
column_names = table.columns.to_list()
56+
result = pd.read_csv(tmpfile.name, sep="\t", names=column_names)
57+
except AttributeError: # 'str' object has no attribute 'columns'
58+
result = pd.read_csv(tmpfile.name, sep="\t", header=None, comment=">")
6759
elif outfile != tmpfile.name: # return None if outfile set, output in outfile
6860
result = None
6961

@@ -95,10 +87,10 @@ def blockmean(table, outfile=None, **kwargs):
9587
9688
Parameters
9789
----------
98-
table : pandas.DataFrame or str
99-
Either a pandas dataframe with (x, y, z) or (longitude, latitude,
100-
elevation) values in the first three columns, or a file name to an
101-
ASCII data table.
90+
table : str or {table-like}
91+
Pass in (x, y, z) or (longitude, latitude, elevation) values by
92+
providing a file name to an ASCII data table, a 2D
93+
{table-classes}.
10294
10395
spacing : str
10496
*xinc*\[\ *unit*\][**+e**\|\ **n**]
@@ -110,8 +102,7 @@ def blockmean(table, outfile=None, **kwargs):
110102
Specify the region of interest.
111103
112104
outfile : str
113-
Required if ``table`` is a file. The file name for the output ASCII
114-
file.
105+
The file name for the output ASCII file.
115106
116107
{V}
117108
{a}
@@ -156,10 +147,10 @@ def blockmedian(table, outfile=None, **kwargs):
156147
157148
Parameters
158149
----------
159-
table : pandas.DataFrame or str
160-
Either a pandas dataframe with (x, y, z) or (longitude, latitude,
161-
elevation) values in the first three columns, or a file name to an
162-
ASCII data table.
150+
table : str or {table-like}
151+
Pass in (x, y, z) or (longitude, latitude, elevation) values by
152+
providing a file name to an ASCII data table, a 2D
153+
{table-classes}.
163154
164155
spacing : str
165156
*xinc*\[\ *unit*\][**+e**\|\ **n**]
@@ -171,8 +162,7 @@ def blockmedian(table, outfile=None, **kwargs):
171162
Specify the region of interest.
172163
173164
outfile : str
174-
Required if ``table`` is a file. The file name for the output ASCII
175-
file.
165+
The file name for the output ASCII file.
176166
177167
{V}
178168
{a}

pygmt/tests/test_blockmean.py

+20-16
Original file line numberDiff line numberDiff line change
@@ -12,38 +12,42 @@
1212
from pygmt.helpers import GMTTempFile, data_kind
1313

1414

15-
def test_blockmean_input_dataframe():
15+
@pytest.fixture(scope="module", name="dataframe")
16+
def fixture_dataframe():
17+
"""
18+
Load the grid data from the sample earth_relief file.
19+
"""
20+
return load_sample_bathymetry()
21+
22+
23+
def test_blockmean_input_dataframe(dataframe):
1624
"""
1725
Run blockmean by passing in a pandas.DataFrame as input.
1826
"""
19-
dataframe = load_sample_bathymetry()
2027
output = blockmean(table=dataframe, spacing="5m", region=[245, 255, 20, 30])
2128
assert isinstance(output, pd.DataFrame)
2229
assert all(dataframe.columns == output.columns)
2330
assert output.shape == (5849, 3)
2431
npt.assert_allclose(output.iloc[0], [245.888877, 29.978707, -384.0])
2532

26-
return output
2733

28-
29-
def test_blockmean_wrong_kind_of_input_table_matrix():
34+
def test_blockmean_input_table_matrix(dataframe):
3035
"""
3136
Run blockmean using table input that is not a pandas.DataFrame but still a
3237
matrix.
3338
"""
34-
dataframe = load_sample_bathymetry()
35-
invalid_table = dataframe.values
36-
assert data_kind(invalid_table) == "matrix"
37-
with pytest.raises(GMTInvalidInput):
38-
blockmean(table=invalid_table, spacing="5m", region=[245, 255, 20, 30])
39+
table = dataframe.values
40+
output = blockmean(table=table, spacing="5m", region=[245, 255, 20, 30])
41+
assert isinstance(output, pd.DataFrame)
42+
assert output.shape == (5849, 3)
43+
npt.assert_allclose(output.iloc[0], [245.888877, 29.978707, -384.0])
3944

4045

41-
def test_blockmean_wrong_kind_of_input_table_grid():
46+
def test_blockmean_wrong_kind_of_input_table_grid(dataframe):
4247
"""
4348
Run blockmean using table input that is not a pandas.DataFrame or file but
4449
a grid.
4550
"""
46-
dataframe = load_sample_bathymetry()
4751
invalid_table = dataframe.bathymetry.to_xarray()
4852
assert data_kind(invalid_table) == "grid"
4953
with pytest.raises(GMTInvalidInput):
@@ -67,12 +71,12 @@ def test_blockmean_input_filename():
6771
assert output.shape == (5849, 3)
6872
npt.assert_allclose(output.iloc[0], [245.888877, 29.978707, -384.0])
6973

70-
return output
71-
7274

7375
def test_blockmean_without_outfile_setting():
7476
"""
7577
Run blockmean by not passing in outfile parameter setting.
7678
"""
77-
with pytest.raises(GMTInvalidInput):
78-
blockmean(table="@tut_ship.xyz", spacing="5m", region=[245, 255, 20, 30])
79+
output = blockmean(table="@tut_ship.xyz", spacing="5m", region=[245, 255, 20, 30])
80+
assert isinstance(output, pd.DataFrame)
81+
assert output.shape == (5849, 3)
82+
npt.assert_allclose(output.iloc[0], [245.888877, 29.978707, -384.0])

pygmt/tests/test_blockmedian.py

+20-16
Original file line numberDiff line numberDiff line change
@@ -12,38 +12,42 @@
1212
from pygmt.helpers import GMTTempFile, data_kind
1313

1414

15-
def test_blockmedian_input_dataframe():
15+
@pytest.fixture(scope="module", name="dataframe")
16+
def fixture_dataframe():
17+
"""
18+
Load the grid data from the sample earth_relief file.
19+
"""
20+
return load_sample_bathymetry()
21+
22+
23+
def test_blockmedian_input_dataframe(dataframe):
1624
"""
1725
Run blockmedian by passing in a pandas.DataFrame as input.
1826
"""
19-
dataframe = load_sample_bathymetry()
2027
output = blockmedian(table=dataframe, spacing="5m", region=[245, 255, 20, 30])
2128
assert isinstance(output, pd.DataFrame)
2229
assert all(dataframe.columns == output.columns)
2330
assert output.shape == (5849, 3)
2431
npt.assert_allclose(output.iloc[0], [245.88819, 29.97895, -385.0])
2532

26-
return output
2733

28-
29-
def test_blockmedian_wrong_kind_of_input_table_matrix():
34+
def test_blockmedian_wrong_kind_of_input_table_matrix(dataframe):
3035
"""
3136
Run blockmedian using table input that is not a pandas.DataFrame but still
3237
a matrix.
3338
"""
34-
dataframe = load_sample_bathymetry()
35-
invalid_table = dataframe.values
36-
assert data_kind(invalid_table) == "matrix"
37-
with pytest.raises(GMTInvalidInput):
38-
blockmedian(table=invalid_table, spacing="5m", region=[245, 255, 20, 30])
39+
table = dataframe.values
40+
output = blockmedian(table=table, spacing="5m", region=[245, 255, 20, 30])
41+
assert isinstance(output, pd.DataFrame)
42+
assert output.shape == (5849, 3)
43+
npt.assert_allclose(output.iloc[0], [245.88819, 29.97895, -385.0])
3944

4045

41-
def test_blockmedian_wrong_kind_of_input_table_grid():
46+
def test_blockmedian_wrong_kind_of_input_table_grid(dataframe):
4247
"""
4348
Run blockmedian using table input that is not a pandas.DataFrame or file
4449
but a grid.
4550
"""
46-
dataframe = load_sample_bathymetry()
4751
invalid_table = dataframe.bathymetry.to_xarray()
4852
assert data_kind(invalid_table) == "grid"
4953
with pytest.raises(GMTInvalidInput):
@@ -67,12 +71,12 @@ def test_blockmedian_input_filename():
6771
assert output.shape == (5849, 3)
6872
npt.assert_allclose(output.iloc[0], [245.88819, 29.97895, -385.0])
6973

70-
return output
71-
7274

7375
def test_blockmedian_without_outfile_setting():
7476
"""
7577
Run blockmedian by not passing in outfile parameter setting.
7678
"""
77-
with pytest.raises(GMTInvalidInput):
78-
blockmedian(table="@tut_ship.xyz", spacing="5m", region=[245, 255, 20, 30])
79+
output = blockmedian(table="@tut_ship.xyz", spacing="5m", region=[245, 255, 20, 30])
80+
assert isinstance(output, pd.DataFrame)
81+
assert output.shape == (5849, 3)
82+
npt.assert_allclose(output.iloc[0], [245.88819, 29.97895, -385.0])

0 commit comments

Comments
 (0)