Skip to content

Commit 54c72a5

Browse files
committed
Add 'to_size' keyword parameter
1 parent f63c9b5 commit 54c72a5

7 files changed

Lines changed: 99 additions & 21 deletions

File tree

cf/data/data.py

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2181,7 +2181,7 @@ def mean_of_upper_decile(
21812181
return d
21822182

21832183
@_inplace_enabled(default=False)
2184-
def pad_missing(self, axis, pad_width, inplace=False):
2184+
def pad_missing(self, axis, pad_width=None, to_size=None, inplace=False):
21852185
"""Pad an axis with missing data.
21862186
21872187
:Parameters:
@@ -2196,7 +2196,9 @@ def pad_missing(self, axis, pad_width, inplace=False):
21962196
*Parameter example:*
21972197
Pad the last axis: ``axis=-1``.
21982198
2199-
{{pad_width: sequence of `int`}}
2199+
{{pad_width: sequence of `int`, optional}}
2200+
2201+
{{to_size: `int`, optional}}
22002202
22012203
{{inplace: `bool`, optional}}
22022204
@@ -2222,11 +2224,44 @@ def pad_missing(self, axis, pad_width, inplace=False):
22222224
[-- 3 4 5 -- --]
22232225
[-- -- -- -- -- --]]
22242226
2227+
>>> g = d.pad_missing(1, to_size=5)
2228+
>>> print(g.array)
2229+
[[0 1 2 -- --]
2230+
[3 4 5 -- --]]
2231+
22252232
"""
2226-
try:
2227-
pad_width0, pad_width1 = pad_width
2228-
except (TypeError, ValueError):
2229-
raise ValueError("'pad_width' must be a sequence of two integers")
2233+
if not 0 <= axis < self.ndim:
2234+
raise ValueError(
2235+
f"'axis' must be a valid dimension position. Got {axis}"
2236+
)
2237+
2238+
if to_size is not None:
2239+
# Set pad_width from to_size
2240+
if pad_width is not None:
2241+
raise ValueError("Can't set both 'pad_width' and 'to_size'")
2242+
2243+
pad_width = (0, to_size - self.shape[axis])
2244+
elif pad_width is None:
2245+
raise ValueError("Must set either 'pad_width' or 'to_size'")
2246+
2247+
pad_width = np.asarray(pad_width)
2248+
if pad_width.shape != (2,) or not pad_width.dtype.kind == "i":
2249+
raise ValueError(
2250+
"'pad_width' must be a sequence of two integers. "
2251+
f"Got: {pad_width}"
2252+
)
2253+
2254+
pad_width = tuple(pad_width)
2255+
if any(n < 0 for n in pad_width):
2256+
if to_size is not None:
2257+
raise ValueError(
2258+
f"'to_size' ({to_size}) must not be smaller than the "
2259+
f"original axis size ({self.shape[axis]})"
2260+
)
2261+
2262+
raise ValueError(
2263+
f"Can't set a negative number of pad values. Got: {pad_width}"
2264+
)
22302265

22312266
d = _inplace_enabled_define_and_cleanup(self)
22322267

cf/docstring/docstring.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -588,9 +588,13 @@
588588
If True then return `False` if weights can't be found,
589589
rather than raising an exception.""",
590590
# pad_width
591-
"{{pad_width: sequence of `int`}}": """pad_width: sequence of `int`
591+
"{{pad_width: sequence of `int`, optional}}": """pad_width: sequence of `int`, optional
592592
Number of values to pad before and after the edges of
593593
the axis.""",
594+
# to_size
595+
"{{to_size: `int`, optional}}": """to_size: `int`, optional
596+
Pad the axis after so that the new axis has the given
597+
size.""",
594598
# ----------------------------------------------------------------
595599
# Method description substitutions (4 levels of indentation)
596600
# ----------------------------------------------------------------

cf/field.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11954,7 +11954,7 @@ def halo(
1195411954
return f
1195511955

1195611956
@_inplace_enabled(default=False)
11957-
def pad_missing(self, axis, pad_width, inplace=False):
11957+
def pad_missing(self, axis, pad_width=None, to_size=None, inplace=False):
1195811958
"""Pad an axis with missing data.
1195911959

1196011960
The field's data and all metadata constructs that span the
@@ -11972,7 +11972,9 @@ def pad_missing(self, axis, pad_width, inplace=False):
1197211972
``'X'``, the domain axis construct returned by
1197311973
``f.domain_axis('X')`` is selected.
1197411974

11975-
{{pad_width: sequence of `int`}}
11975+
{{pad_width: sequence of `int`, optional}}
11976+
11977+
{{to_size: `int`, optional}}
1197611978

1197711979
{{inplace: `bool`, optional}}
1197811980

@@ -11984,7 +11986,7 @@ def pad_missing(self, axis, pad_width, inplace=False):
1198411986

1198511987
**Examples*
1198611988

11987-
>>> f = cf.example_field(6)
11989+
>>> f = cf.example_field(6)
1198811990
>>> print(f)
1198911991
Field: precipitation_amount (ncvar%pr)
1199011992
--------------------------------------
@@ -12028,6 +12030,17 @@ def pad_missing(self, axis, pad_width, inplace=False):
1202812030
[5.0 6.0 7.0 8.0 -- -- -- -- --]
1202912031
[ -- -- -- -- -- -- -- -- --]]
1203012032

12033+
>>> print(f.pad_missing('time', to_size=6))
12034+
Field: precipitation_amount (ncvar%pr)
12035+
--------------------------------------
12036+
Data : precipitation_amount(cf_role=timeseries_id(2), time(6))
12037+
Dimension coords: time(6) = [2000-01-16 12:00:00, ..., --] gregorian
12038+
Auxiliary coords: latitude(cf_role=timeseries_id(2)) = [25.0, 7.0] degrees_north
12039+
: longitude(cf_role=timeseries_id(2)) = [10.0, 40.0] degrees_east
12040+
: cf_role=timeseries_id(cf_role=timeseries_id(2)) = [x1, y2]
12041+
: altitude(cf_role=timeseries_id(2), 3, 4) = [[[1.0, ..., --]]] m
12042+
Coord references: grid_mapping_name:latitude_longitude
12043+
1203112044
"""
1203212045
f = _inplace_enabled_define_and_cleanup(self)
1203312046

@@ -12048,7 +12061,9 @@ def pad_missing(self, axis, pad_width, inplace=False):
1204812061
iaxis = data_axes.index(axis)
1204912062

1205012063
# Pad the field
12051-
super(Field, f).pad_missing(iaxis, pad_width, inplace=True)
12064+
super(Field, f).pad_missing(
12065+
iaxis, pad_width=pad_width, to_size=to_size, inplace=True
12066+
)
1205212067

1205312068
# Set new domain axis size
1205412069
domain_axis = f.domain_axis(axis)
@@ -12062,7 +12077,9 @@ def pad_missing(self, axis, pad_width, inplace=False):
1206212077

1206312078
# Pad the construct
1206412079
iaxis = construct_axes.index(axis)
12065-
construct.pad_missing(iaxis, pad_width, inplace=True)
12080+
construct.pad_missing(
12081+
iaxis, pad_width=pad_width, to_size=to_size, inplace=True
12082+
)
1206612083

1206712084
return f
1206812085

cf/mixin/propertiesdata.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1889,7 +1889,7 @@ def minimum(self):
18891889
)
18901890

18911891
@_inplace_enabled(default=False)
1892-
def pad_missing(self, axis, pad_width, inplace=False):
1892+
def pad_missing(self, axis, pad_width=None, to_size=None, inplace=False):
18931893
"""Pad an axis with missing data.
18941894
18951895
:Parameters:
@@ -1898,7 +1898,9 @@ def pad_missing(self, axis, pad_width, inplace=False):
18981898
Select the axis for which the padding is to be
18991899
applied.
19001900
1901-
{{pad_width: sequence of `int`}}
1901+
{{pad_width: sequence of `int`, optional}}
1902+
1903+
{{to_size: `int`, optional}}
19021904
19031905
{{inplace: `bool`, optional}}
19041906
@@ -1914,6 +1916,7 @@ def pad_missing(self, axis, pad_width, inplace=False):
19141916
"pad_missing",
19151917
axis=axis,
19161918
pad_width=pad_width,
1919+
to_size=to_size,
19171920
inplace=inplace,
19181921
)
19191922

cf/mixin/propertiesdatabounds.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3875,7 +3875,7 @@ def inspect(self):
38753875
print(cf_inspect(self)) # pragma: no cover
38763876

38773877
@_inplace_enabled(default=False)
3878-
def pad_missing(self, axis, pad_width, inplace=False):
3878+
def pad_missing(self, axis, pad_width=None, to_size=None, inplace=False):
38793879
"""Pad an axis with missing data.
38803880
38813881
:Parameters:
@@ -3884,7 +3884,9 @@ def pad_missing(self, axis, pad_width, inplace=False):
38843884
Select the axis for which the padding is to be
38853885
applied.
38863886
3887-
{{pad_width: sequence of `int`}}
3887+
{{pad_width: sequence of `int`, optional}}
3888+
3889+
{{to_size: `int`, optional}}
38883890
38893891
{{inplace: `bool`, optional}}
38903892
@@ -3902,6 +3904,7 @@ def pad_missing(self, axis, pad_width, inplace=False):
39023904
interior_ring=True,
39033905
axis=axis,
39043906
pad_width=pad_width,
3907+
to_size=to_size,
39053908
inplace=inplace,
39063909
)
39073910

cf/test/test_Data.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4735,15 +4735,27 @@ def test_Data_pad_missing(self):
47354735
"""Test Data.pad_missing."""
47364736
d = cf.Data(np.arange(6).reshape(2, 3))
47374737

4738-
self.assertIsNone(d.pad_missing(1, (1, 2), inplace=True))
4738+
g = d.pad_missing(1, to_size=5)
4739+
self.assertEqual(g.shape, (2, 5))
4740+
self.assertTrue(g[:, 3:].mask.all())
4741+
4742+
self.assertIsNone(d.pad_missing(1, pad_width=(1, 2), inplace=True))
47394743
self.assertEqual(d.shape, (2, 6))
47404744
self.assertTrue(d[:, 0].mask.all())
47414745
self.assertTrue(d[:, 4:].mask.all())
47424746

4743-
e = d.pad_missing(0, (0, 1))
4747+
e = d.pad_missing(0, pad_width=(0, 1))
47444748
self.assertEqual(e.shape, (3, 6))
47454749
self.assertTrue(e[2, :].mask.all())
47464750

4751+
# Can't set both pad_width and to_size
4752+
with self.assertRaises(ValueError):
4753+
d.pad_missing(0, pad_width=(0, 1), to_size=99)
4754+
4755+
# Axis out of bounds
4756+
with self.assertRaises(ValueError):
4757+
d.pad_missing(99, to_size=99)
4758+
47474759

47484760
if __name__ == "__main__":
47494761
print("Run date:", datetime.datetime.now())

cf/test/test_Field.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2669,16 +2669,20 @@ def test_Field_file_location(self):
26692669
f.del_file_location("/invalid")
26702670
self.assertEqual(f.file_locations(), set((location,)))
26712671

2672-
def test_Data_pad_missing(self):
2672+
def test_Field_pad_missing(self):
26732673
"""Test Field.pad_missing."""
26742674
f = cf.example_field(0)
26752675

2676-
self.assertIsNone(f.pad_missing("X", (1, 2), inplace=True))
2676+
g = f.pad_missing("X", to_size=10)
2677+
self.assertEqual(g.shape, (5, 10))
2678+
self.assertTrue(g[:, 8:].mask.all())
2679+
2680+
self.assertIsNone(f.pad_missing("X", pad_width=(1, 2), inplace=True))
26772681
self.assertEqual(f.shape, (5, 11))
26782682
self.assertTrue(f[:, 0].mask.all())
26792683
self.assertTrue(f[:, 9:].mask.all())
26802684

2681-
g = f.pad_missing("Y", (0, 1))
2685+
g = f.pad_missing("Y", pad_width=(0, 1))
26822686
self.assertEqual(g.shape, (6, 11))
26832687
self.assertTrue(g[5, :].mask.all())
26842688

0 commit comments

Comments
 (0)