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
51 changes: 49 additions & 2 deletions cf/data/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -8739,20 +8739,67 @@ def count_masked(self):
"""
return self._size - self.count()

@daskified(_DASKIFIED_VERBOSE)
def cyclic(self, axes=None, iscyclic=True):
"""Returns or sets the axes of the data array which are cyclic.
"""Get or set the cyclic axes.

Some methods treat the first and last elements of a cyclic
axis as adjacent and physically connected, such as
`convolution_filter`, `__getitem__` and `__setitem__`. Some
methods may make a cyclic axis non-cyclic, such as `halo`.

:Parameters:

axes: (sequence of) `int`, optional
Select the axes to have their cyclicity set. By
default, or if *axes* is `None` or an empty sequence,
no axes are modified.

iscyclic: `bool`
Specify whether to make the axes cyclic or
non-cyclic. By default (True), the axes are set as
cyclic.

:Returns:

`set`
The cyclic axes prior to the change, or the current
cylcic axes if no axes are specified.

**Examples:**
**Examples**

>>> d = cf.Data(np.arange(12).reshape(3, 4))
>>> d.cyclic()
set()
>>> d.cyclic(0)
set()
>>> d.cyclic()
{0}
>>> d.cyclic(0, iscyclic=False)
{0}
>>> d.cyclic()
set()
>>> d.cyclic([0, 1])
set()
>>> d.cyclic()
{0, 1}
>>> d.cyclic([0, 1], iscyclic=False)
{0, 1}
>>> d.cyclic()
set()

>>> print(d.array)
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
>>> d[0, -1:2]
Traceback (most recent call last):
...
IndexError: Can't take a cyclic slice of a non-cyclic axis
>>> d.cyclic(1)
set()
>>> d[0, -1:2]
<CF Data(1, 2): [[3, 0, 1]]>

"""
cyclic_axes = self._cyclic
Expand Down
28 changes: 28 additions & 0 deletions cf/test/test_Data.py
Original file line number Diff line number Diff line change
Expand Up @@ -3831,6 +3831,34 @@ def test_Data__bool__(self):
with self.assertRaises(ValueError):
bool(cf.Data([1, 2]))

def test_Data_cyclic(self):
d = cf.Data(np.arange(12).reshape(3, 4))
self.assertEqual(d.cyclic(), set())
self.assertEqual(d.cyclic(0), set())
self.assertEqual(d.cyclic(), {0})
self.assertEqual(d.cyclic(1), {0})
self.assertEqual(d.cyclic(), {0, 1})
self.assertEqual(d.cyclic(0, iscyclic=False), {0, 1})
self.assertEqual(d.cyclic(), {1})
self.assertEqual(d.cyclic(1, iscyclic=False), {1})
self.assertEqual(d.cyclic(), set())
self.assertEqual(d.cyclic([0, 1]), set())
self.assertEqual(d.cyclic(), {0, 1})
self.assertEqual(d.cyclic([0, 1], iscyclic=False), {0, 1})
self.assertEqual(d.cyclic(), set())

# Invalid axis
with self.assertRaises(ValueError):
d.cyclic(2)

# Scalar data
d = cf.Data(9)
self.assertEqual(d.cyclic(), set())

# Scalar data invalid axis
with self.assertRaises(ValueError):
d.cyclic(0)

def test_Data_change_calendar(self):
d = cf.Data(
[0, 1, 2, 3, 4], "days since 2004-02-27", calendar="standard"
Expand Down