Skip to content

Commit

Permalink
fix(str and repr): better repr and str output for transient data with…
Browse files Browse the repository at this point in the history
… multiple blocks (modflowpy#2058) (modflowpy#2102)

* fix(str and repr): improved display string for str and repr data with multiple blocks

* fix(str and repr)

* fix(str/repr): pandas list str/repr fix
  • Loading branch information
scottrp authored Mar 13, 2024
1 parent f2f2d9d commit 1fe5157
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 32 deletions.
22 changes: 19 additions & 3 deletions flopy/mf6/data/mfdata.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,10 +269,26 @@ def __init__(
self._cached_model_grid = None

def __repr__(self):
return repr(self._get_storage_obj())
if isinstance(self._data_storage, dict):
stor_size = len(self._data_storage)
else:
stor_size = 1
if stor_size <= 1:
return repr(self._get_storage_obj(first_record=True))
else:
rpr = repr(self._get_storage_obj(first_record=True))
return f"{rpr}...\nand {stor_size - 1} additional data blocks"

def __str__(self):
return str(self._get_storage_obj())
if isinstance(self._data_storage, dict):
stor_size = len(self._data_storage)
else:
stor_size = 1
if stor_size <= 1:
return str(self._get_storage_obj(first_record=True))
else:
st = str(self._get_storage_obj(first_record=True))
return f"{st}...\nand {stor_size - 1} additional data blocks"

@property
def path(self):
Expand Down Expand Up @@ -531,7 +547,7 @@ def _get_aux_var_name(self, aux_var_index):
# TODO: Verify that this works for multi-dimensional layering
return aux_var_names[0][aux_var_index[0] + 1]

def _get_storage_obj(self):
def _get_storage_obj(self, first_record=False):
return self._data_storage


Expand Down
8 changes: 6 additions & 2 deletions flopy/mf6/data/mfdataarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -1293,7 +1293,7 @@ def _new_storage(
data_path=self._path,
)

def _get_storage_obj(self):
def _get_storage_obj(self, first_record=False):
return self._data_storage

def _set_storage_obj(self, storage):
Expand Down Expand Up @@ -2020,7 +2020,11 @@ def _new_storage(
def _set_storage_obj(self, storage):
self._data_storage[self._current_key] = storage

def _get_storage_obj(self):
def _get_storage_obj(self, first_record=False):
if first_record and isinstance(self._data_storage, dict):
for value in self._data_storage.values():
return value
return None
if (
self._current_key is None
or self._current_key not in self._data_storage
Expand Down
8 changes: 6 additions & 2 deletions flopy/mf6/data/mfdatalist.py
Original file line number Diff line number Diff line change
Expand Up @@ -1391,7 +1391,7 @@ def _new_storage(self, stress_period=0):
data_path=self._path,
)

def _get_storage_obj(self):
def _get_storage_obj(self, first_record=False):
return self._data_storage

def plot(
Expand Down Expand Up @@ -2046,7 +2046,11 @@ def update_record(self, record, key_index, key=0):
def _new_storage(self, stress_period=0):
return {}

def _get_storage_obj(self):
def _get_storage_obj(self, first_record=False):
if first_record and isinstance(self._data_storage, dict):
for value in self._data_storage.values():
return value
return None
if (
self._current_key is None
or self._current_key not in self._data_storage
Expand Down
99 changes: 76 additions & 23 deletions flopy/mf6/data/mfdataplist.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,55 @@ def __init__(self):
self.data_storage_type = None
self.modified = False

def __repr__(self):
return self.get_data_str(True)

def __str__(self):
return self.get_data_str(False)

def _get_header_str(self):
header_list = []
if self.data_storage_type == DataStorageType.external_file:
header_list.append(f"open/close {self.fname}")
else:
header_list.append("internal")
if self.iprn is not None:
header_list.append(f"iprn {self.iprn}")
if len(header_list) > 0:
return ", ".join(header_list)
else:
return ""

def get_data_str(self, formal):
data_str = ""
layer_str = ""
if self.data_storage_type == DataStorageType.internal_array:
if self.internal_data is not None:
header = self._get_header_str()
if formal:
data_str = "{}{}{{{}}}\n({})\n".format(
data_str,
layer_str,
header,
repr(self.internal_data),
)
else:
data_str = "{}{}{{{}}}\n({})\n".format(
data_str,
layer_str,
header,
str(self.internal_data),
)
elif self.data_storage_type == DataStorageType.external_file:
header = self._get_header_str()
data_str = "{}{}{{{}}}\n({})\n".format(
data_str,
layer_str,
header,
"External data not displayed",
)
return data_str

def get_record(self):
rec = {}
if self.internal_data is not None:
Expand Down Expand Up @@ -726,7 +775,7 @@ def set_data(self, data, autofill=False, check_data=True, append=False):
self._simulation_data.debug,
)

data_storage = self._get_storage()
data_storage = self._get_storage_obj()
if append:
# append data to existing dataframe
current_data = self._get_dataframe()
Expand All @@ -742,15 +791,15 @@ def set_data(self, data, autofill=False, check_data=True, append=False):

def has_modified_ext_data(self):
"""check to see if external data has been modified since last read"""
data_storage = self._get_storage()
data_storage = self._get_storage_obj()
return (
data_storage.data_storage_type == DataStorageType.external_file
and data_storage.internal_data is not None
)

def binary_ext_data(self):
"""check for binary data"""
data_storage = self._get_storage()
data_storage = self._get_storage_obj()
return data_storage.binary

def to_array(self, kper=0, mask=False):
Expand Down Expand Up @@ -792,7 +841,7 @@ def set_record(self, record, autofill=False, check_data=True):
"""
if isinstance(record, dict):
data_storage = self._get_storage()
data_storage = self._get_storage_obj()
if "filename" in record:
data_storage.set_external(record["filename"])
if "binary" in record:
Expand Down Expand Up @@ -851,9 +900,9 @@ def append_data(self, data):
"""
try:
self._resync()
if self._get_storage() is None:
if self._get_storage_obj() is None:
self._data_storage = self._new_storage()
data_storage = self._get_storage()
data_storage = self._get_storage_obj()
if (
data_storage.data_storage_type
== DataStorageType.internal_array
Expand Down Expand Up @@ -952,7 +1001,7 @@ def store_internal(
Verify data prior to storing
"""
storage = self._get_storage()
storage = self._get_storage_obj()
# check if data is already stored external
if (
storage is None
Expand Down Expand Up @@ -999,7 +1048,7 @@ def store_as_external_file(
"""
# only store data externally (do not subpackage info)
if self.structure.construct_package is None:
storage = self._get_storage()
storage = self._get_storage_obj()
# check if data is already stored external
if (
replace_existing_external
Expand Down Expand Up @@ -1030,7 +1079,7 @@ def store_as_external_file(

def external_file_name(self):
"""Returns external file name, or None if this is not external data."""
storage = self._get_storage()
storage = self._get_storage_obj()
if storage is None:
return None
if (
Expand Down Expand Up @@ -1191,15 +1240,15 @@ def _save_binary_data(self, fd_data_file, data):
fd_data_file,
self._model_or_sim.modeldiscrit,
)
data_storage = self._get_storage()
data_storage = self._get_storage_obj()
data_storage.internal_data = None

def has_data(self, key=None):
"""Returns whether this MFList has any data associated with it."""
try:
if self._get_storage() is None:
if self._get_storage_obj() is None:
return False
return self._get_storage().has_data()
return self._get_storage_obj().has_data()
except Exception as ex:
type_, value_, traceback_ = sys.exc_info()
raise MFDataException(
Expand Down Expand Up @@ -1281,7 +1330,7 @@ def load(
next data line : str
"""
data_storage = self._get_storage()
data_storage = self._get_storage_obj()
data_storage.modified = False
# parse first line to determine if this is internal or external data
datautil.PyListUtil.reset_delimiter_used()
Expand Down Expand Up @@ -1338,7 +1387,7 @@ def load(
def _new_storage(self):
return {"Data": PandasListStorage()}

def _get_storage(self):
def _get_storage_obj(self, first_record=False):
return self._data_storage["Data"]

def _get_id_fields(self, data_frame):
Expand Down Expand Up @@ -1484,7 +1533,7 @@ def _get_data(self):

def _get_dataframe(self):
"""get and return dataframe for this list data"""
data_storage = self._get_storage()
data_storage = self._get_storage_obj()
if data_storage is None or data_storage.data_storage_type is None:
block_exists = self._block.header_exists(
self._current_key, self.path
Expand Down Expand Up @@ -1551,9 +1600,9 @@ def _get_record(self, data_frame=False):
"""
try:
if self._get_storage() is None:
if self._get_storage_obj() is None:
return None
record = self._get_storage().get_record()
record = self._get_storage_obj().get_record()
except Exception as ex:
type_, value_, traceback_ = sys.exc_info()
raise MFDataException(
Expand Down Expand Up @@ -1650,7 +1699,7 @@ def _write_file_entry(
-------
result of pandas to_csv call
"""
data_storage = self._get_storage()
data_storage = self._get_storage_obj()
if data_storage is None:
return ""
if (
Expand Down Expand Up @@ -1751,7 +1800,7 @@ def _get_file_path(self):
file_path : file path to data
"""
data_storage = self._get_storage()
data_storage = self._get_storage_obj()
if data_storage.fname is None:
return None
if self._model_or_sim.type == "model":
Expand Down Expand Up @@ -1989,11 +2038,11 @@ def store_as_external_file(
self._cache_model_grid = True
for sp in self._data_storage.keys():
self._current_key = sp
storage = self._get_storage()
storage = self._get_storage_obj()
if storage.internal_size == 0:
storage.internal_data = self.get_dataframe(sp)
if storage.internal_size > 0 and (
self._get_storage().data_storage_type
self._get_storage_obj().data_storage_type
!= DataStorageType.external_file
or replace_existing_external
):
Expand Down Expand Up @@ -2027,7 +2076,7 @@ def store_internal(
for sp in self._data_storage.keys():
self._current_key = sp
if (
self._get_storage().data_storage_type
self._get_storage_obj().data_storage_type
== DataStorageType.external_file
):
super().store_internal(
Expand Down Expand Up @@ -2482,7 +2531,11 @@ def update_record(self, record, key_index, key=0):
def _new_storage(self):
return {}

def _get_storage(self):
def _get_storage_obj(self, first_record=False):
if first_record and isinstance(self._data_storage, dict):
for value in self._data_storage.values():
return value
return None
if (
self._current_key is None
or self._current_key not in self._data_storage
Expand Down
8 changes: 6 additions & 2 deletions flopy/mf6/data/mfdatascalar.py
Original file line number Diff line number Diff line change
Expand Up @@ -661,7 +661,7 @@ def _new_storage(self, stress_period=0):
data_path=self._path,
)

def _get_storage_obj(self):
def _get_storage_obj(self, first_record=False):
return self._data_storage

def plot(self, filename_base=None, file_extension=None, **kwargs):
Expand Down Expand Up @@ -911,7 +911,11 @@ def load(
def _new_storage(self, stress_period=0):
return {}

def _get_storage_obj(self):
def _get_storage_obj(self, first_record=False):
if first_record and isinstance(self._data_storage, dict):
for value in self._data_storage.values():
return value
return None
if (
self._current_key is None
or self._current_key not in self._data_storage
Expand Down
16 changes: 16 additions & 0 deletions flopy/mf6/data/mfdatastorage.py
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,22 @@ def get_data_str(self, formal):
layer_str,
self._get_layer_header_str(index),
)
elif storage.data_storage_type == DataStorageType.external_file:
header = self._get_layer_header_str(index)
if self.layered:
data_str = "{}{}{{{}}}\n({})\n".format(
data_str,
layer_str,
header,
"External data not displayed",
)
else:
data_str = "{}{}{{{}}}\n({})\n".format(
data_str,
layer_str,
header,
"External data not displayed",
)
return data_str

def _get_layer_header_str(self, layer):
Expand Down

0 comments on commit 1fe5157

Please sign in to comment.