Skip to content

BUG fix +test .sel method gives error with float32 values #3153

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

Merged
merged 10 commits into from
Aug 10, 2019
3 changes: 3 additions & 0 deletions doc/whats-new.rst
Original file line number Diff line number Diff line change
@@ -62,6 +62,9 @@ Bug fixes
- XFAIL several tests which are expected to fail on ARM systems
due to a ``datetime`` issue in NumPy (:issue:`2334`).
By `Graham Inggs <https://github.com/ginggs>`_.
- Fix KeyError that arises when using .sel method with float values
different from coords float type (:issue:`3137`).
By `Hasan Ahmad <https://github.com/HasanAhmadQ7>`_.
- Fixed bug in ``combine_by_coords()`` causing a `ValueError` if the input had
an unused dimension with coordinates which were not monotonic (:issue:`3150`).
By `Tom Nicholas <http://github.com/TomNicholas>`_.
4 changes: 3 additions & 1 deletion xarray/core/indexing.py
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@
from . import duck_array_ops, nputils, utils
from .npcompat import DTypeLike
from .pycompat import dask_array_type, integer_types
from .utils import is_dict_like
from .utils import is_dict_like, maybe_cast_to_coords_dtype


def expanded_indexer(key, ndim):
@@ -269,6 +269,8 @@ def remap_label_indexers(data_obj, indexers, method=None, tolerance=None):
)
pos_indexers[dim] = label
else:
coords_dtype = data_obj.coords[dim].dtype
label = maybe_cast_to_coords_dtype(label, coords_dtype)
idxr, new_idx = convert_label_indexer(index, label, dim, method, tolerance)
pos_indexers[dim] = idxr
if new_idx is not None:
6 changes: 6 additions & 0 deletions xarray/core/utils.py
Original file line number Diff line number Diff line change
@@ -85,6 +85,12 @@ def _maybe_cast_to_cftimeindex(index: pd.Index) -> pd.Index:
return index


def maybe_cast_to_coords_dtype(label, coords_dtype):
if coords_dtype.kind == "f" and not isinstance(label, slice):
label = np.asarray(label, dtype=coords_dtype)
return label


def safe_cast_to_index(array: Any) -> pd.Index:
"""Given an array, safely cast it to a pandas.Index.

27 changes: 27 additions & 0 deletions xarray/tests/test_dataarray.py
Original file line number Diff line number Diff line change
@@ -928,6 +928,33 @@ def test_sel_dataarray_datetime(self):
result = array.sel(delta=slice(array.delta[0], array.delta[-1]))
assert_equal(result, array)

def test_sel_float(self):
data_values = np.arange(4)

# case coords are float32 and label is list of floats
float_values = [0.0, 0.111, 0.222, 0.333]
coord_values = np.asarray(float_values, dtype="float32")
array = DataArray(data_values, [("float32_coord", coord_values)])
expected = DataArray(data_values[1:3], [("float32_coord", coord_values[1:3])])
actual = array.sel(float32_coord=float_values[1:3])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would also be good to add a test case where you're only indexing by a scalar.

# case coords are float16 and label is list of floats
coord_values_16 = np.asarray(float_values, dtype="float16")
expected_16 = DataArray(
data_values[1:3], [("float16_coord", coord_values_16[1:3])]
)
array_16 = DataArray(data_values, [("float16_coord", coord_values_16)])
actual_16 = array_16.sel(float16_coord=float_values[1:3])

# case coord, label are scalars
expected_scalar = DataArray(
data_values[2], coords={"float32_coord": coord_values[2]}
)
actual_scalar = array.sel(float32_coord=float_values[2])

assert_equal(expected, actual)
assert_equal(expected_scalar, actual_scalar)
assert_equal(expected_16, actual_16)

def test_sel_no_index(self):
array = DataArray(np.arange(10), dims="x")
assert_identical(array[0], array.sel(x=0))