Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

interp and interp_like #72

Merged
merged 8 commits into from
Mar 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions ci/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pint
numpy
scipy
xarray
isort
black
Expand Down
4 changes: 4 additions & 0 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Dataset

xarray.Dataset.pint.quantify
xarray.Dataset.pint.dequantify
xarray.Dataset.pint.interp
xarray.Dataset.pint.interp_like
xarray.Dataset.pint.reindex
xarray.Dataset.pint.reindex_like
xarray.Dataset.pint.sel
Expand All @@ -37,6 +39,8 @@ DataArray

xarray.DataArray.pint.quantify
xarray.DataArray.pint.dequantify
xarray.DataArray.pint.interp
xarray.DataArray.pint.interp_like
xarray.DataArray.pint.reindex
xarray.DataArray.pint.reindex_like
xarray.DataArray.pint.sel
Expand Down
3 changes: 3 additions & 0 deletions docs/whats-new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ What's new
- implement :py:meth:`Dataset.pint.reindex`, :py:meth:`Dataset.pint.reindex_like`,
:py:meth:`DataArray.pint.reindex` and :py:meth:`DataArray.pint.reindex_like` (:pull:`69`).
By `Justus Magin <https://github.com/keewis>`_.
- implement :py:meth:`Dataset.pint.interp`, :py:meth:`Dataset.pint.interp_like`,
:py:meth:`DataArray.pint.interp` and :py:meth:`DataArray.pint.interp_like` (:pull:`72`).
By `Justus Magin <https://github.com/keewis>`_.

v0.1 (October 26 2020)
----------------------
Expand Down
256 changes: 249 additions & 7 deletions pint_xarray/accessors.py
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ def reindex(
):
"""unit-aware version of reindex

Just like :py:meth:`xarray.DataArray.reindex`, except the dataset's indexes are converted
Just like :py:meth:`xarray.DataArray.reindex`, except the object's indexes are converted
to the units of the indexers first.

.. note::
Expand Down Expand Up @@ -490,7 +490,7 @@ def reindex_like(
):
"""unit-aware version of reindex_like

Just like :py:meth:`xarray.DataArray.reindex_like`, except the dataset's indexes are converted
Just like :py:meth:`xarray.DataArray.reindex_like`, except the object's indexes are converted
to the units of the indexers first.

.. note::
Expand Down Expand Up @@ -540,12 +540,133 @@ def reindex_like(
fill_value=fill_value,
)

def interp(
self,
coords=None,
method="linear",
assume_sorted=False,
kwargs=None,
**coords_kwargs,
):
"""unit-aware version of interp

Just like :py:meth:`xarray.DataArray.interp`, except the object's indexes are converted
to the units of the indexers first.
keewis marked this conversation as resolved.
Show resolved Hide resolved

.. note::
``tolerance`` and ``fill_value`` are not supported, yet. They will be passed through to
``DataArray.interp`` unmodified.

See Also
--------
xarray.Dataset.pint.interp
xarray.DataArray.pint.interp_like
xarray.DataArray.interp
"""
indexers = either_dict_or_kwargs(coords, coords_kwargs, "interp")

indexer_units = {
name: conversion.extract_indexer_units(indexer)
for name, indexer in indexers.items()
}

# make sure we only have compatible units
dims = self.da.dims
unit_attrs = conversion.extract_unit_attributes(self.da)
index_units = {
name: units for name, units in unit_attrs.items() if name in dims
}

registry = get_registry(None, index_units, indexer_units)

units = zip_mappings(indexer_units, index_units)
incompatible_units = [
key
for key, (indexer_unit, index_unit) in units.items()
if (
None not in (indexer_unit, index_unit)
and not registry.is_compatible_with(indexer_unit, index_unit)
)
]
if incompatible_units:
units1 = {key: indexer_units[key] for key in incompatible_units}
units2 = {key: index_units[key] for key in incompatible_units}
raise DimensionalityError(units1, units2)

# convert the indexes to the indexer's units
converted = conversion.convert_units(self.da, indexer_units)
stripped = conversion.strip_units(converted)

# index
stripped_indexers = {
name: conversion.strip_indexer_units(indexer)
for name, indexer in indexers.items()
}
interpolated = stripped.interp(
stripped_indexers,
method=method,
assume_sorted=False,
kwargs=None,
)
return conversion.attach_units(interpolated, indexer_units)

def interp_like(self, other, method="linear", assume_sorted=False, kwargs=None):
"""unit-aware version of interp_like

Just like :py:meth:`xarray.DataArray.interp_like`, except the object's indexes are converted
to the units of the indexers first.

.. note::
``tolerance`` and ``fill_value`` are not supported, yet. They will be passed through to
``DataArray.interp_like`` unmodified.

See Also
--------
xarray.Dataset.pint.interp_like
xarray.DataArray.pint.interp
xarray.DataArray.interp_like
"""
indexer_units = conversion.extract_unit_attributes(other)

# make sure we only have compatible units
dims = self.da.dims
unit_attrs = conversion.extract_unit_attributes(self.da)
index_units = {
name: units for name, units in unit_attrs.items() if name in dims
}

registry = get_registry(None, index_units, indexer_units)

units = zip_mappings(indexer_units, index_units)
incompatible_units = [
key
for key, (indexer_unit, index_unit) in units.items()
if (
None not in (indexer_unit, index_unit)
and not registry.is_compatible_with(indexer_unit, index_unit)
)
]
if incompatible_units:
units1 = {key: indexer_units[key] for key in incompatible_units}
units2 = {key: index_units[key] for key in incompatible_units}
raise DimensionalityError(units1, units2)

converted = conversion.convert_units(self.da, indexer_units)
stripped = conversion.strip_units(converted)
interpolated = stripped.interp_like(
other,
method=method,
assume_sorted=assume_sorted,
kwargs=kwargs,
)
return conversion.attach_units(interpolated, indexer_units)

def sel(
self, indexers=None, method=None, tolerance=None, drop=False, **indexers_kwargs
):
"""unit-aware version of sel

Just like :py:meth:`xarray.DataArray.sel`, except the dataset's indexes are converted
Just like :py:meth:`xarray.DataArray.sel`, except the object's indexes are converted
to the units of the indexers first.

.. note::
Expand Down Expand Up @@ -743,7 +864,7 @@ def to(self, units=None, **unit_kwargs):
----------
units : unit-like or mapping of hashable to unit-like, optional
The units to convert to. If a unit name or ``pint.Unit``
object, convert all the Dataset's data variables. If a dict-like, it
object, convert all the object's data variables. If a dict-like, it
maps variable names to unit names or ``pint.Unit``
objects.
**unit_kwargs
Expand Down Expand Up @@ -891,7 +1012,7 @@ def reindex(
):
"""unit-aware version of reindex

Just like :py:meth:`xarray.Dataset.reindex`, except the dataset's indexes are converted
Just like :py:meth:`xarray.Dataset.reindex`, except the object's indexes are converted
to the units of the indexers first.

.. note::
Expand Down Expand Up @@ -959,7 +1080,7 @@ def reindex_like(
):
"""unit-aware version of reindex_like

Just like :py:meth:`xarray.Dataset.reindex_like`, except the dataset's indexes are converted
Just like :py:meth:`xarray.Dataset.reindex_like`, except the object's indexes are converted
to the units of the indexers first.

.. note::
Expand Down Expand Up @@ -1009,12 +1130,133 @@ def reindex_like(
fill_value=fill_value,
)

def interp(
self,
coords=None,
method="linear",
assume_sorted=False,
kwargs=None,
**coords_kwargs,
):
"""unit-aware version of interp

Just like :py:meth:`xarray.Dataset.interp`, except the object's indexes are converted
to the units of the indexers first.

.. note::
``tolerance`` and ``fill_value`` are not supported, yet. They will be passed through to
``Dataset.interp`` unmodified.

See Also
--------
xarray.DataArray.pint.interp
xarray.Dataset.pint.interp_like
xarray.Dataset.interp
"""
indexers = either_dict_or_kwargs(coords, coords_kwargs, "interp")

indexer_units = {
name: conversion.extract_indexer_units(indexer)
for name, indexer in indexers.items()
}

# make sure we only have compatible units
dims = self.ds.dims
unit_attrs = conversion.extract_unit_attributes(self.ds)
index_units = {
name: units for name, units in unit_attrs.items() if name in dims
}

registry = get_registry(None, index_units, indexer_units)

units = zip_mappings(indexer_units, index_units)
incompatible_units = [
key
for key, (indexer_unit, index_unit) in units.items()
if (
None not in (indexer_unit, index_unit)
and not registry.is_compatible_with(indexer_unit, index_unit)
)
]
if incompatible_units:
units1 = {key: indexer_units[key] for key in incompatible_units}
units2 = {key: index_units[key] for key in incompatible_units}
raise DimensionalityError(units1, units2)

# convert the indexes to the indexer's units
converted = conversion.convert_units(self.ds, indexer_units)
stripped = conversion.strip_units(converted)

# index
stripped_indexers = {
name: conversion.strip_indexer_units(indexer)
for name, indexer in indexers.items()
}
interpolated = stripped.interp(
stripped_indexers,
method=method,
assume_sorted=False,
kwargs=None,
)
return conversion.attach_units(interpolated, indexer_units)

def interp_like(self, other, method="linear", assume_sorted=False, kwargs=None):
"""unit-aware version of interp_like

Just like :py:meth:`xarray.Dataset.interp_like`, except the object's indexes are converted
to the units of the indexers first.

.. note::
``tolerance`` and ``fill_value`` are not supported, yet. They will be passed through to
``Dataset.interp_like`` unmodified.

See Also
--------
xarray.DataArray.pint.interp_like
xarray.Dataset.pint.interp
xarray.Dataset.interp_like
"""
indexer_units = conversion.extract_unit_attributes(other)

# make sure we only have compatible units
dims = self.ds.dims
unit_attrs = conversion.extract_unit_attributes(self.ds)
index_units = {
name: units for name, units in unit_attrs.items() if name in dims
}

registry = get_registry(None, index_units, indexer_units)

units = zip_mappings(indexer_units, index_units)
incompatible_units = [
key
for key, (indexer_unit, index_unit) in units.items()
if (
None not in (indexer_unit, index_unit)
and not registry.is_compatible_with(indexer_unit, index_unit)
)
]
if incompatible_units:
units1 = {key: indexer_units[key] for key in incompatible_units}
units2 = {key: index_units[key] for key in incompatible_units}
raise DimensionalityError(units1, units2)

converted = conversion.convert_units(self.ds, indexer_units)
stripped = conversion.strip_units(converted)
interpolated = stripped.interp_like(
other,
method=method,
assume_sorted=assume_sorted,
kwargs=kwargs,
)
return conversion.attach_units(interpolated, indexer_units)

def sel(
self, indexers=None, method=None, tolerance=None, drop=False, **indexers_kwargs
):
"""unit-aware version of sel

Just like :py:meth:`xarray.Dataset.sel`, except the dataset's indexes are converted to the units
Just like :py:meth:`xarray.Dataset.sel`, except the object's indexes are converted to the units
of the indexers first.

.. note::
Expand Down