Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/source/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1642,6 +1642,7 @@ IntervalIndex Components
IntervalIndex.is_non_overlapping_monotonic
IntervalIndex.get_loc
IntervalIndex.get_indexer
IntervalIndex.set_closed


.. _api.multiindex:
Expand Down
1 change: 1 addition & 0 deletions doc/source/whatsnew/v0.24.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Other Enhancements
(:issue:`21627`)
- New method :meth:`HDFStore.walk` will recursively walk the group hierarchy of an HDF5 file (:issue:`10932`)
- :meth:`Series.nlargest`, :meth:`Series.nsmallest`, :meth:`DataFrame.nlargest`, and :meth:`DataFrame.nsmallest` now accept the value ``"all"`` for the ``keep` argument. This keeps all ties for the nth largest/smallest value (:issue:`16818`)
- :class:`IntervalIndex` has gained the :meth:`~IntervalIndex.set_closed` method to change the existing ``closed`` value (:issue:`21670`)
-

.. _whatsnew_0240.api_breaking:
Expand Down
36 changes: 36 additions & 0 deletions pandas/core/indexes/interval.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ class IntervalIndex(IntervalMixin, Index):
from_tuples
get_indexer
get_loc
set_closed

Examples
---------
Expand Down Expand Up @@ -708,6 +709,41 @@ def closed(self):
"""
return self._closed

def set_closed(self, closed):
"""
Return an IntervalIndex identical to the current one, but closed on the
specified side

.. versionadded:: 0.24.0

Parameters
----------
closed : {'left', 'right', 'both', 'neither'}
Whether the intervals are closed on the left-side, right-side, both
or neither.

Returns
-------
new_index : IntervalIndex

Examples
--------
>>> index = pd.interval_range(0, 3)
>>> index
IntervalIndex([(0, 1], (1, 2], (2, 3]]
closed='right',
dtype='interval[int64]')
>>> index.set_closed('both')
IntervalIndex([[0, 1], [1, 2], [2, 3]]
closed='both',
dtype='interval[int64]')
"""
if closed not in _VALID_CLOSED:
msg = "invalid option for 'closed': {closed}"
raise ValueError(msg.format(closed=closed))

return self._shallow_copy(closed=closed)

@property
def length(self):
"""
Expand Down
17 changes: 17 additions & 0 deletions pandas/tests/indexes/interval/test_interval.py
Original file line number Diff line number Diff line change
Expand Up @@ -977,3 +977,20 @@ def test_to_tuples_na(self, tuples, na_tuple):
assert all(isna(x) for x in result_na)
else:
assert isna(result_na)

@pytest.mark.parametrize('new_closed', [
'left', 'right', 'both', 'neither'])
def test_set_closed(self, name, closed, new_closed):
# GH 21670
index = interval_range(0, 5, closed=closed, name=name)
result = index.set_closed(new_closed)
expected = interval_range(0, 5, closed=new_closed, name=name)
tm.assert_index_equal(result, expected)

@pytest.mark.parametrize('bad_closed', ['foo', 10, 'LEFT', True, False])
def test_set_closed_errors(self, bad_closed):
# GH 21670
index = interval_range(0, 5)
msg = "invalid option for 'closed': {closed}".format(closed=bad_closed)
with tm.assert_raises_regex(ValueError, msg):
index.set_closed(bad_closed)