Skip to content

Commit

Permalink
Fix docstring, simplify.
Browse files Browse the repository at this point in the history
  • Loading branch information
pp-mo committed Jan 13, 2022
1 parent 70ce630 commit 417a3ab
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 71 deletions.
72 changes: 34 additions & 38 deletions lib/iris/coords.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,9 +289,10 @@ def _str_dates(self, dates_as_numbers):
def summary(
self,
shorten=False,
max_values=10,
max_values=None,
fetch_lazy=False,
convert_dates=True,
max_array_width=60,
):
"""
Make a printable text summary of a dimensional cube component.
Expand All @@ -300,44 +301,43 @@ def summary(
----------
shorten : bool, default = False
If True, produce an abbreviated one-line summary.
If False, produce a multi-line summary, with embedded '\n's.
If False, produce a multi-line summary, with embedded newlines.
max_values : int or None, default = None
If more than this many data values, print truncated data arrays.
If 0, print only the shape.
If None, print the entire data arrays.
Defaults to 5 if `shorten` is True, else 10.
fetch_lazy : bool, default = None
Defaults to 5 if `shorten` is True, else 20.
fetch_lazy : bool, default = False
Whether to calculate values from lazy content.
When `fetch_lazy=False`, set max_values=0 if data is lazy.
convert_dates : bool, default = True
Print values in date form, if the units has a calendar.
If not, print raw number values.
max_array_width : int, default = 60
Character-width controlling line splitting of array outputs.
Returns
-------
result : str
"""
is_lazy = self._has_lazy_values()
if self._bounds_dm and _lazy.is_lazy_data(self._bounds_dm.core_data()):
# No distinction here: either lazy points *or* bounds means no data.
is_lazy = True
if fetch_lazy:
keep_lazy = False
else:
# N.B. no distinction here: lazy points *or* bounds means no data.
keep_lazy = self._has_lazy_values() or (
self._bounds_dm
and _lazy.is_lazy_data(self._bounds_dm.core_data())
)

def array_summary(
data, n_max=10, n_edge=2, linewidth=50, precision=None
):
# Return a text summary of the data, or "" for unfetched lazy data.
# Take account of lazy control, strings, dates and masked points.
# Return a text summary of an array.
# Take account of strings, dates and masked points.
result = ""
formatter = None
# if _lazy.is_lazy_data(data):
# # Either fetch lazy data, or disable values printout.
# if not fetch_lazy:
# data = None
# else:
# data = _lazy.as_concrete_data(data)
# if data is not None:
if self.units.is_time_reference():
if convert_dates and self.units.is_time_reference():
# Account for dates, if enabled.
# N.B. a time unit with a long time interval ("months"
# or "years") cannot be converted to a date using
Expand All @@ -355,9 +355,6 @@ def array_summary(
if mask is not None:
data = np.ma.masked_array(data, mask)

# if data is None:
# result = ""
# else:
if ma.is_masked(data):
# Masks are not handled by np.array2string, whereas
# MaskedArray.__str__ is using a private method to convert to
Expand All @@ -367,7 +364,7 @@ def array_summary(
# with a common numeric format, but there is no *public* logic
# in numpy to arrange that, so let's not overcomplicate.
# It happens that array2string *also* does not use a common
# format (width) for strings, but fix that below...
# format (width) for strings, but we fix that below...
data = data.astype(str).filled("--")

if data.dtype.kind == "U":
Expand All @@ -393,25 +390,24 @@ def array_summary(
cls_str = type(self).__name__
shape_str = str(self.shape)

# Implement conditional defaults for control args.
if max_values is None:
max_values = 5 if shorten else 15
precision = 3 if shorten else None

# Make a printout of the main data array (or maybe not, if lazy).
max_data_strlen = 60
n_max = 15
precision = None
if shorten:
precision = 3
n_max = 5
if is_lazy:
if keep_lazy:
data_str = "<lazy>"
else:
data_str = array_summary(
self._core_values(),
n_max=n_max,
linewidth=max_data_strlen,
n_max=max_values,
linewidth=max_array_width,
precision=precision,
)

if shorten:
if is_lazy:
if keep_lazy:
# Data summary is invalid due to being lazy : show shape.
data_str += f", shape={shape_str}"
else:
Expand All @@ -421,7 +417,7 @@ def array_summary(
while " " in data_str:
data_str = data_str.replace(" ", " ")
# Work out whether to include a summary of the data values
if len(data_str) > max_data_strlen:
if len(data_str) > max_array_width:
# Data summary is still too long : show shape instead.
data_str = f"shape={shape_str}"
if "..." in data_str:
Expand Down Expand Up @@ -450,11 +446,11 @@ def reindent_data_string(text, n_indent):

result += addline + reindent_data_string(data_str, n_indent + 1)

if not is_lazy and self.has_bounds():
if not keep_lazy and self.has_bounds():
bounds_str = array_summary(
self._bounds_dm.core_data(),
n_max=n_max,
linewidth=max_data_strlen,
n_max=max_values,
linewidth=max_array_width,
precision=precision,
)
bounds_str = reindent_data_string(bounds_str, 2 * n_indent)
Expand Down Expand Up @@ -486,10 +482,10 @@ def reindent_data_string(text, n_indent):
return result

def __str__(self):
return self.summary(max_values=10)
return self.summary()

def __repr__(self):
return self.summary(shorten=True, max_values=5)
return self.summary(shorten=True)

def _old__str__(self):
# Note: this method includes bounds handling code, but it only runs
Expand Down
73 changes: 40 additions & 33 deletions simple_coord_print_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,113 +5,120 @@
import iris._lazy_data as lazy

cube = istk.simple_pp()
co = cube.coord('latitude')
co = cube.coord("latitude")
co_b = co.copy()
co_b.guess_bounds()


def test(co):
# print(f'coord shape: {co.shape}')
print('------------REPR:-------')
print("------------REPR:-------")
print(repr(co))
print('------------STR:--------')
print("------------STR:--------")
print(str(co))
print('------------------------')
print('')
print("------------------------")
print("")


print('Small section of latitude coord[:2]')
print("Small section of latitude coord[:2]")
test(co[:2])

with np.printoptions(precision=3):
co2 = co_b.copy()
multibounds = np.concatenate([co2.bounds, co2.bounds], axis=-1)
co2.bounds = multibounds
print('co[:2] with 4x bounds + printoptions(precision=3) ')
print("co[:2] with 4x bounds + printoptions(precision=3) ")
test(co2[:2])

print('\nLonger section co[:5]')
print("\nLonger section co[:5]")
test(co[:5])

print('\nLonger section co[:5] with bounds')
print("\nLonger section co[:5] with bounds")
test(co_b[:5])

print('\nStill longer co[-15:] with bounds')
print("\nStill longer co[-15:] with bounds")
test(co_b[-15:])

print('\nFull co')
print("\nFull co")
test(co)

print('\nFull co with bounds')
print("\nFull co with bounds")
test(co_b)

print('\nSmall co with lazy points')
print("\nSmall co with lazy points")
co2 = AuxCoord.from_coord(co[:4])
co2.points = lazy.as_lazy_data(co2.points)
assert co2.has_lazy_points()
assert not co2.has_lazy_bounds()
print(co2.core_points())
test(co2)

print('\nSmall co with real points but lazy bounds')
print("\nSmall co with real points but lazy bounds")
co2.points = lazy.as_concrete_data(co2.points)
co2.guess_bounds()
co2.bounds = lazy.as_lazy_data(co2.bounds)
assert not co2.has_lazy_points()
assert co2.has_lazy_bounds()
test(co2)

print('\nFloat with masked points')
print("\nFloat with masked points")
co2 = AuxCoord.from_coord(co[:10])
pts = co2.points
pts = np.ma.masked_array(pts)
pts[[1, 3]] = np.ma.masked
co2.points = pts
test(co2)

print('\nInteger')
co = AuxCoord(range(5), long_name='integer_points')
print("\nInteger")
co = AuxCoord(range(5), long_name="integer_points")
test(co)

print('\nInteger with masked points')
print("\nInteger with masked points")
pts = co.points
pts = np.ma.masked_array(pts)
pts[[1, 3]] = np.ma.masked
co.points = pts
test(co)

print('\nLonger integers with masked points')
print("\nLonger integers with masked points")
pts = np.ma.arange(995, 1020)
pts[[1, 7]] = np.ma.masked
co = AuxCoord(pts, long_name='integer_points', var_name='qq')
co = AuxCoord(pts, long_name="integer_points", var_name="qq")
test(co)

print('\ndates with bounds')
print("\ndates with bounds")
co = AuxCoord(
np.linspace(0,100, 10), units='days since 2015-05-17',
var_name='x', attributes={'a':14, 'b':None})
np.linspace(0, 100, 10),
units="days since 2015-05-17",
var_name="x",
attributes={"a": 14, "b": None},
)
co.guess_bounds()
test(co)

print('\ndates with masked points')
print("\ndates with masked points")
pts = co.points
pts = np.ma.masked_array(pts)
pts[[2, 5]] = np.ma.masked
co.points = pts
test(co)

print('\nmultidimensional')
print("\nmultidimensional")
bigdata = np.exp(np.random.uniform(-3, 6, size=(7, 5, 4)))
co = AuxCoord(bigdata)
test(co)

print('\nsmall multidim')
print("\nsmall multidim")
test(co[0, :2, :2])

print('')
print('SCALAR:')
test(AuxCoord([15.], standard_name='forecast_period', units='hours'))
print("")
print("SCALAR:")
test(AuxCoord([15.0], standard_name="forecast_period", units="hours"))

print('')
print('==== REAL DATA nc test cube coords ...')
test_ncfile = iris.tests.get_data_path('NetCDF/global/xyt/SMALL_hires_wind_u_for_ipcc4.nc')
print("")
print("==== REAL DATA nc test cube coords ...")
test_ncfile = iris.tests.get_data_path(
"NetCDF/global/xyt/SMALL_hires_wind_u_for_ipcc4.nc"
)
for coord in iris.load_cube(test_ncfile)[:4].coords():
test(coord)
test(coord)

0 comments on commit 417a3ab

Please sign in to comment.