Skip to content

Commit cc83f67

Browse files
Adding reprs for FieldSet, Field, VectorField and XGrid
1 parent 3df2b13 commit cc83f67

4 files changed

Lines changed: 69 additions & 22 deletions

File tree

src/parcels/_core/field.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
from parcels._core.uxgrid import UxGrid
2525
from parcels._core.xgrid import XGrid, _transpose_xfield_data_to_tzyx, assert_all_field_dims_have_axis
2626
from parcels._python import assert_same_function_signature
27-
from parcels._reprs import default_repr
27+
from parcels._reprs import field_repr, vectorfield_repr
2828
from parcels._typing import VectorType
2929
from parcels.interpolators import (
3030
ZeroInterpolator,
@@ -148,6 +148,9 @@ def __init__(
148148
if "time" not in self.data.coords:
149149
raise ValueError("Field data is missing a 'time' coordinate.")
150150

151+
def __repr__(self):
152+
return field_repr(self)
153+
151154
@property
152155
def units(self):
153156
return self._units
@@ -272,11 +275,7 @@ def __init__(
272275
self._vector_interp_method = vector_interp_method
273276

274277
def __repr__(self):
275-
return f"""<{type(self).__name__}>
276-
name: {self.name!r}
277-
U: {default_repr(self.U)}
278-
V: {default_repr(self.V)}
279-
W: {default_repr(self.W)}"""
278+
return vectorfield_repr(self)
280279

281280
@property
282281
def vector_interp_method(self):

src/parcels/_core/fieldset.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from parcels._core.uxgrid import UxGrid
1919
from parcels._core.xgrid import _DEFAULT_XGCM_KWARGS, XGrid
2020
from parcels._logger import logger
21+
from parcels._reprs import fieldset_repr
2122
from parcels._typing import Mesh
2223
from parcels.interpolators import UxPiecewiseConstantFace, UxPiecewiseLinearNode, XConstantField, XLinear
2324

@@ -75,6 +76,9 @@ def __getattr__(self, name):
7576
else:
7677
raise AttributeError(f"FieldSet has no attribute '{name}'")
7778

79+
def __repr__(self):
80+
return fieldset_repr(self)
81+
7882
@property
7983
def time_interval(self):
8084
"""Returns the valid executable time interval of the FieldSet,

src/parcels/_core/xgrid.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
from parcels._core.basegrid import BaseGrid
1111
from parcels._core.index_search import _search_1d_array, _search_indices_curvilinear_2d
12+
from parcels._reprs import xgrid_repr
1213
from parcels._typing import assert_valid_mesh
1314

1415
_XGRID_AXES = Literal["X", "Y", "Z"]
@@ -135,6 +136,9 @@ def from_dataset(cls, ds: xr.Dataset, mesh, xgcm_kwargs=None):
135136
grid = xgcm.Grid(ds, **xgcm_kwargs)
136137
return cls(grid, mesh=mesh)
137138

139+
def __repr__(self):
140+
return xgrid_repr(self)
141+
138142
@property
139143
def axes(self) -> list[_XGRID_AXES]:
140144
return _get_xgrid_axes(self.xgcm_grid)

src/parcels/_reprs.py

Lines changed: 56 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,67 @@
55
import textwrap
66
from typing import TYPE_CHECKING, Any
77

8+
import xarray as xr
9+
810
if TYPE_CHECKING:
911
from parcels import Field, FieldSet, ParticleSet
1012

1113

12-
def field_repr(field: Field) -> str: # TODO v4: Rework or remove entirely
14+
def fieldset_repr(fieldset: FieldSet) -> str:
15+
"""Return a pretty repr for FieldSet"""
16+
fields = [f for f in fieldset.fields.values() if getattr(f.__class__, "__name__", "") == "Field"]
17+
vfields = [f for f in fieldset.fields.values() if getattr(f.__class__, "__name__", "") == "VectorField"]
18+
19+
fields_repr = "\n".join([repr(f) for f in fields])
20+
vfields_repr = "\n".join([vectorfield_repr(vf, from_fieldset_repr=True) for vf in vfields])
21+
22+
out = f"""<{type(fieldset).__name__}>
23+
fields:
24+
{textwrap.indent(fields_repr, 8 * " ")}
25+
vectorfields:
26+
{textwrap.indent(vfields_repr, 8 * " ")}
27+
"""
28+
return textwrap.dedent(out).strip()
29+
30+
31+
def field_repr(field: Field, offset: int = 0) -> str:
1332
"""Return a pretty repr for Field"""
14-
out = f"""<{type(field).__name__}>
15-
name : {field.name!r}
16-
data : {field.data!r}
17-
extrapolate time: {field.allow_time_extrapolation!r}
33+
with xr.set_options(display_expand_data=False):
34+
out = f"""<{type(field).__name__} {field.name!r}>
35+
Parcels attributes:
36+
name : {field.name!r}
37+
interp_method : {field.interp_method!r}
38+
time_interval : {field.time_interval!r}
39+
units : {field.units!r}
40+
igrid : {field.igrid!r}
41+
DataArray:
42+
{textwrap.indent(repr(field.data), 8 * " ")}
43+
{textwrap.indent(repr(field.grid), 4 * " ")}
44+
"""
45+
return textwrap.indent(out, " " * offset).strip()
46+
47+
48+
def vectorfield_repr(fieldset: FieldSet, from_fieldset_repr=False) -> str:
49+
"""Return a pretty repr for VectorField"""
50+
out = f"""<{type(fieldset).__name__} {fieldset.name!r}>
51+
Parcels attributes:
52+
name : {fieldset.name!r}
53+
vector_interp_method : {fieldset.vector_interp_method!r}
54+
vector_type : {fieldset.vector_type!r}
55+
{field_repr(fieldset.U, offset=4) if not from_fieldset_repr else ""}
56+
{field_repr(fieldset.V, offset=4) if not from_fieldset_repr else ""}
57+
{field_repr(fieldset.W, offset=4) if not from_fieldset_repr and fieldset.W else ""}"""
58+
return out
59+
60+
61+
def xgrid_repr(grid: Any) -> str:
62+
"""Return a pretty repr for Grid"""
63+
out = f"""<{type(grid).__name__}>
64+
Parcels attributes:
65+
mesh : {grid._mesh}
66+
spatialhash : {grid._spatialhash}
67+
xgcm Grid:
68+
{textwrap.indent(repr(grid.xgcm_grid), 8 * " ")}
1869
"""
1970
return textwrap.dedent(out).strip()
2071

@@ -62,17 +113,6 @@ def particleset_repr(pset: ParticleSet) -> str:
62113
return textwrap.dedent(out).strip()
63114

64115

65-
def fieldset_repr(fieldset: FieldSet) -> str: # TODO v4: Rework or remove entirely
66-
"""Return a pretty repr for FieldSet"""
67-
fields_repr = "\n".join([repr(f) for f in fieldset.fields.values()])
68-
69-
out = f"""<{type(fieldset).__name__}>
70-
fields:
71-
{textwrap.indent(fields_repr, 8 * " ")}
72-
"""
73-
return textwrap.dedent(out).strip()
74-
75-
76116
def default_repr(obj: Any):
77117
if is_builtin_object(obj):
78118
return repr(obj)

0 commit comments

Comments
 (0)