Esempio n. 1
0
def build_time_index(
    time: types_timeindex = None,
    time_ref: pd.Timestamp = None,
) -> pd.TimedeltaIndex:
    """Build time index used for xarray objects.

    Parameters
    ----------
    time:
        Datetime- or Timedelta-like time index.
    time_ref:
        Reference timestamp for Timedelta inputs.

    Returns
    -------
    pandas.TimedeltaIndex

    """
    if time is None:
        return time, time_ref

    time = util.to_pandas_time_index(time)

    if isinstance(time, pd.DatetimeIndex):
        if time_ref is None:
            time_ref = time[0]
        time = time - time_ref

    return time, time_ref
Esempio n. 2
0
    def test_interp_time(ts, time, magnitude_exp, unit_exp):
        """Test the interp_time function."""
        result = ts.interp_time(time)

        assert np.all(np.isclose(result.data.magnitude, magnitude_exp))
        assert Q_(1, str(result.data.units)) == Q_(1, unit_exp)

        if isinstance(time, pint.Quantity):
            assert np.all(result.time == ut.to_pandas_time_index(time))
        else:
            assert np.all(result.time == time)
Esempio n. 3
0
    def time(self) -> Union[None, pd.TimedeltaIndex]:
        """Return the data's timestamps.

        Returns
        -------
        pandas.TimedeltaIndex:
            Timestamps of the  data

        """
        if isinstance(self._data, xr.DataArray) and len(self._data.time) > 1:
            return ut.to_pandas_time_index(self._data.time.data)
        return None
Esempio n. 4
0
    def interp_time(
        self,
        time: types_time_and_lcs,
        time_ref: Union[pd.Timestamp, None] = None,
    ) -> "LocalCoordinateSystem":
        """Interpolates the data in time.

        Parameters
        ----------
        time :
            Series of times.
            If passing "None" no interpolation will be performed.
        time_ref:
            The reference timestamp

        Returns
        -------
        LocalCoordinateSystem
            Coordinate system with interpolated data

        """
        if (not self.is_time_dependent) or (time is None):
            return self

        # use LCS reference time if none provided
        if isinstance(time, LocalCoordinateSystem) and time_ref is None:
            time_ref = time.reference_time
        time = ut.to_pandas_time_index(time)

        if self.has_reference_time != (time_ref is not None
                                       or isinstance(time, pd.DatetimeIndex)):
            raise TypeError(
                "Only 1 reference time provided for time dependent coordinate "
                "system. Either the reference time of the coordinate system or the "
                "one passed to the function is 'None'. Only cases where the "
                "reference times are both 'None' or both contain a timestamp are "
                "allowed. Also check that the reference time has the correct type."
            )

        if self.has_reference_time and (not isinstance(time,
                                                       pd.DatetimeIndex)):
            time = time + time_ref

        orientation = ut.xr_interp_orientation_in_time(self.orientation, time)
        coordinates = ut.xr_interp_coordinates_in_time(self.coordinates, time)

        return LocalCoordinateSystem(orientation,
                                     coordinates,
                                     time_ref=time_ref)
Esempio n. 5
0
    def interp_time(self,
                    time: Union[pd.TimedeltaIndex, pint.Quantity],
                    time_unit: str = "s") -> xr.DataArray:
        """Interpolate the TimeSeries in time.

        If the internal data consists of discrete values, an interpolation with the
        prescribed interpolation method is performed. In case of mathematical
        expression, the expression is evaluated for the given timestamps.

        Parameters
        ----------
        time:
            A set of timestamps.
        time_unit:
            Only important if the time series is described by an expression and a
            'pandas.TimedeltaIndex' is passed to this function. In this case, time is
            converted to a quantity with the provided unit. Even though pint handles
            unit prefixes automatically, the accuracy of the results can be heavily
            influenced if the provided unit results in extreme large or
            small values when compared to the parameters of the expression.

        Returns
        -------
        xarray.DataArray:
            A data array containing the interpolated data.

        """
        if isinstance(self._data, xr.DataArray):
            if isinstance(time, pint.Quantity):
                time = ut.to_pandas_time_index(time)
            if not isinstance(time, pd.TimedeltaIndex):
                raise ValueError(
                    '"time" must be a time quantity or a "pandas.TimedeltaIndex".'
                )
            # constant values are also treated by this branch
            if self._data.attrs["interpolation"] == "linear" or self.shape[
                    0] == 1:
                return ut.xr_interp_like(
                    self._data,
                    {"time": time},
                    assume_sorted=False,
                    broadcast_missing=False,
                )

            dax = self._data.reindex({"time": time}, method="ffill")
            return dax.fillna(self._data[0])

        # Transform time to both formats
        if isinstance(time, pint.Quantity) and time.check(
                UREG.get_dimensionality("s")):
            time_q = time
            time_pd = ut.to_pandas_time_index(time)
        elif isinstance(time, pd.TimedeltaIndex):
            time_q = ut.pandas_time_delta_to_quantity(time, time_unit)
            time_pd = time
        else:
            raise ValueError(
                '"time" must be a time quantity or a "pandas.TimedeltaIndex".')

        if len(self.shape) > 1 and np.iterable(time_q):
            while len(time_q.shape) < len(self.shape):
                time_q = time_q[:, np.newaxis]

        # evaluate expression
        data = self._data.evaluate(**{self._time_var_name: time_q})
        data = data.astype(
            float).to_reduced_units()  # float conversion before reduce!

        # create data array
        if not np.iterable(data):  # make sure quantity is not scalar value
            data = np.expand_dims(data, 0)

        dax = xr.DataArray(data=data)  # don't know exact dimensions so far
        return dax.rename({"dim_0": "time"}).assign_coords({"time": time_pd})
Esempio n. 6
0
    def __init__(
        self,
        data: Union[pint.Quantity, MathematicalExpression],
        time: Union[None, pd.TimedeltaIndex, pint.Quantity] = None,
        interpolation: str = "linear",
    ):
        """Construct a TimSeries.

        Parameters
        ----------
        data:
            Either a pint.Quantity or a weldx.MathematicalExpression. If a mathematical
            expression is chosen, it is only allowed to have a single free variable,
            which represents time.
        time:
            An instance of pandas.TimedeltaIndex if a quantity is passed and 'None'
            otherwise.
        interpolation:
            A string defining the desired interpolation method. This is only relevant if
            a quantity is passed as data. Currently supported interpolation methods are:
            'step', 'linear'.

        """
        self._data = None
        self._time_var_name = None
        self._shape = None
        self._units = None

        if isinstance(data, pint.Quantity):
            if not np.iterable(data):  # expand dim for scalar input
                data = np.expand_dims(data, 0)
            if time is None:  # constant value case
                time = pd.TimedeltaIndex([0])
                interpolation = None
            elif interpolation not in self._valid_interpolations:
                raise ValueError(
                    "A valid interpolation method must be specified if discrete "
                    f'values are used. "{interpolation}" is not supported')
            if isinstance(time, pint.Quantity):
                time = ut.to_pandas_time_index(time)
            if not isinstance(time, pd.TimedeltaIndex):
                raise ValueError(
                    '"time" must be a time quantity or a "pandas.TimedeltaIndex".'
                )

            dax = xr.DataArray(
                data=data,
                attrs={"interpolation": interpolation},
            )
            self._data = dax.rename({
                "dim_0": "time"
            }).assign_coords({"time": time})

        elif isinstance(data, MathematicalExpression):

            if data.num_variables != 1:
                raise Exception(
                    "The mathematical expression must have exactly 1 free "
                    "variable that represents time.")
            time_var_name = data.get_variable_names()[0]
            try:
                eval_data = data.evaluate(**{time_var_name: Q_(1, "second")})
                self._units = eval_data.units
                if np.iterable(eval_data):
                    self._shape = eval_data.shape
                else:
                    self._shape = (1, )
            except pint.errors.DimensionalityError:
                raise Exception(
                    "Expression can not be evaluated with "
                    '"weldx.Quantity(1, "seconds")"'
                    ". Ensure that every parameter posses the correct unit.")

            self._data = data
            self._time_var_name = time_var_name

            try:
                self.interp_time(Q_([1, 2], "second"))
                self.interp_time(Q_([1, 2, 3], "second"))
            except Exception as e:
                raise Exception(
                    "The expression can not be evaluated with arrays of time deltas. "
                    "Ensure that all parameters that are multiplied with the time "
                    "variable have an outer dimension of size 1. This dimension is "
                    "broadcasted during multiplication. The original error message was:"
                    f' "{str(e)}"')

        else:
            raise TypeError(f'The data type "{type(data)}" is not supported.')
Esempio n. 7
0
def test_to_pandas_time_index_exceptions(arg, exception):
    """Test correct exceptions on invalid inputs."""
    with pytest.raises(exception):
        ut.to_pandas_time_index(arg)
Esempio n. 8
0
def test_to_pandas_time_index(arg, expected):
    """Test conversion to appropriate pd.TimedeltaIndex or pd.DatetimeIndex."""
    assert np.all(ut.to_pandas_time_index(arg) == expected)