-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Accept int value in head, thin and tail #3298
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
Changes from 4 commits
ad7560e
5d76cd6
6ca0b42
d9cbcda
4fec603
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2009,15 +2009,18 @@ def sel( | |
return result._overwrite_indexes(new_indexes) | ||
|
||
def head( | ||
self, indexers: Mapping[Hashable, Any] = None, **indexers_kwargs: Any | ||
self, | ||
indexers: Union[Mapping[Hashable, int], int] = None, | ||
**indexers_kwargs: Any | ||
) -> "Dataset": | ||
"""Returns a new dataset with the first `n` values of each array | ||
for the specified dimension(s). | ||
|
||
Parameters | ||
---------- | ||
indexers : dict, optional | ||
A dict with keys matching dimensions and integer values `n`. | ||
indexers : dict or int, default: 5 | ||
A dict with keys matching dimensions and integer values `n` | ||
or a single integer `n` applied over all dimensions. | ||
One of indexers or indexers_kwargs must be provided. | ||
**indexers_kwargs : {dim: n, ...}, optional | ||
The keyword arguments form of ``indexers``. | ||
|
@@ -2030,20 +2033,35 @@ def head( | |
Dataset.thin | ||
DataArray.head | ||
""" | ||
if not indexers_kwargs: | ||
if indexers is None: | ||
indexers = 5 | ||
if not isinstance(indexers, int) and not is_dict_like(indexers): | ||
raise TypeError("indexers must be a dict or a single integer") | ||
if isinstance(indexers, int): | ||
indexers = {dim: indexers for dim in self.dims} | ||
indexers = either_dict_or_kwargs(indexers, indexers_kwargs, "head") | ||
for v in indexers.values(): | ||
if not isinstance(v, int): | ||
raise TypeError("indexer value must be an integer") | ||
elif v < 0: | ||
raise ValueError("indexer value must be positive") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is help to include a little more context in error messages if possible. In this case, you could include offending the name and value. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmmm, Something along these lines maybe? "expected integer as indexer value, found type %r for dim %r" % (type(v), k) and "expected positive integer as indexer value for dim %r" % k The |
||
indexers = {k: slice(val) for k, val in indexers.items()} | ||
return self.isel(indexers) | ||
|
||
def tail( | ||
self, indexers: Mapping[Hashable, Any] = None, **indexers_kwargs: Any | ||
self, | ||
indexers: Union[Mapping[Hashable, int], int] = None, | ||
**indexers_kwargs: Any | ||
) -> "Dataset": | ||
"""Returns a new dataset with the last `n` values of each array | ||
for the specified dimension(s). | ||
|
||
Parameters | ||
---------- | ||
indexers : dict, optional | ||
A dict with keys matching dimensions and integer values `n`. | ||
indexers : dict or int, default: 5 | ||
A dict with keys matching dimensions and integer values `n` | ||
or a single integer `n` applied over all dimensions. | ||
One of indexers or indexers_kwargs must be provided. | ||
**indexers_kwargs : {dim: n, ...}, optional | ||
The keyword arguments form of ``indexers``. | ||
|
@@ -2056,24 +2074,38 @@ def tail( | |
Dataset.thin | ||
DataArray.tail | ||
""" | ||
|
||
if not indexers_kwargs: | ||
if indexers is None: | ||
indexers = 5 | ||
if not isinstance(indexers, int) and not is_dict_like(indexers): | ||
raise TypeError("indexers must be a dict or a single integer") | ||
if isinstance(indexers, int): | ||
indexers = {dim: indexers for dim in self.dims} | ||
indexers = either_dict_or_kwargs(indexers, indexers_kwargs, "tail") | ||
for v in indexers.values(): | ||
if not isinstance(v, int): | ||
raise TypeError("indexer value must be an integer") | ||
elif v < 0: | ||
raise ValueError("indexer value must be positive") | ||
indexers = { | ||
k: slice(-val, None) if val != 0 else slice(val) | ||
for k, val in indexers.items() | ||
} | ||
return self.isel(indexers) | ||
|
||
def thin( | ||
self, indexers: Mapping[Hashable, Any] = None, **indexers_kwargs: Any | ||
self, | ||
indexers: Union[Mapping[Hashable, int], int] = None, | ||
**indexers_kwargs: Any | ||
) -> "Dataset": | ||
"""Returns a new dataset with each array indexed along every `n`th | ||
value for the specified dimension(s) | ||
|
||
Parameters | ||
---------- | ||
indexers : dict, optional | ||
A dict with keys matching dimensions and integer values `n`. | ||
indexers : dict or int, default: 5 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does it make sense to thin by a factor of five by default? Or should we not have a default value? The use case for a default thinning value are less clear to me than defaults for head/tail. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agree! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think picking a default makes it very convenient to use. And this is a convenience method... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I set a default value to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't have a strong enough view. I agree it's a convenience method, but a convenient value significantly depends on the size of the array, unlike with So whatever you think. I'm probably a -0.2 |
||
A dict with keys matching dimensions and integer values `n` | ||
or a single integer `n` applied over all dimensions. | ||
One of indexers or indexers_kwargs must be provided. | ||
**indexers_kwargs : {dim: n, ...}, optional | ||
The keyword arguments form of ``indexers``. | ||
|
@@ -2086,9 +2118,22 @@ def thin( | |
Dataset.tail | ||
DataArray.thin | ||
""" | ||
if ( | ||
not indexers_kwargs | ||
and not isinstance(indexers, int) | ||
and not is_dict_like(indexers) | ||
): | ||
raise TypeError("indexers must be a dict or a single integer") | ||
if isinstance(indexers, int): | ||
indexers = {dim: indexers for dim in self.dims} | ||
indexers = either_dict_or_kwargs(indexers, indexers_kwargs, "thin") | ||
if 0 in indexers.values(): | ||
raise ValueError("step cannot be zero") | ||
for v in indexers.values(): | ||
if not isinstance(v, int): | ||
raise TypeError("indexer value must be an integer") | ||
elif v < 0: | ||
raise ValueError("indexer value must be positive") | ||
elif v == 0: | ||
raise ValueError("step cannot be zero") | ||
indexers = {k: slice(None, None, val) for k, val in indexers.items()} | ||
return self.isel(indexers) | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1005,13 +1005,48 @@ def test_isel_drop(self): | |
def test_head(self): | ||
assert_equal(self.dv.isel(x=slice(5)), self.dv.head(x=5)) | ||
assert_equal(self.dv.isel(x=slice(0)), self.dv.head(x=0)) | ||
assert_equal( | ||
self.dv.isel({dim: slice(6) for dim in self.dv.dims}), self.dv.head(6) | ||
) | ||
assert_equal( | ||
self.dv.isel({dim: slice(5) for dim in self.dv.dims}), self.dv.head() | ||
) | ||
with raises_regex(TypeError, "must be a dict or a single int"): | ||
self.dv.head([3]) | ||
with raises_regex(TypeError, "must be an int"): | ||
self.dv.head(x=3.1) | ||
with raises_regex(ValueError, "must be positive"): | ||
self.dv.head(-3) | ||
|
||
def test_tail(self): | ||
assert_equal(self.dv.isel(x=slice(-5, None)), self.dv.tail(x=5)) | ||
assert_equal(self.dv.isel(x=slice(0)), self.dv.tail(x=0)) | ||
assert_equal( | ||
self.dv.isel({dim: slice(-6, None) for dim in self.dv.dims}), | ||
self.dv.tail(6), | ||
) | ||
assert_equal( | ||
self.dv.isel({dim: slice(-5, None) for dim in self.dv.dims}), self.dv.tail() | ||
) | ||
with raises_regex(TypeError, "must be a dict or a single int"): | ||
self.dv.tail([3]) | ||
with raises_regex(TypeError, "must be an int"): | ||
self.dv.tail(x=3.1) | ||
with raises_regex(ValueError, "must be positive"): | ||
self.dv.tail(-3) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Very thorough tests! Thank you! |
||
|
||
def test_thin(self): | ||
assert_equal(self.dv.isel(x=slice(None, None, 5)), self.dv.thin(x=5)) | ||
assert_equal( | ||
self.dv.isel({dim: slice(None, None, 6) for dim in self.dv.dims}), | ||
self.dv.thin(6), | ||
) | ||
with raises_regex(TypeError, "must be a dict or a single int"): | ||
self.dv.thin([3]) | ||
with raises_regex(TypeError, "must be an int"): | ||
self.dv.thin(x=3.1) | ||
with raises_regex(ValueError, "must be positive"): | ||
self.dv.thin(-3) | ||
with raises_regex(ValueError, "cannot be zero"): | ||
self.dv.thin(time=0) | ||
|
||
|
Uh oh!
There was an error while loading. Please reload this page.