import datetime
import logging
from pytplot import get_data, store, tnames
import numpy as np
[docs]
def tinterpol(names, interp_to, method=None, newname=None, suffix=None):
"""
Interpolate data to times in interp_to.
Parameters
----------
names : array_like or str
List of tplot variables to interpolate.
Allowed wildcards are ? for a single character, * from multiple characters.
interp_to : array_like or str
String containing the tplot variable with the time stamps to interpolate to.
method : str, optional
Interpolation method. Default is 'linear'.
Specifies the kind of interpolation as a string ('linear', 'nearest', 'zero', 'slinear', 'quadratic', 'cubic', 'previous', 'next')
where 'zero', 'slinear', 'quadratic' and 'cubic' refer to a spline interpolation of zeroth, first, second or third order;
'previous' and 'next' simply return the previous or next value of the point) or as an integer specifying the order of the spline interpolator to use.
newname : str or list of str, optional
List of new names for pytplot variables. If '', then pytplot variables are replaced. If not given, then a suffix is applied.
suffix : str, optional
A suffix to apply. Default is '-itrp'.
Returns
-------
None
This function works in-place or creates new pytplot variables depending on the 'newname' parameter.
Notes
-----
Uses xarray interp method to interpolate data to the times in interp_to.
See: https://docs.xarray.dev/en/latest/generated/xarray.DataArray.interp.html
Similar to tinterpol.pro in IDL SPEDAS.
Examples
--------
import numpy as np
import pytplot
import pyspedas
# Create some time series data
times = np.array(['2002-02-03T04:05:00', '2002-02-03T04:05:05', '2002-02-03T04:05:10'], dtype='datetime64')
data = np.array([0.0, 5.0, 10.0])
# Store the data in pytplot
pytplot.store_data('variable1', data={'x': times, 'y': data})
# Create some new times to interpolate to
new_times = np.array(['2002-02-03T04:05:07', '2002-02-03T04:05:08', '2002-02-03T04:05:09'], dtype='datetime64')
new_data = np.array([11.0, 12.0, 13.0])
# Store the new times in pytplot, the new_data will be ignored
pytplot.store_data('variable2', data={'x': new_times, 'y': new_data})
# Interpolate 'variable1' to the new times using the default linear method
pyspedas.tinterpol(names='variable1', interp_to='variable2')
# The interpolated data is now stored in 'variable1-itrp'
interpolated_data = pytplot.get_data('variable1-itrp')
print(interpolated_data)
"""
if not isinstance(names, list):
names = [names]
if not isinstance(newname, list):
newname = [newname]
old_names = tnames(names) # expand any wildcards
if len(old_names) < 1:
logging.error("tinterpol error: No pytplot names were provided.")
return
if suffix is None:
suffix = "-itrp"
if method is None:
method = "linear"
if (newname is None) or (len(newname) == 1 and newname[0] is None):
n_names = [s + suffix for s in old_names]
else:
n_names = newname
if isinstance(interp_to, str):
interp_to_data = get_data(interp_to, dt=True)
if interp_to_data is None:
logging.error("Error, tplot variable: " + interp_to + " not found.")
return
interp_to_times = interp_to_data[0]
else:
interp_to_times = interp_to
for name_idx, name in enumerate(old_names):
xdata = get_data(name, xarray=True)
metadata = get_data(name, metadata=True)
if isinstance(interp_to_times[0], (datetime.datetime, np.datetime64)):
# Timezone-naive datetime or np.datetime64, use as-is
interp_to_datetimes = interp_to_times
elif isinstance(interp_to_times[0], (int, float, np.integer, np.float64)):
# Assume seconds since Unix epoch, convert to np.datetime64 with nanosecond precision
if isinstance(interp_to_times, np.ndarray):
interp_to_datetimes = np.array(
interp_to_times * 1e09, dtype="datetime64[ns]"
)
else:
# We need to convert input to a numpy array before scaling to nanoseconds
interp_to_datetimes = np.array(
np.array(interp_to_times) * 1e9, dtype="datetime64[ns]"
)
elif isinstance(interp_to_times[0], str):
# Interpret strings as timestamps, convert to np.datetime64 with nanosecond precision
interp_to_datetimes = np.array(interp_to_times, dtype="datetime64[ns]")
else:
# Give up for any other type
logging.error(
"tinterpol: Unable to convert type %s to timestamp.",
type(interp_to_times[0]),
)
return
xdata_interpolated = xdata.interp({"time": interp_to_datetimes}, method=method)
if "spec_bins" in xdata.coords:
store(
n_names[name_idx],
data={
"x": interp_to_times,
"y": xdata_interpolated.values,
"v": xdata_interpolated.coords["spec_bins"].values,
},
metadata=metadata,
)
else:
store(
n_names[name_idx],
data={"x": interp_to_times, "y": xdata_interpolated.values},
metadata=metadata,
)
logging.info("tinterpol (" + method + ") was applied to: " + n_names[name_idx])