Skip to content

Commit b5aa8a8

Browse files
committed
Let x2sys_file handle multiple input tracks and external crossovers
1 parent 383134f commit b5aa8a8

2 files changed

Lines changed: 65 additions & 24 deletions

File tree

pygmt/tests/test_x2sys_cross.py

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import os
66
from tempfile import TemporaryDirectory
77

8+
import numpy as np
89
import pandas as pd
910
import pytest
1011

@@ -25,14 +26,15 @@ def fixture_mock_x2sys_home(monkeypatch):
2526

2627
def test_x2sys_cross_input_file_output_file(mock_x2sys_home):
2728
"""
28-
Run x2sys_cross by passing in a filename and output to an ASCII txt file
29+
Run x2sys_cross by passing in a filename, and output internal crossovers to
30+
an ASCII txt file
2931
"""
3032
with TemporaryDirectory(prefix="X2SYS", dir=os.getcwd()) as tmpdir:
3133
tag = os.path.basename(tmpdir)
3234
x2sys_init(tag=tag, fmtfile="xyz", force=True)
3335
outfile = os.path.join(tmpdir, "tmp_coe.txt")
3436
output = x2sys_cross(
35-
tracks=["@tut_ship.xyz"], tag=tag, coe="i", outfile=outfile, verbose="d"
37+
tracks=["@tut_ship.xyz"], tag=tag, coe="i", outfile=outfile, verbose="i"
3638
)
3739

3840
assert output is None # check that output is None since outfile is set
@@ -44,12 +46,13 @@ def test_x2sys_cross_input_file_output_file(mock_x2sys_home):
4446

4547
def test_x2sys_cross_input_file_output_dataframe(mock_x2sys_home):
4648
"""
47-
Run x2sys_cross by passing in a filename and output to a pandas.DataFrame
49+
Run x2sys_cross by passing in a filename, and output internal crossovers to
50+
a pandas.DataFrame
4851
"""
4952
with TemporaryDirectory(prefix="X2SYS", dir=os.getcwd()) as tmpdir:
5053
tag = os.path.basename(tmpdir)
5154
x2sys_init(tag=tag, fmtfile="xyz", force=True)
52-
output = x2sys_cross(tracks=["@tut_ship.xyz"], tag=tag, coe="i", verbose="d")
55+
output = x2sys_cross(tracks=["@tut_ship.xyz"], tag=tag, coe="i", verbose="i")
5356

5457
assert isinstance(output, pd.DataFrame)
5558
assert output.shape == (14294, 12)
@@ -58,3 +61,31 @@ def test_x2sys_cross_input_file_output_dataframe(mock_x2sys_home):
5861
assert columns[6:] == ["head_1", "head_2", "vel_1", "vel_2", "z_X", "z_M"]
5962

6063
return output
64+
65+
66+
def test_x2sys_cross_input_two_filenames(mock_x2sys_home):
67+
"""
68+
Run x2sys_cross by passing in two filenames, and output external crossovers
69+
to a pandas.DataFrame
70+
"""
71+
with TemporaryDirectory(prefix="X2SYS", dir=os.getcwd()) as tmpdir:
72+
tag = os.path.basename(tmpdir)
73+
x2sys_init(tag=tag, fmtfile="xyz", force=True)
74+
75+
# Create temporary xyz files
76+
for i in range(2):
77+
np.random.seed(seed=i)
78+
with open(os.path.join(os.getcwd(), f"track_{i}.xyz"), mode="w") as fname:
79+
np.savetxt(fname=fname, X=np.random.rand(10, 3))
80+
81+
output = x2sys_cross(
82+
tracks=["track_0.xyz", "track_1.xyz"], tag=tag, coe="e", verbose="i"
83+
)
84+
85+
assert isinstance(output, pd.DataFrame)
86+
assert output.shape == (24, 12)
87+
columns = list(output.columns)
88+
assert columns[:6] == ["x", "y", "i_1", "i_2", "dist_1", "dist_2"]
89+
assert columns[6:] == ["head_1", "head_2", "vel_1", "vel_2", "z_X", "z_M"]
90+
91+
return output

pygmt/x2sys.py

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
11
"""
22
GMT supplementary X2SYS module for crossover analysis.
33
"""
4+
import contextlib
5+
46
import pandas as pd
57

68
from .clib import Session
9+
10+
# from .exceptions import GMTInvalidInput
711
from .helpers import (
8-
build_arg_string,
9-
fmt_docstring,
1012
GMTTempFile,
11-
use_alias,
13+
build_arg_string,
1214
data_kind,
1315
dummy_context,
16+
fmt_docstring,
17+
use_alias,
1418
)
1519

16-
# from .exceptions import GMTInvalidInput
17-
1820

1921
@fmt_docstring
2022
@use_alias(D="fmtfile", F="force", V="verbose")
@@ -86,10 +88,19 @@ def x2sys_cross(tracks=None, outfile=None, **kwargs):
8688
8789
Parameters
8890
----------
89-
tracks : pandas.DataFrame or str
90-
Either a table with (x, y) or (lon, lat) values in the first two
91-
columns, or a filename (e.g. csv, txt format). More columns may be
92-
present.
91+
tracks : pandas.DataFrame or str or list
92+
Either a single pandas.DataFrame table with (x, y) or (lon, lat) values
93+
in the first two columns, or a single filename (supported formats are
94+
ASCII .txt, native binary, or COARDS netCDF 1-D .nc), or a combination
95+
of tables and/or filenames in a list. More columns may also be present.
96+
97+
If the filenames are missing their file extension, we will append the
98+
suffix specified for this TAG. Track files will be searched for first
99+
in the current directory and second in all directories listed in
100+
$X2SYS_HOME/TAG/TAG_paths.txt (if it exists). [If $X2SYS_HOME is not
101+
set it will default to $GMT_SHAREDIR/x2sys]. (Note: MGD77 files will
102+
also be looked for via $MGD77_HOME/mgd77_paths.txt and *.gmt files will
103+
be searched for via $GMT_SHAREDIR/mgg/gmtfile_paths).
93104
94105
outfile : str
95106
Optional. The file name for the output ASCII txt file to store the
@@ -115,22 +126,21 @@ def x2sys_cross(tracks=None, outfile=None, **kwargs):
115126
- None if outfile is set (track output will be stored in outfile)
116127
117128
"""
118-
# kinds = [data_kind(data=track) for track in tracks]
119-
track = tracks[0]
120-
kind = data_kind(track)
121-
122129
with Session() as lib:
123-
# for kind, track in zip(kinds, tracks):
124-
if kind == "file":
125-
file_context = dummy_context(track)
126-
elif kind == "matrix":
127-
file_context = lib.virtualfile_from_matrix(track.values)
130+
file_contexts = []
131+
for track in tracks:
132+
kind = data_kind(track)
133+
if kind == "file":
134+
file_contexts.append(dummy_context(track))
135+
elif kind == "matrix":
136+
file_contexts.append(lib.virtualfile_from_matrix(track.values))
128137

129138
with GMTTempFile(suffix=".txt") as tmpfile:
130-
with file_context as fname:
139+
with contextlib.ExitStack() as stack:
140+
fnames = [stack.enter_context(c) for c in file_contexts]
131141
if outfile is None:
132142
outfile = tmpfile.name
133-
arg_str = " ".join([fname, build_arg_string(kwargs), "->" + outfile])
143+
arg_str = " ".join([*fnames, build_arg_string(kwargs), "->" + outfile])
134144
lib.call_module(module="x2sys_cross", args=arg_str)
135145

136146
# Read temporary csv output to a pandas table

0 commit comments

Comments
 (0)