5
5
import contextlib
6
6
import os
7
7
from pathlib import Path
8
+ from typing import Literal
8
9
9
10
import pandas as pd
10
- from packaging .version import Version
11
11
from pygmt .clib import Session
12
12
from pygmt .exceptions import GMTInvalidInput
13
13
from pygmt .helpers import (
14
- GMTTempFile ,
15
14
build_arg_list ,
16
15
data_kind ,
17
16
fmt_docstring ,
18
17
kwargs_to_strings ,
19
18
unique_name ,
20
19
use_alias ,
20
+ validate_output_table_type ,
21
21
)
22
22
23
23
@@ -71,7 +71,12 @@ def tempfile_from_dftrack(track, suffix):
71
71
Z = "trackvalues" ,
72
72
)
73
73
@kwargs_to_strings (R = "sequence" )
74
- def x2sys_cross (tracks = None , outfile = None , ** kwargs ):
74
+ def x2sys_cross (
75
+ tracks = None ,
76
+ output_type : Literal ["pandas" , "numpy" , "file" ] = "pandas" ,
77
+ outfile : str | None = None ,
78
+ ** kwargs ,
79
+ ):
75
80
r"""
76
81
Calculate crossovers between track data files.
77
82
@@ -192,6 +197,8 @@ def x2sys_cross(tracks=None, outfile=None, **kwargs):
192
197
- None if ``outfile`` is set (track output will be stored in the set in
193
198
``outfile``)
194
199
"""
200
+ output_type = validate_output_table_type (output_type , outfile = outfile )
201
+
195
202
with Session () as lib :
196
203
file_contexts = []
197
204
for track in tracks :
@@ -216,35 +223,21 @@ def x2sys_cross(tracks=None, outfile=None, **kwargs):
216
223
else :
217
224
raise GMTInvalidInput (f"Unrecognized data type: { type (track )} " )
218
225
219
- with GMTTempFile ( suffix = ".txt" ) as tmpfile :
226
+ with lib . virtualfile_out ( kind = "dataset" , fname = outfile ) as vouttbl :
220
227
with contextlib .ExitStack () as stack :
221
228
fnames = [stack .enter_context (c ) for c in file_contexts ]
222
- if outfile is None :
223
- outfile = tmpfile .name
224
229
lib .call_module (
225
230
module = "x2sys_cross" ,
226
- args = build_arg_list (kwargs , infile = fnames , outfile = outfile ),
227
- )
228
-
229
- # Read temporary csv output to a pandas table
230
- if outfile == tmpfile .name : # if outfile isn't set, return pd.DataFrame
231
- # Read the tab-separated ASCII table
232
- date_format_kwarg = (
233
- {"date_format" : "ISO8601" }
234
- if Version (pd .__version__ ) >= Version ("2.0.0" )
235
- else {}
231
+ args = build_arg_list (kwargs , infile = fnames , outfile = vouttbl ),
236
232
)
237
- table = pd .read_csv (
238
- tmpfile .name ,
239
- sep = "\t " ,
240
- header = 2 , # Column names are on 2nd row
241
- comment = ">" , # Skip the 3rd row with a ">"
242
- parse_dates = [2 , 3 ], # Datetimes on 3rd and 4th column
243
- ** date_format_kwarg , # Parse dates in ISO8601 format on pandas>=2
233
+ result = lib .virtualfile_to_dataset (
234
+ vfname = vouttbl , output_type = output_type , header = 2
244
235
)
245
- # Remove the "# " from "# x" in the first column
246
- table = table .rename (columns = {table .columns [0 ]: table .columns [0 ][2 :]})
247
- elif outfile != tmpfile .name : # if outfile is set, output in outfile only
248
- table = None
249
236
250
- return table
237
+ # Convert 3rd and 4th columns to datetimes.
238
+ # These two columns have names "t_1"/"t_2" or "i_1"/"i_2".
239
+ # "t_1"/"t_2" means they are datetimes and should be converted.
240
+ # "i_1"/"i_2" means they are dummy times (i.e., floating-point values).
241
+ if output_type == "pandas" and result .columns [2 ] == "t_1" :
242
+ result .iloc [:, 2 :4 ] = result .iloc [:, 2 :4 ].apply (pd .to_datetime )
243
+ return result
0 commit comments