Skip to content

Commit

Permalink
Fix xr check coords (#221)
Browse files Browse the repository at this point in the history
* fix check for timedelta64 in xr_check_coords

* fix time_ref_restore for datetime64 without existing ref_time

* allow np.datetime64 for _as_valid_timestamp

* update CHANGELOG.md

* add utility test
  • Loading branch information
CagtayFabry authored Jan 13, 2021
1 parent a537da4 commit 78ad82b
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 11 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

### fixes
- don't inline time dependent `LCS.coordinates` [[#222]](https://github.com/BAMWelDX/weldx/pull/222)
- fix "datetime64" passing for "timedelta64" in `xr_check_coords` [[#221]](https://github.com/BAMWelDX/weldx/pull/221)
- fix `time_ref_restore` not working correctly if no `time_ref` was set [[#221]](https://github.com/BAMWelDX/weldx/pull/221)

## 0.2.2 (30.11.2020)
### added
Expand Down
41 changes: 40 additions & 1 deletion tests/test_utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ def test_get_time_union(list_of_objects, time_exp):
assert np.all(ut.get_time_union(list_of_objects) == time_exp)


def test_xf_fill_all():
def test_xr_fill_all():
"""Test filling along all dimensions."""
da1 = xr.DataArray(
np.eye(2), dims=["a", "b"], coords={"a": np.arange(2), "b": np.arange(2)}
Expand Down Expand Up @@ -440,6 +440,7 @@ def test_xr_check_coords(dax, ref_dict):
ValueError,
),
(_dax_check, {"d1": {"dtype": [int, str, bool]}}, TypeError),
(_dax_check, {"d3": {"dtype": "timedelta64"}}, TypeError),
(_dax_check, {"d4": {"dtype": "datetime64"}}, TypeError),
({"d4": np.arange(4)}, {"d4": {"dtype": "int"}}, ValueError),
],
Expand All @@ -448,3 +449,41 @@ def test_xr_check_coords_exception(dax, ref_dict, exception_type):
"""Test weldx.utility.xr_check_coords function."""
with pytest.raises(exception_type):
ut.xr_check_coords(dax, ref_dict)


def test_xr_time_ref():
"""Test weldx accessor functions for time handling."""
dt = pd.TimedeltaIndex([0, 1, 2, 3], "s")
da1 = xr.DataArray(
data=np.ones(4),
dims=["time"],
coords={"time": dt},
)

da1.time.attrs = {"A": "B"}

# non changing operations
da = da1.weldx.time_ref_unset()
assert da1.identical(da)
da = da1.weldx.time_ref_restore()
assert da1.identical(da)

t0 = pd.Timestamp("2021-01-01")
da1.weldx.time_ref = t0
da = da1.weldx.time_ref_unset()
assert np.all(da.time.data == (dt + t0))

da = da.weldx.reset_reference_time(pd.Timestamp("2021-01-01 00:00:01"))
assert np.all(da.time.data == pd.TimedeltaIndex([-1, 0, 1, 2], "s"))

da2 = xr.DataArray(
data=np.ones(4),
dims=["time"],
coords={"time": t0 + dt},
)
da2 = da2.weldx.time_ref_restore()
assert np.all(da2.time.data == pd.TimedeltaIndex([0, 1, 2, 3], "s"))
assert da2.time.attrs["time_ref"] == t0

da2.weldx.time_ref = t0
assert da2.time.attrs["time_ref"] == t0
24 changes: 14 additions & 10 deletions weldx/utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -729,10 +729,8 @@ def _check_dtype(var_dtype, ref_dtype: dict) -> bool:
if var_dtype != np.dtype(ref_dtype):
if isinstance(ref_dtype, str):
if (
"timedelta64" in ref_dtype
or "datetime64" in ref_dtype
and np.issubdtype(var_dtype, np.dtype(ref_dtype))
):
"timedelta64" in ref_dtype or "datetime64" in ref_dtype
) and np.issubdtype(var_dtype, np.dtype(ref_dtype)):
return True

if not (
Expand Down Expand Up @@ -978,20 +976,20 @@ def xr_interp_coordinates_in_time(
return da


def _as_valid_timestamp(value: Union[pd.Timestamp, str]) -> pd.Timestamp:
def _as_valid_timestamp(value: Union[pd.Timestamp, np.datetime64, str]) -> pd.Timestamp:
"""Create a valid (by convention) Timestamp object or raise TypeError.
Parameters
----------
value: pandas.Timestamp or str
value: pandas.Timestamp, np.datetime64 or str
Value to convert to `pd.Timestamp`.
Returns
-------
pandas.Timestamp
"""
if isinstance(value, str):
if isinstance(value, (str, np.datetime64)):
value = pd.Timestamp(value)
if isinstance(value, pd.Timestamp): # catch NaT from empty str.
return value
Expand Down Expand Up @@ -1039,10 +1037,16 @@ def time_ref_unset(self) -> xr.DataArray:
def time_ref_restore(self) -> xr.DataArray:
"""Convert DatetimeIndex back to TimedeltaIndex + reference Timestamp."""
da = self._obj.copy()
time_ref = da.weldx.time_ref
if time_ref and is_datetime64_dtype(da.time):
if "time" not in da.coords:
return da

if is_datetime64_dtype(da.time):
time_ref = da.weldx.time_ref
if time_ref is None:
time_ref = pd.Timestamp(da.time.data[0])
da["time"] = pd.DatetimeIndex(da.time.data) - time_ref
da.time.attrs = self._obj.time.attrs # restore old attributes !
da.time.attrs["time_ref"] = time_ref
return da

def reset_reference_time(self, time_ref_new: pd.Timestamp) -> xr.DataArray:
Expand All @@ -1053,7 +1057,7 @@ def reset_reference_time(self, time_ref_new: pd.Timestamp) -> xr.DataArray:
return da

@property
def time_ref(self) -> pd.Timestamp:
def time_ref(self) -> Union[pd.Timestamp, None]:
"""Get the time_ref value or `None` if not set."""
da = self._obj
if "time" in da.coords:
Expand Down

0 comments on commit 78ad82b

Please sign in to comment.